]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/mips/adm5120/admpci.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / mips / adm5120 / admpci.c
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
132 admpci_probe(device_t dev)
133 {
134
135         return (0);
136 }
137
138 static int
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", busno);
185         return (bus_generic_attach(dev));
186 }
187
188 static int
189 admpci_maxslots(device_t dev)
190 {
191
192         return (PCI_SLOTMAX);
193 }
194
195 static uint32_t
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
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
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
321 admpci_route_interrupt(device_t pcib, device_t dev, int pin)
322 {
323         /* TODO: implement */
324         return (0);
325 }
326
327 static int
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
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 *
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
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
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
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);