xref: /openbsd-src/sys/arch/octeon/dev/octeon_pcibus.c (revision d13be5d47e4149db2549a9828e244d59dbc43f15)
1 /*	$OpenBSD: octeon_pcibus.c,v 1.6 2011/05/08 13:24:55 syuu Exp $	*/
2 /*	$OpenBSD: octeon_pcibus.c,v 1.6 2011/05/08 13:24:55 syuu Exp $	*/
3 /*	$NetBSD: bonito_mainbus.c,v 1.11 2008/04/28 20:23:10 martin Exp $	*/
4 /*	$NetBSD: bonito_pci.c,v 1.5 2008/04/28 20:23:28 martin Exp $	*/
5 
6 /*
7  * Copyright (c) 2009, 2010 Miodrag Vallat.
8  *
9  * Permission to use, copy, modify, and distribute this software for any
10  * purpose with or without fee is hereby granted, provided that the above
11  * copyright notice and this permission notice appear in all copies.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20  */
21 /*-
22  * Copyright (c) 2001 The NetBSD Foundation, Inc.
23  * All rights reserved.
24  *
25  * This code is derived from software contributed to The NetBSD Foundation
26  * by Jason R. Thorpe.
27  *
28  * Redistribution and use in source and binary forms, with or without
29  * modification, are permitted provided that the following conditions
30  * are met:
31  * 1. Redistributions of source code must retain the above copyright
32  *    notice, this list of conditions and the following disclaimer.
33  * 2. Redistributions in binary form must reproduce the above copyright
34  *    notice, this list of conditions and the following disclaimer in the
35  *    documentation and/or other materials provided with the distribution.
36  *
37  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
38  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
39  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
40  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
41  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
43  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
44  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
45  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
46  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
47  * POSSIBILITY OF SUCH DAMAGE.
48  */
49 
50 #include <sys/param.h>
51 #include <sys/systm.h>
52 #include <sys/device.h>
53 #include <sys/extent.h>
54 #include <sys/malloc.h>
55 
56 #include <machine/autoconf.h>
57 #include <machine/bus.h>
58 #include <machine/intr.h>
59 
60 #include <dev/pci/pcidevs.h>
61 #include <dev/pci/pcireg.h>
62 #include <dev/pci/pcivar.h>
63 #include <dev/pci/ppbreg.h>
64 
65 #include <octeon/dev/iobusvar.h>
66 #include <octeon/dev/octeon_pcibus.h>
67 #include <octeon/dev/octeon_pcibusvar.h>
68 
69 #include <uvm/uvm_extern.h>
70 
71 #if 1
72 #define	OCTEON_PCIBUS_DEBUG
73 #endif
74 
75 #ifdef OCTEON_PCIBUS_DEBUG
76 #define DEBUG_PRINT(p) printf p
77 #else
78 #define DEBUG_PRINT(p)
79 #endif
80 
81 #define REG_READ32(addr)	(*(volatile uint32_t *)(addr))
82 #define REG_WRITE32(addr, data)	(*(volatile uint32_t *)(addr) = (uint32_t)(data))
83 
84 int	octeon_pcibus_match(struct device *, void *, void *);
85 void	octeon_pcibus_attach(struct device *, struct device *, void *);
86 int	octeon_pcibus_intr_map(int dev, int fn, int pin);
87 
88 const struct cfattach pcibus_ca = {
89 	sizeof(struct octeon_pcibus_softc),
90 	octeon_pcibus_match, octeon_pcibus_attach
91 };
92 
93 struct cfdriver pcibus_cd = {
94 	NULL, "pcibus", DV_DULL
95 };
96 
97 bus_addr_t  octeon_pcibus_pa_to_device(paddr_t);
98 paddr_t     octeon_pcibus_device_to_pa(bus_addr_t);
99 void        octeon_pcibus_attach_hook(struct device *, struct device *,
100                                       struct pcibus_attach_args *);
101 int         octeon_pcibus_bus_maxdevs(void *, int);
102 pcitag_t    octeon_pcibus_make_tag(void *, int, int, int);
103 void        octeon_pcibus_decompose_tag(void *, pcitag_t, int *, int *, int *);
104 int	    octeon_pcibus_pci_conf_size(void *, pcitag_t);
105 pcireg_t    octeon_pcibus_pci_conf_read(void *, pcitag_t, int);
106 void        octeon_pcibus_pci_conf_write(void *, pcitag_t, int, pcireg_t);
107 int         octeon_pcibus_pci_intr_map(struct pci_attach_args *,
108                                        pci_intr_handle_t *);
109 const char *octeon_pcibus_pci_intr_string(void *, pci_intr_handle_t);
110 void       *octeon_pcibus_pci_intr_establish(void *, pci_intr_handle_t, int,
111                                              int (*)(void *), void *, char *);
112 void        octeon_pcibus_pci_intr_disestablish(void *, void *);
113 
114 
115 struct machine_bus_dma_tag octeon_pcibus_bus_dma_tag = {
116 	._cookie = NULL,
117 	._dmamap_create =	_dmamap_create,
118 	._dmamap_destroy =	_dmamap_destroy,
119 	._dmamap_load =		_dmamap_load,
120 	._dmamap_load_mbuf =	_dmamap_load_mbuf,
121 	._dmamap_load_uio =	_dmamap_load_uio,
122 	._dmamap_load_raw =	_dmamap_load_raw,
123 	._dmamap_load_buffer =	_dmamap_load_buffer,
124 	._dmamap_unload =	_dmamap_unload,
125 	._dmamap_sync =		_dmamap_sync,
126 	._dmamem_alloc =	_dmamem_alloc,
127 	._dmamem_free =		_dmamem_free,
128 	._dmamem_map =		_dmamem_map,
129 	._dmamem_unmap =	_dmamem_unmap,
130 	._dmamem_mmap =		_dmamem_mmap,
131 	._pa_to_device =	octeon_pcibus_pa_to_device,
132 	._device_to_pa =	octeon_pcibus_device_to_pa
133 };
134 
135 int octeon_pcibus_io_map(bus_space_tag_t, bus_addr_t, bus_size_t, int,
136     bus_space_handle_t *);
137 int octeon_pcibus_mem_map(bus_space_tag_t, bus_addr_t, bus_size_t, int,
138     bus_space_handle_t *);
139 
140 #define _OCTEON_PCIBUS_PCIIO_BASE	0x00001000
141 #define _OCTEON_PCIBUS_PCIIO_SIZE	0x08000000
142 #define _OCTEON_PCIBUS_PCIMEM_BASE	0x80000000
143 #define _OCTEON_PCIBUS_PCIMEM_SIZE	0x40000000
144 
145 struct mips_bus_space octeon_pcibus_pci_io_space_tag = {
146 	.bus_base = PHYS_TO_XKPHYS(_OCTEON_PCIBUS_PCIIO_BASE, CCA_NC),
147 	.bus_private = NULL,
148 	._space_read_1 =	generic_space_read_1,
149 	._space_write_1 =	generic_space_write_1,
150 	._space_read_2 =	generic_space_read_2,
151 	._space_write_2 =	generic_space_write_2,
152 	._space_read_4 =	generic_space_read_4,
153 	._space_write_4 =	generic_space_write_4,
154 	._space_read_8 =	generic_space_read_8,
155 	._space_write_8 =	generic_space_write_8,
156 	._space_read_raw_2 =	generic_space_read_raw_2,
157 	._space_write_raw_2 =	generic_space_write_raw_2,
158 	._space_read_raw_4 =	generic_space_read_raw_4,
159 	._space_write_raw_4 =	generic_space_write_raw_4,
160 	._space_read_raw_8 =	generic_space_read_raw_8,
161 	._space_write_raw_8 =	generic_space_write_raw_8,
162 	._space_map =		octeon_pcibus_io_map,
163 	._space_unmap =		generic_space_unmap,
164 	._space_subregion =	generic_space_region,
165 	._space_vaddr =		generic_space_vaddr
166 };
167 
168 struct mips_bus_space octeon_pcibus_pci_mem_space_tag = {
169 	.bus_base = PHYS_TO_XKPHYS(_OCTEON_PCIBUS_PCIMEM_BASE, CCA_NC),
170 	.bus_private = NULL,
171 	._space_read_1 =	generic_space_read_1,
172 	._space_write_1 =	generic_space_write_1,
173 	._space_read_2 =	generic_space_read_2,
174 	._space_write_2 =	generic_space_write_2,
175 	._space_read_4 =	generic_space_read_4,
176 	._space_write_4 =	generic_space_write_4,
177 	._space_read_8 =	generic_space_read_8,
178 	._space_write_8 =	generic_space_write_8,
179 	._space_read_raw_2 =	generic_space_read_raw_2,
180 	._space_write_raw_2 =	generic_space_write_raw_2,
181 	._space_read_raw_4 =	generic_space_read_raw_4,
182 	._space_write_raw_4 =	generic_space_write_raw_4,
183 	._space_read_raw_8 =	generic_space_read_raw_8,
184 	._space_write_raw_8 =	generic_space_write_raw_8,
185 	._space_map =		octeon_pcibus_mem_map,
186 	._space_unmap =		generic_space_unmap,
187 	._space_subregion =	generic_space_region,
188 	._space_vaddr =		generic_space_vaddr
189 };
190 
191 int
192 octeon_pcibus_match(struct device *parent, void *vcf, void *aux)
193 {
194 	struct iobus_attach_args *aa = aux;
195 
196 	if (strcmp(aa->aa_name, pcibus_cd.cd_name) == 0)
197 		return 1;
198 
199 	return 0;
200 }
201 
202 void
203 octeon_pcibus_attach(struct device *parent, struct device *self, void *aux)
204 {
205 	struct octeon_pcibus_softc *sc;
206 	struct iobus_attach_args *aa;
207 	struct pcibus_attach_args pba;
208 
209 	sc = (struct octeon_pcibus_softc *)self;
210 	aa = aux;
211 	sc->sc_aa = aa;
212 
213 	/*
214 	 * Attach PCI bus.
215 	 */
216 	sc->sc_pc.pc_attach_hook = octeon_pcibus_attach_hook;
217 	sc->sc_pc.pc_bus_maxdevs = octeon_pcibus_bus_maxdevs;
218 	sc->sc_pc.pc_make_tag = octeon_pcibus_make_tag;
219 	sc->sc_pc.pc_decompose_tag = octeon_pcibus_decompose_tag;
220 
221 	sc->sc_pc.pc_conf_v = sc;
222 	sc->sc_pc.pc_conf_size = octeon_pcibus_pci_conf_size;
223 	sc->sc_pc.pc_conf_read = octeon_pcibus_pci_conf_read;
224 	sc->sc_pc.pc_conf_write = octeon_pcibus_pci_conf_write;
225 
226 	sc->sc_pc.pc_intr_v = sc;
227 	sc->sc_pc.pc_intr_map = octeon_pcibus_pci_intr_map;
228 	sc->sc_pc.pc_intr_string = octeon_pcibus_pci_intr_string;
229 	sc->sc_pc.pc_intr_establish = octeon_pcibus_pci_intr_establish;
230 	sc->sc_pc.pc_intr_disestablish = octeon_pcibus_pci_intr_disestablish;
231 
232 	bzero(&pba, sizeof pba);
233 	pba.pba_busname = "pci";
234 	pba.pba_iot = &octeon_pcibus_pci_io_space_tag;
235 	pba.pba_memt = &octeon_pcibus_pci_mem_space_tag;
236 	pba.pba_dmat = &octeon_pcibus_bus_dma_tag;
237 	pba.pba_pc = &sc->sc_pc;
238 	pba.pba_domain = pci_ndomains++;
239 	pba.pba_bus = 0;
240 	pba.pba_ioex = octeon_pcibus_get_resource_extent(&sc->sc_pc, 1);
241 	pba.pba_memex = octeon_pcibus_get_resource_extent(&sc->sc_pc, 0);
242 
243 	config_found(&sc->sc_dev, &pba, octeon_pcibus_print);
244 }
245 
246 bus_addr_t
247 octeon_pcibus_pa_to_device(paddr_t pa)
248 {
249 	printf("%s:%d: pa=%p\n", __func__, __LINE__, pa);
250 
251 	return pa & 0x1ffffffffffffUL;
252 }
253 
254 paddr_t
255 octeon_pcibus_device_to_pa(bus_addr_t addr)
256 {
257 	printf("%s:%d: addr=%p\n", __func__, __LINE__, addr);
258 
259 	return PHYS_TO_XKPHYS(addr, CCA_NC);
260 }
261 
262 int
263 octeon_pcibus_print(void *aux, const char *pnp)
264 {
265 	struct pcibus_attach_args *pba = aux;
266 
267 	if (pnp)
268 		printf("%s at %s", pba->pba_busname, pnp);
269 	printf(" bus %d", pba->pba_bus);
270 
271 	return UNCONF;
272 }
273 
274 /*
275  * various PCI helpers
276  */
277 void
278 octeon_pcibus_attach_hook(struct device *parent, struct device *self,
279     struct pcibus_attach_args *pba)
280 {
281 }
282 
283 /*
284  * PCI configuration space access routines
285  */
286 int
287 octeon_pcibus_bus_maxdevs(void *v, int busno)
288 {
289 	/* XXX */
290 	return 32;
291 }
292 
293 pcitag_t
294 octeon_pcibus_make_tag(void *unused, int b, int d, int f)
295 {
296 	return (b << 16) | (d << 11) | (f << 8);
297 }
298 
299 void
300 octeon_pcibus_decompose_tag(void *unused, pcitag_t tag, int *bp, int *dp, int *fp)
301 {
302 	if (bp != NULL)
303 		*bp = (tag >> 16) & 0xff;
304 	if (dp != NULL)
305 		*dp = (tag >> 11) & 0x1f;
306 	if (fp != NULL)
307 		*fp = (tag >> 8) & 0x7;
308 }
309 
310 int
311 octeon_pcibus_pci_conf_size(void *v, pcitag_t tag)
312 {
313 	return PCI_CONFIG_SPACE_SIZE;
314 }
315 
316 pcireg_t
317 octeon_pcibus_pci_conf_read(void *v, pcitag_t tag, int offset)
318 {
319 	pcireg_t data;
320 	uint64_t cfgoff;
321 
322 	if (tag == 0){
323 		if (offset & 0x4){
324 			cfgoff = OCTEON_PCI_CFG1 + (offset & 0xfff8);
325 		} else {
326 			cfgoff = OCTEON_PCI_CFG0 + (offset & 0xfff8);
327 		}
328 	} else {
329 		cfgoff = tag + offset;
330 		if (offset & 0x4) {
331 			cfgoff = OCTEON_PCI_CONFIG_BASE1 + (cfgoff & 0xfffffff8);
332 		} else {
333 			cfgoff = OCTEON_PCI_CONFIG_BASE0 + (cfgoff & 0xfffffff8);
334 		}
335 	}
336 
337 	data = REG_READ32(cfgoff);
338 	return data;
339 }
340 
341 void
342 octeon_pcibus_pci_conf_write(void *v, pcitag_t tag, int offset, pcireg_t data)
343 {
344 	uint64_t cfgoff;
345 
346 	if (tag == 0){
347 		if (offset & 0x4){
348 			cfgoff = OCTEON_PCI_CFG1 + (offset & 0xfff8);
349 		} else {
350 			cfgoff = OCTEON_PCI_CFG0 + (offset & 0xfff8);
351 		}
352 	} else {
353 		cfgoff = tag + offset;
354 		if (offset & 0x4){
355 			cfgoff = OCTEON_PCI_CONFIG_BASE1 + (cfgoff & 0xfffffff8);
356 		} else {
357 			cfgoff = OCTEON_PCI_CONFIG_BASE0 + (cfgoff & 0xfffffff8);
358 		}
359 	}
360 
361 	REG_WRITE32(cfgoff, data);
362 }
363 
364 
365 /*
366  * PCI Interrupt handling
367  */
368 int
369 octeon_pcibus_pci_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
370 {
371 #if 0
372 	struct octeon_pcibus_softc *sc = pa->pa_pc->pc_intr_v;
373 #endif
374 	int bus, dev, fn, pin;
375 
376 	*ihp = (pci_intr_handle_t)-1;
377 
378 	if (pa->pa_intrpin == 0)	/* no interrupt needed */
379 		return 1;
380 
381 #ifdef DIAGNOSTIC
382 	if (pa->pa_intrpin > 4) {
383 		printf("%s: bad interrupt pin %d\n", __func__, pa->pa_intrpin);
384 		return 1;
385 	}
386 #endif
387 
388 	pci_decompose_tag(pa->pa_pc, pa->pa_tag, &bus, &dev, &fn);
389 	if (pa->pa_bridgetag) {
390 		pin = PPB_INTERRUPT_SWIZZLE(pa->pa_rawintrpin, dev);
391 		*ihp = pa->pa_bridgeih[pin - 1];
392 	} else {
393 		if (bus == 0)
394 			*ihp = octeon_pcibus_intr_map(dev, fn, pa->pa_intrpin);
395 
396 		if (*ihp == (pci_intr_handle_t)-1)
397 			return 1;
398 	}
399 
400 	return 0;
401 }
402 
403 const char *
404 octeon_pcibus_pci_intr_string(void *cookie, pci_intr_handle_t ih)
405 {
406 	static char irqstr[sizeof("irq 0123456789")];
407 
408 	snprintf(irqstr, sizeof irqstr, "irq %d", ih);
409 	return irqstr;
410 }
411 
412 void *
413 octeon_pcibus_pci_intr_establish(void *cookie, pci_intr_handle_t ih, int level,
414     int (*cb)(void *), void *cbarg, char *name)
415 {
416 	return octeon_intr_establish(ih, level, cb, cbarg, name);
417 }
418 
419 void
420 octeon_pcibus_pci_intr_disestablish(void *cookie, void *ihp)
421 {
422 	struct octeon_pcibus_softc *sc;
423 	struct iobus_attach_args *aa;
424 
425 	sc = (struct octeon_pcibus_softc *)cookie;
426 	aa = sc->sc_aa;
427 
428 // XXX: this cause panic...
429 //	iobus_intr_disestablish(ihp);
430 }
431 
432 /*
433  * bus_space mapping routines.
434  */
435 int
436 octeon_pcibus_io_map(bus_space_tag_t t, bus_addr_t offs, bus_size_t size, int flags,
437     bus_space_handle_t *bshp)
438 {
439 	if (ISSET(flags, BUS_SPACE_MAP_CACHEABLE)) {
440 		offs +=
441 		    PHYS_TO_XKPHYS(0, CCA_CACHED) - PHYS_TO_XKPHYS(0, CCA_NC);
442 	}
443 	*bshp = t->bus_base + offs;
444 	return 0;
445 }
446 
447 int
448 octeon_pcibus_mem_map(bus_space_tag_t t, bus_addr_t offs, bus_size_t size, int flags,
449     bus_space_handle_t *bshp)
450 {
451 	if (ISSET(flags, BUS_SPACE_MAP_CACHEABLE)) {
452 		offs +=
453 		    PHYS_TO_XKPHYS(0, CCA_CACHED) - PHYS_TO_XKPHYS(0, CCA_NC);
454 	}
455 	*bshp = t->bus_base + offs;
456 	return 0;
457 }
458 
459 /*
460  * PCI resource handling
461  */
462 struct extent *
463 octeon_pcibus_get_resource_extent(pci_chipset_tag_t pc, int io)
464 {
465 	struct octeon_pcibus_softc *sc = pc->pc_conf_v;
466 	struct extent *ex;
467 	char *exname;
468 	int exnamesz;
469 	int errors;
470 
471 	exnamesz = 1 + 16 + 4;
472 	exname = (char *)malloc(exnamesz, M_DEVBUF, M_NOWAIT);
473 	if (exname == NULL)
474 		return NULL;
475 	snprintf(exname, exnamesz, "%s%s", sc->sc_dev.dv_xname,
476 	    io ? "_io" : "_mem");
477 
478 	ex = extent_create(exname, 0, 0xffffffffffffffff, M_DEVBUF, NULL, 0,
479 	    EX_NOWAIT | EX_FILLED);
480 	if (ex == NULL)
481 		goto out;
482 
483 	exname = NULL;
484 	errors = 0;
485 	if (io) {
486 		if (extent_free(ex, _OCTEON_PCIBUS_PCIIO_BASE, _OCTEON_PCIBUS_PCIIO_SIZE,
487 		    EX_NOWAIT) != 0)
488 			errors++;
489 	} else {
490 		if (extent_free(ex, _OCTEON_PCIBUS_PCIMEM_BASE, _OCTEON_PCIBUS_PCIMEM_SIZE,
491 		    EX_NOWAIT) != 0)
492 			errors++;
493 	}
494 
495 	if (errors != 0) {
496 		extent_destroy(ex);
497 		ex = NULL;
498 	}
499 
500 #ifdef OCTEON_PCIBUS_DEBUG
501 	extent_print(ex);
502 #endif
503 
504 out:
505 	if (exname != NULL)
506 		free(exname, M_DEVBUF);
507 
508 	return ex;
509 }
510 
511 /*
512  * PCI model specific routines
513  */
514 
515 int
516 octeon_pcibus_intr_map(int dev, int fn, int pin)
517 {
518 	return CIU_INT_PCI_INTA + ((pin - 1) & 3);
519 }
520