xref: /NextBSD/sys/mips/adm5120/admpci.c (revision 84d351007654069f9643c8e4b4802a7f5f08ee42)
1 /* $NetBSD: admpci.c,v 1.1 2007/03/20 08:52:02 dyoung Exp $ */
2 
3 /*-
4  * Copyright (c) 2007 David Young.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or
7  * without modification, are permitted provided that the following
8  * conditions are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above
12  *    copyright notice, this list of conditions and the following
13  *    disclaimer in the documentation and/or other materials provided
14  *    with the distribution.
15  * 3. The name of the author may not be used to endorse or promote
16  *    products derived from this software without specific prior
17  *    written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
20  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22  * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
24  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
26  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
28  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
29  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
30  * OF SUCH DAMAGE.
31  */
32 /*-
33  * Copyright (c) 2006 Itronix Inc.
34  * All rights reserved.
35  *
36  * Written by Garrett D'Amore for Itronix Inc.
37  *
38  * Redistribution and use in source and binary forms, with or without
39  * modification, are permitted provided that the following conditions
40  * are met:
41  * 1. Redistributions of source code must retain the above copyright
42  *    notice, this list of conditions and the following disclaimer.
43  * 2. Redistributions in binary form must reproduce the above copyright
44  *    notice, this list of conditions and the following disclaimer in the
45  *    documentation and/or other materials provided with the distribution.
46  * 3. The name of Itronix Inc. may not be used to endorse
47  *    or promote products derived from this software without specific
48  *    prior written permission.
49  *
50  * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
51  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
52  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
53  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
54  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
55  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
56  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
57  * ON ANY THEORY OF LIABILITY, WHETHER IN
58  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
59  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
60  * POSSIBILITY OF SUCH DAMAGE.
61  */
62 
63 #include <sys/cdefs.h>
64 __FBSDID("$FreeBSD$");
65 
66 #include <sys/param.h>
67 #include <sys/systm.h>
68 
69 #include <sys/bus.h>
70 #include <sys/interrupt.h>
71 #include <sys/malloc.h>
72 #include <sys/kernel.h>
73 #include <sys/module.h>
74 #include <sys/rman.h>
75 
76 #include <vm/vm.h>
77 #include <vm/pmap.h>
78 #include <vm/vm_extern.h>
79 
80 #include <machine/bus.h>
81 #include <machine/cpu.h>
82 #include <machine/pmap.h>
83 
84 #include <dev/pci/pcivar.h>
85 #include <dev/pci/pcireg.h>
86 
87 #include <dev/pci/pcib_private.h>
88 #include "pcib_if.h"
89 
90 #include <mips/adm5120/adm5120reg.h>
91 
92 #ifdef ADMPCI_DEBUG
93 int admpci_debug = 1;
94 #define	ADMPCI_DPRINTF(__fmt, ...)		\
95 do {						\
96 	if (admpci_debug)			\
97 		printf((__fmt), __VA_ARGS__);	\
98 } while (/*CONSTCOND*/0)
99 #else /* !ADMPCI_DEBUG */
100 #define	ADMPCI_DPRINTF(__fmt, ...)	do { } while (/*CONSTCOND*/0)
101 #endif /* ADMPCI_DEBUG */
102 
103 #define	ADMPCI_TAG_BUS_MASK		__BITS(23, 16)
104 /* Bit 11 is reserved.	It selects the AHB-PCI bridge.	Let device 0
105  * be the bridge.  For all other device numbers, let bit[11] == 0.
106  */
107 #define	ADMPCI_TAG_DEVICE_MASK		__BITS(15, 11)
108 #define	ADMPCI_TAG_DEVICE_SUBMASK	__BITS(15, 12)
109 #define	ADMPCI_TAG_DEVICE_BRIDGE	__BIT(11)
110 #define	ADMPCI_TAG_FUNCTION_MASK	__BITS(10, 8)
111 #define	ADMPCI_TAG_REGISTER_MASK	__BITS(7, 0)
112 
113 #define	ADMPCI_MAX_DEVICE
114 
115 struct admpci_softc {
116 	device_t		sc_dev;
117 	bus_space_tag_t		sc_st;
118 
119 	/* Access to PCI config registers */
120 	bus_space_handle_t	sc_addrh;
121 	bus_space_handle_t	sc_datah;
122 
123 	int			sc_busno;
124 	struct rman		sc_mem_rman;
125 	struct rman		sc_io_rman;
126 	struct rman		sc_irq_rman;
127 	uint32_t		sc_mem;
128 	uint32_t		sc_io;
129 };
130 
131 static int
admpci_probe(device_t dev)132 admpci_probe(device_t dev)
133 {
134 
135 	return (0);
136 }
137 
138 static int
admpci_attach(device_t dev)139 admpci_attach(device_t dev)
140 {
141 	int busno = 0;
142 	struct admpci_softc *sc = device_get_softc(dev);
143 
144 	sc->sc_dev = dev;
145 	sc->sc_busno = busno;
146 
147 	/* Use KSEG1 to access IO ports for it is uncached */
148 	sc->sc_io = MIPS_PHYS_TO_KSEG1(ADM5120_BASE_PCI_IO);
149 	sc->sc_io_rman.rm_type = RMAN_ARRAY;
150 	sc->sc_io_rman.rm_descr = "ADMPCI I/O Ports";
151 	if (rman_init(&sc->sc_io_rman) != 0 ||
152 		rman_manage_region(&sc->sc_io_rman, 0, 0xffff) != 0) {
153 		panic("admpci_attach: failed to set up I/O rman");
154 	}
155 
156 	/* Use KSEG1 to access PCI memory for it is uncached */
157 	sc->sc_mem = MIPS_PHYS_TO_KSEG1(ADM5120_BASE_PCI_MEM);
158 	sc->sc_mem_rman.rm_type = RMAN_ARRAY;
159 	sc->sc_mem_rman.rm_descr = "ADMPCI PCI Memory";
160 	if (rman_init(&sc->sc_mem_rman) != 0 ||
161 	    rman_manage_region(&sc->sc_mem_rman,
162 	    sc->sc_mem, sc->sc_mem + 0x100000) != 0) {
163 		panic("admpci_attach: failed to set up memory rman");
164 	}
165 
166 	sc->sc_irq_rman.rm_type = RMAN_ARRAY;
167 	sc->sc_irq_rman.rm_descr = "ADMPCI PCI IRQs";
168 	if (rman_init(&sc->sc_irq_rman) != 0 ||
169 	    rman_manage_region(&sc->sc_irq_rman, 1, 31) != 0)
170 		panic("admpci_attach: failed to set up IRQ rman");
171 
172 	if (bus_space_map(sc->sc_st, ADM5120_BASE_PCI_CONFADDR, 4, 0,
173 	    &sc->sc_addrh) != 0) {
174 		device_printf(sc->sc_dev, "unable to address space\n");
175 		panic("bus_space_map failed");
176 	}
177 
178 	if (bus_space_map(sc->sc_st, ADM5120_BASE_PCI_CONFDATA, 4, 0,
179 	    &sc->sc_datah) != 0) {
180 		device_printf(sc->sc_dev, "unable to address space\n");
181 		panic("bus_space_map failed");
182 	}
183 
184 	device_add_child(dev, "pci", -1);
185 	return (bus_generic_attach(dev));
186 }
187 
188 static int
admpci_maxslots(device_t dev)189 admpci_maxslots(device_t dev)
190 {
191 
192 	return (PCI_SLOTMAX);
193 }
194 
195 static uint32_t
admpci_make_addr(int bus,int slot,int func,int reg)196 admpci_make_addr(int bus, int slot, int func, int reg)
197 {
198 
199 	return (0x80000000 | (bus << 16) | (slot << 11) | (func << 8) | reg);
200 }
201 
202 static uint32_t
admpci_read_config(device_t dev,int bus,int slot,int func,int reg,int bytes)203 admpci_read_config(device_t dev, int bus, int slot, int func, int reg,
204     int bytes)
205 {
206 	struct admpci_softc *sc = device_get_softc(dev);
207 	uint32_t data;
208 	uint32_t shift, mask;
209 	bus_addr_t addr;
210 
211 	ADMPCI_DPRINTF("%s: sc %p tag (%x, %x, %x) reg %d\n", __func__,
212 			(void *)sc, bus, slot, func, reg);
213 
214 	addr = admpci_make_addr(bus, slot, func, reg);
215 
216 	ADMPCI_DPRINTF("%s: sc_addrh %p sc_datah %p addr %p\n", __func__,
217 	    (void *)sc->sc_addrh, (void *)sc->sc_datah, (void *)addr);
218 
219 	bus_space_write_4(sc->sc_io, sc->sc_addrh, 0, addr);
220 	data = bus_space_read_4(sc->sc_io, sc->sc_datah, 0);
221 
222 	switch (reg % 4) {
223 	case 3:
224 		shift = 24;
225 		break;
226 	case 2:
227 		shift = 16;
228 		break;
229 	case 1:
230 		shift = 8;
231 		break;
232 	default:
233 		shift = 0;
234 		break;
235 	}
236 
237 	switch (bytes) {
238 	case 1:
239 		mask = 0xff;
240 		data = (data >> shift) & mask;
241 		break;
242 	case 2:
243 		mask = 0xffff;
244 		if (reg % 4 == 0)
245 			data = data & mask;
246 		else
247 			data = (data >> 16) & mask;
248 		break;
249 	case 4:
250 		break;
251 	default:
252 		panic("%s: wrong bytes count", __func__);
253 		break;
254 	}
255 
256 	ADMPCI_DPRINTF("%s: read 0x%x\n", __func__, data);
257 	return (data);
258 }
259 
260 static void
admpci_write_config(device_t dev,int bus,int slot,int func,int reg,uint32_t data,int bytes)261 admpci_write_config(device_t dev, int bus, int slot, int func, int reg,
262     uint32_t data, int bytes)
263 {
264 	struct admpci_softc *sc = device_get_softc(dev);
265 	bus_addr_t addr;
266 	uint32_t reg_data;
267 	uint32_t shift, mask;
268 
269 	ADMPCI_DPRINTF("%s: sc %p tag (%x, %x, %x) reg %d\n", __func__,
270 			(void *)sc, bus, slot, func, reg);
271 
272 	if (bytes != 4) {
273 		reg_data = admpci_read_config(dev, bus, slot, func, reg, 4);
274 
275 		switch (reg % 4) {
276 		case 3:
277 			shift = 24;
278 			break;
279 		case 2:
280 			shift = 16;
281 			break;
282 		case 1:
283 			shift = 8;
284 			break;
285 		default:
286 			shift = 0;
287 			break;
288 		}
289 
290 		switch (bytes) {
291 		case 1:
292 			mask = 0xff;
293 			data = (reg_data & ~ (mask << shift)) | (data << shift);
294 			break;
295 		case 2:
296 			mask = 0xffff;
297 			if (reg % 4 == 0)
298 				data = (reg_data & ~mask) | data;
299 			else
300 				data = (reg_data & ~ (mask << shift)) |
301 				    (data << shift);
302 			break;
303 		case 4:
304 			break;
305 		default:
306 			panic("%s: wrong bytes count", __func__);
307 			break;
308 		}
309 	}
310 
311 	addr = admpci_make_addr(bus, slot, func, reg);
312 
313 	ADMPCI_DPRINTF("%s: sc_addrh %p sc_datah %p addr %p\n", __func__,
314 	    (void *)sc->sc_addrh, (void *)sc->sc_datah, (void *)addr);
315 
316 	bus_space_write_4(sc->sc_io, sc->sc_addrh, 0, addr);
317 	bus_space_write_4(sc->sc_io, sc->sc_datah, 0, data);
318 }
319 
320 static int
admpci_route_interrupt(device_t pcib,device_t dev,int pin)321 admpci_route_interrupt(device_t pcib, device_t dev, int pin)
322 {
323 	/* TODO: implement */
324 	return (0);
325 }
326 
327 static int
admpci_read_ivar(device_t dev,device_t child,int which,uintptr_t * result)328 admpci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
329 {
330 	struct admpci_softc *sc = device_get_softc(dev);
331 
332 	switch (which) {
333 	case PCIB_IVAR_DOMAIN:
334 		*result = 0;
335 		return (0);
336 	case PCIB_IVAR_BUS:
337 		*result = sc->sc_busno;
338 		return (0);
339 	}
340 
341 	return (ENOENT);
342 }
343 
344 static int
admpci_write_ivar(device_t dev,device_t child,int which,uintptr_t result)345 admpci_write_ivar(device_t dev, device_t child, int which, uintptr_t result)
346 {
347 	struct admpci_softc * sc = device_get_softc(dev);
348 
349 	switch (which) {
350 	case PCIB_IVAR_BUS:
351 		sc->sc_busno = result;
352 		return (0);
353 	}
354 	return (ENOENT);
355 }
356 
357 static struct resource *
admpci_alloc_resource(device_t bus,device_t child,int type,int * rid,u_long start,u_long end,u_long count,u_int flags)358 admpci_alloc_resource(device_t bus, device_t child, int type, int *rid,
359     u_long start, u_long end, u_long count, u_int flags)
360 {
361 
362 	return (NULL);
363 #if 0
364 	struct admpci_softc *sc = device_get_softc(bus);
365 	struct resource *rv = NULL;
366 	struct rman *rm;
367 	bus_space_handle_t bh = 0;
368 
369 	switch (type) {
370 	case SYS_RES_IRQ:
371 		rm = &sc->sc_irq_rman;
372 		break;
373 	case SYS_RES_MEMORY:
374 		rm = &sc->sc_mem_rman;
375 		bh = sc->sc_mem;
376 		break;
377 	case SYS_RES_IOPORT:
378 		rm = &sc->sc_io_rman;
379 		bh = sc->sc_io;
380 		break;
381 	default:
382 		return (NULL);
383 	}
384 
385 	rv = rman_reserve_resource(rm, start, end, count, flags, child);
386 	if (rv == NULL)
387 		return (NULL);
388 	rman_set_rid(rv, *rid);
389 	if (type != SYS_RES_IRQ) {
390 		bh += (rman_get_start(rv));
391 
392 		rman_set_bustag(rv, sc->sc_st);
393 		rman_set_bushandle(rv, bh);
394 		if (flags & RF_ACTIVE) {
395 			if (bus_activate_resource(child, type, *rid, rv)) {
396 				rman_release_resource(rv);
397 				return (NULL);
398 			}
399 		}
400 	}
401 	return (rv);
402 #endif
403 }
404 
405 static int
admpci_activate_resource(device_t bus,device_t child,int type,int rid,struct resource * r)406 admpci_activate_resource(device_t bus, device_t child, int type, int rid,
407     struct resource *r)
408 {
409 	bus_space_handle_t p;
410 	int error;
411 
412 	if ((type == SYS_RES_MEMORY) || (type == SYS_RES_IOPORT)) {
413 		error = bus_space_map(rman_get_bustag(r),
414 		    rman_get_bushandle(r), rman_get_size(r), 0, &p);
415 		if (error)
416 			return (error);
417 		rman_set_bushandle(r, p);
418 	}
419 	return (rman_activate_resource(r));
420 }
421 
422 static int
admpci_setup_intr(device_t dev,device_t child,struct resource * ires,int flags,driver_filter_t * filt,driver_intr_t * handler,void * arg,void ** cookiep)423 admpci_setup_intr(device_t dev, device_t child, struct resource *ires,
424 		int flags, driver_filter_t *filt, driver_intr_t *handler,
425 		void *arg, void **cookiep)
426 {
427 
428 #if 0
429 	struct admpci_softc *sc = device_get_softc(dev);
430 	struct intr_event *event;
431 	int irq, error;
432 
433 	irq = rman_get_start(ires);
434 	if (irq >= ICU_LEN || irq == 2)
435 		panic("%s: bad irq or type", __func__);
436 
437 	event = sc->sc_eventstab[irq];
438 	if (event == NULL) {
439 		error = intr_event_create(&event, (void *)irq, 0,
440 		    (void (*)(void *))NULL, "admpci intr%d:", irq);
441 		if (error)
442 			return 0;
443 		sc->sc_eventstab[irq] = event;
444 	}
445 
446 	intr_event_add_handler(event, device_get_nameunit(child), filt,
447 	    handler, arg, intr_priority(flags), flags, cookiep);
448 
449 	/* Enable it, set trigger mode. */
450 	sc->sc_imask &= ~(1 << irq);
451 	sc->sc_elcr &= ~(1 << irq);
452 
453 	admpci_set_icus(sc);
454 #endif
455 
456 	return (0);
457 }
458 
459 static int
admpci_teardown_intr(device_t dev,device_t child,struct resource * res,void * cookie)460 admpci_teardown_intr(device_t dev, device_t child, struct resource *res,
461     void *cookie)
462 {
463 
464 	return (intr_event_remove_handler(cookie));
465 }
466 
467 static device_method_t admpci_methods[] = {
468 	/* Device interface */
469 	DEVMETHOD(device_probe,		admpci_probe),
470 	DEVMETHOD(device_attach,	admpci_attach),
471 	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
472 	DEVMETHOD(device_suspend,	bus_generic_suspend),
473 	DEVMETHOD(device_resume,	bus_generic_resume),
474 
475 	/* Bus interface */
476 	DEVMETHOD(bus_read_ivar,	admpci_read_ivar),
477 	DEVMETHOD(bus_write_ivar,	admpci_write_ivar),
478 	DEVMETHOD(bus_alloc_resource,	admpci_alloc_resource),
479 	DEVMETHOD(bus_release_resource,	bus_generic_release_resource),
480 	DEVMETHOD(bus_activate_resource, admpci_activate_resource),
481 	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
482 	DEVMETHOD(bus_setup_intr,	admpci_setup_intr),
483 	DEVMETHOD(bus_teardown_intr,	admpci_teardown_intr),
484 
485 	/* pcib interface */
486 	DEVMETHOD(pcib_maxslots,	admpci_maxslots),
487 	DEVMETHOD(pcib_read_config,	admpci_read_config),
488 	DEVMETHOD(pcib_write_config,	admpci_write_config),
489 	DEVMETHOD(pcib_route_interrupt,	admpci_route_interrupt),
490 
491 	DEVMETHOD_END
492 };
493 
494 static driver_t admpci_driver = {
495 	"pcib",
496 	admpci_methods,
497 	sizeof(struct admpci_softc),
498 };
499 
500 static devclass_t admpci_devclass;
501 
502 DRIVER_MODULE(admpci, obio, admpci_driver, admpci_devclass, 0, 0);
503