xref: /openbsd-src/sys/arch/octeon/dev/octeon_pcibus.c (revision 46035553bfdd96e63c94e32da0210227ec2e3cf1)
1 /*	$OpenBSD: octeon_pcibus.c,v 1.20 2018/06/13 14:38:42 visa Exp $	*/
2 /*	$NetBSD: bonito_mainbus.c,v 1.11 2008/04/28 20:23:10 martin Exp $	*/
3 /*	$NetBSD: bonito_pci.c,v 1.5 2008/04/28 20:23:28 martin Exp $	*/
4 
5 /*
6  * Copyright (c) 2009, 2010 Miodrag Vallat.
7  *
8  * Permission to use, copy, modify, and distribute this software for any
9  * purpose with or without fee is hereby granted, provided that the above
10  * copyright notice and this permission notice appear in all copies.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19  */
20 /*-
21  * Copyright (c) 2001 The NetBSD Foundation, Inc.
22  * All rights reserved.
23  *
24  * This code is derived from software contributed to The NetBSD Foundation
25  * by Jason R. Thorpe.
26  *
27  * Redistribution and use in source and binary forms, with or without
28  * modification, are permitted provided that the following conditions
29  * are met:
30  * 1. Redistributions of source code must retain the above copyright
31  *    notice, this list of conditions and the following disclaimer.
32  * 2. Redistributions in binary form must reproduce the above copyright
33  *    notice, this list of conditions and the following disclaimer in the
34  *    documentation and/or other materials provided with the distribution.
35  *
36  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
37  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
38  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
39  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
40  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
41  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
42  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
43  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
44  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
45  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46  * POSSIBILITY OF SUCH DAMAGE.
47  */
48 
49 #include <sys/param.h>
50 #include <sys/systm.h>
51 #include <sys/device.h>
52 #include <sys/extent.h>
53 #include <sys/malloc.h>
54 
55 #include <machine/autoconf.h>
56 #include <machine/bus.h>
57 #include <machine/intr.h>
58 #include <machine/octeonvar.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 #ifdef DEBUG
72 #define OCTEON_PCIDEBUG(p) printf p
73 #else
74 #define OCTEON_PCIDEBUG(p)
75 #endif
76 
77 #define REG_READ32(addr)	(*(volatile uint32_t *)(addr))
78 #define REG_WRITE32(addr, data)	(*(volatile uint32_t *)(addr) = (uint32_t)(data))
79 
80 int	octeon_pcibus_match(struct device *, void *, void *);
81 void	octeon_pcibus_attach(struct device *, struct device *, void *);
82 int	octeon_pcibus_intr_map(int dev, int fn, int pin);
83 
84 const struct cfattach pcibus_ca = {
85 	sizeof(struct octeon_pcibus_softc),
86 	octeon_pcibus_match, octeon_pcibus_attach
87 };
88 
89 struct cfdriver pcibus_cd = {
90 	NULL, "pcibus", DV_DULL
91 };
92 
93 bus_addr_t  octeon_pcibus_pa_to_device(paddr_t);
94 paddr_t     octeon_pcibus_device_to_pa(bus_addr_t);
95 void        octeon_pcibus_attach_hook(struct device *, struct device *,
96                                       struct pcibus_attach_args *);
97 int         octeon_pcibus_bus_maxdevs(void *, int);
98 pcitag_t    octeon_pcibus_make_tag(void *, int, int, int);
99 void        octeon_pcibus_decompose_tag(void *, pcitag_t, int *, int *, int *);
100 int	    octeon_pcibus_pci_conf_size(void *, pcitag_t);
101 pcireg_t    octeon_pcibus_pci_conf_read(void *, pcitag_t, int);
102 void        octeon_pcibus_pci_conf_write(void *, pcitag_t, int, pcireg_t);
103 int         octeon_pcibus_pci_intr_map(struct pci_attach_args *,
104                                        pci_intr_handle_t *);
105 const char *octeon_pcibus_pci_intr_string(void *, pci_intr_handle_t);
106 void       *octeon_pcibus_pci_intr_establish(void *, pci_intr_handle_t, int,
107                                              int (*)(void *), void *, char *);
108 void        octeon_pcibus_pci_intr_disestablish(void *, void *);
109 
110 
111 struct machine_bus_dma_tag octeon_pcibus_bus_dma_tag = {
112 	._cookie = NULL,
113 	._dmamap_create =	_dmamap_create,
114 	._dmamap_destroy =	_dmamap_destroy,
115 	._dmamap_load =		_dmamap_load,
116 	._dmamap_load_mbuf =	_dmamap_load_mbuf,
117 	._dmamap_load_uio =	_dmamap_load_uio,
118 	._dmamap_load_raw =	_dmamap_load_raw,
119 	._dmamap_load_buffer =	_dmamap_load_buffer,
120 	._dmamap_unload =	_dmamap_unload,
121 	._dmamap_sync =		_dmamap_sync,
122 	._dmamem_alloc =	_dmamem_alloc,
123 	._dmamem_free =		_dmamem_free,
124 	._dmamem_map =		_dmamem_map,
125 	._dmamem_unmap =	_dmamem_unmap,
126 	._dmamem_mmap =		_dmamem_mmap,
127 	._pa_to_device =	octeon_pcibus_pa_to_device,
128 	._device_to_pa =	octeon_pcibus_device_to_pa
129 };
130 
131 int octeon_pcibus_io_map(bus_space_tag_t, bus_addr_t, bus_size_t, int,
132     bus_space_handle_t *);
133 int octeon_pcibus_mem_map(bus_space_tag_t, bus_addr_t, bus_size_t, int,
134     bus_space_handle_t *);
135 
136 #define _OCTEON_PCIBUS_PCIIO_BASE	0x00001000
137 #define _OCTEON_PCIBUS_PCIIO_SIZE	0x08000000
138 #define _OCTEON_PCIBUS_PCIMEM_BASE	0x80000000
139 #define _OCTEON_PCIBUS_PCIMEM_SIZE	0x40000000
140 
141 struct mips_bus_space octeon_pcibus_pci_io_space_tag = {
142 	.bus_base = PHYS_TO_XKPHYS(_OCTEON_PCIBUS_PCIIO_BASE, CCA_NC),
143 	.bus_private = NULL,
144 	._space_read_1 =	generic_space_read_1,
145 	._space_write_1 =	generic_space_write_1,
146 	._space_read_2 =	generic_space_read_2,
147 	._space_write_2 =	generic_space_write_2,
148 	._space_read_4 =	generic_space_read_4,
149 	._space_write_4 =	generic_space_write_4,
150 	._space_read_8 =	generic_space_read_8,
151 	._space_write_8 =	generic_space_write_8,
152 	._space_read_raw_2 =	generic_space_read_raw_2,
153 	._space_write_raw_2 =	generic_space_write_raw_2,
154 	._space_read_raw_4 =	generic_space_read_raw_4,
155 	._space_write_raw_4 =	generic_space_write_raw_4,
156 	._space_read_raw_8 =	generic_space_read_raw_8,
157 	._space_write_raw_8 =	generic_space_write_raw_8,
158 	._space_map =		octeon_pcibus_io_map,
159 	._space_unmap =		generic_space_unmap,
160 	._space_subregion =	generic_space_region,
161 	._space_vaddr =		generic_space_vaddr
162 };
163 
164 struct mips_bus_space octeon_pcibus_pci_mem_space_tag = {
165 	.bus_base = PHYS_TO_XKPHYS(_OCTEON_PCIBUS_PCIMEM_BASE, CCA_NC),
166 	.bus_private = NULL,
167 	._space_read_1 =	generic_space_read_1,
168 	._space_write_1 =	generic_space_write_1,
169 	._space_read_2 =	generic_space_read_2,
170 	._space_write_2 =	generic_space_write_2,
171 	._space_read_4 =	generic_space_read_4,
172 	._space_write_4 =	generic_space_write_4,
173 	._space_read_8 =	generic_space_read_8,
174 	._space_write_8 =	generic_space_write_8,
175 	._space_read_raw_2 =	generic_space_read_raw_2,
176 	._space_write_raw_2 =	generic_space_write_raw_2,
177 	._space_read_raw_4 =	generic_space_read_raw_4,
178 	._space_write_raw_4 =	generic_space_write_raw_4,
179 	._space_read_raw_8 =	generic_space_read_raw_8,
180 	._space_write_raw_8 =	generic_space_write_raw_8,
181 	._space_map =		octeon_pcibus_mem_map,
182 	._space_unmap =		generic_space_unmap,
183 	._space_subregion =	generic_space_region,
184 	._space_vaddr =		generic_space_vaddr
185 };
186 
187 int
188 octeon_pcibus_match(struct device *parent, void *vcf, void *aux)
189 {
190 	struct iobus_attach_args *aa = aux;
191 
192 	if ((octeon_boot_info->config_flags & BOOTINFO_CFG_FLAG_PCI_HOST) == 0) {
193 		OCTEON_PCIDEBUG(("%s, no PCI host function detected.\n", __func__));
194 		return 0;
195 	}
196 
197 	if (strcmp(aa->aa_name, pcibus_cd.cd_name) == 0)
198 		return 1;
199 
200 	return 0;
201 }
202 
203 void
204 octeon_pcibus_attach(struct device *parent, struct device *self, void *aux)
205 {
206 	struct octeon_pcibus_softc *sc;
207 	struct pcibus_attach_args pba;
208 
209 	sc = (struct octeon_pcibus_softc *)self;
210 	sc->sc_aa = aux;
211 
212 	printf("\n");
213 
214 	/*
215 	 * Attach PCI bus.
216 	 */
217 	sc->sc_pc.pc_attach_hook = octeon_pcibus_attach_hook;
218 	sc->sc_pc.pc_bus_maxdevs = octeon_pcibus_bus_maxdevs;
219 	sc->sc_pc.pc_make_tag = octeon_pcibus_make_tag;
220 	sc->sc_pc.pc_decompose_tag = octeon_pcibus_decompose_tag;
221 
222 	sc->sc_pc.pc_conf_v = sc;
223 	sc->sc_pc.pc_conf_size = octeon_pcibus_pci_conf_size;
224 	sc->sc_pc.pc_conf_read = octeon_pcibus_pci_conf_read;
225 	sc->sc_pc.pc_conf_write = octeon_pcibus_pci_conf_write;
226 
227 	sc->sc_pc.pc_intr_v = sc;
228 	sc->sc_pc.pc_intr_map = octeon_pcibus_pci_intr_map;
229 	sc->sc_pc.pc_intr_string = octeon_pcibus_pci_intr_string;
230 	sc->sc_pc.pc_intr_establish = octeon_pcibus_pci_intr_establish;
231 	sc->sc_pc.pc_intr_disestablish = octeon_pcibus_pci_intr_disestablish;
232 
233 	bzero(&pba, sizeof pba);
234 	pba.pba_busname = "pci";
235 	pba.pba_iot = &octeon_pcibus_pci_io_space_tag;
236 	pba.pba_memt = &octeon_pcibus_pci_mem_space_tag;
237 	pba.pba_dmat = &octeon_pcibus_bus_dma_tag;
238 	pba.pba_pc = &sc->sc_pc;
239 	pba.pba_domain = pci_ndomains++;
240 	pba.pba_bus = 0;
241 	pba.pba_ioex = octeon_pcibus_get_resource_extent(&sc->sc_pc, 1);
242 	pba.pba_memex = octeon_pcibus_get_resource_extent(&sc->sc_pc, 0);
243 
244 	config_found(&sc->sc_dev, &pba, octeon_pcibus_print);
245 }
246 
247 bus_addr_t
248 octeon_pcibus_pa_to_device(paddr_t pa)
249 {
250 	OCTEON_PCIDEBUG(("%s:%d: pa=%p\n", __func__, __LINE__, (void *)pa));
251 
252 	return pa & 0x1ffffffffffffUL;
253 }
254 
255 paddr_t
256 octeon_pcibus_device_to_pa(bus_addr_t addr)
257 {
258 	OCTEON_PCIDEBUG(("%s:%d: addr=%lx\n", __func__, __LINE__, addr));
259 
260 	return PHYS_TO_XKPHYS(addr, CCA_NC);
261 }
262 
263 int
264 octeon_pcibus_print(void *aux, const char *pnp)
265 {
266 	struct pcibus_attach_args *pba = aux;
267 
268 	if (pnp)
269 		printf("%s at %s", pba->pba_busname, pnp);
270 	printf(" bus %d", pba->pba_bus);
271 
272 	return UNCONF;
273 }
274 
275 /*
276  * various PCI helpers
277  */
278 void
279 octeon_pcibus_attach_hook(struct device *parent, struct device *self,
280     struct pcibus_attach_args *pba)
281 {
282 }
283 
284 /*
285  * PCI configuration space access routines
286  */
287 int
288 octeon_pcibus_bus_maxdevs(void *v, int busno)
289 {
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 %ld", 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 
470 	exnamesz = 1 + 16 + 4;
471 	exname = malloc(exnamesz, M_DEVBUF, M_NOWAIT);
472 	if (exname == NULL)
473 		return NULL;
474 	snprintf(exname, exnamesz, "%s%s", sc->sc_dev.dv_xname,
475 	    io ? "_io" : "_mem");
476 
477 	ex = extent_create(exname, 0, 0xffffffffffffffff, M_DEVBUF, NULL, 0,
478 	    EX_NOWAIT | EX_FILLED);
479 	if (ex == NULL)
480 		goto error;
481 
482 	if (io) {
483 		if (extent_free(ex, _OCTEON_PCIBUS_PCIIO_BASE,
484 		    _OCTEON_PCIBUS_PCIIO_SIZE, EX_NOWAIT) != 0)
485 			goto error;
486 	} else {
487 		if (extent_free(ex, _OCTEON_PCIBUS_PCIMEM_BASE,
488 		    _OCTEON_PCIBUS_PCIMEM_SIZE, EX_NOWAIT) != 0)
489 			goto error;
490 	}
491 
492 #if defined(DEBUG) && defined(DIAGNOSTIC)
493 	extent_print(ex);
494 #endif
495 	return ex;
496 
497 error:
498 	if (ex != NULL)
499 		extent_destroy(ex);
500 	free(exname, M_DEVBUF, exnamesz);
501 	return NULL;
502 }
503 
504 /*
505  * PCI model specific routines
506  */
507 
508 int
509 octeon_pcibus_intr_map(int dev, int fn, int pin)
510 {
511 	return CIU_INT_PCI_INTA + ((pin - 1) & 3);
512 }
513