]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/powerpc/mpc85xx/lbc.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / powerpc / mpc85xx / lbc.c
1 /*-
2  * Copyright (c) 2006-2008, Juniper Networks, Inc.
3  * Copyright (c) 2008 Semihalf, Rafal Czubak
4  * Copyright (c) 2009 The FreeBSD Foundation
5  * All rights reserved.
6  *
7  * Portions of this software were developed by Semihalf
8  * under sponsorship from the FreeBSD Foundation.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/ktr.h>
40 #include <sys/kernel.h>
41 #include <sys/malloc.h>
42 #include <sys/module.h>
43 #include <sys/bus.h>
44 #include <sys/rman.h>
45 #include <machine/bus.h>
46
47 #include <vm/vm.h>
48 #include <vm/pmap.h>
49
50 #include <dev/fdt/fdt_common.h>
51 #include <dev/ofw/ofw_bus.h>
52 #include <dev/ofw/ofw_bus_subr.h>
53
54 #include <powerpc/mpc85xx/mpc85xx.h>
55
56 #include "ofw_bus_if.h"
57 #include "lbc.h"
58
59 #define DEBUG
60 #undef DEBUG
61
62 #ifdef DEBUG
63 #define debugf(fmt, args...) do { printf("%s(): ", __func__);   \
64     printf(fmt,##args); } while (0)
65 #else
66 #define debugf(fmt, args...)
67 #endif
68
69 static __inline void
70 lbc_write_reg(struct lbc_softc *sc, bus_size_t off, uint32_t val)
71 {
72
73         bus_space_write_4(sc->sc_bst, sc->sc_bsh, off, val);
74 }
75
76 static __inline uint32_t
77 lbc_read_reg(struct lbc_softc *sc, bus_size_t off)
78 {
79
80         return (bus_space_read_4(sc->sc_bst, sc->sc_bsh, off));
81 }
82
83 static MALLOC_DEFINE(M_LBC, "localbus", "localbus devices information");
84
85 static int lbc_probe(device_t);
86 static int lbc_attach(device_t);
87 static int lbc_shutdown(device_t);
88 static struct resource *lbc_alloc_resource(device_t, device_t, int, int *,
89     u_long, u_long, u_long, u_int);
90 static int lbc_print_child(device_t, device_t);
91 static int lbc_release_resource(device_t, device_t, int, int,
92     struct resource *);
93 static const struct ofw_bus_devinfo *lbc_get_devinfo(device_t, device_t);
94
95 /*
96  * Bus interface definition
97  */
98 static device_method_t lbc_methods[] = {
99         /* Device interface */
100         DEVMETHOD(device_probe,         lbc_probe),
101         DEVMETHOD(device_attach,        lbc_attach),
102         DEVMETHOD(device_shutdown,      lbc_shutdown),
103
104         /* Bus interface */
105         DEVMETHOD(bus_print_child,      lbc_print_child),
106         DEVMETHOD(bus_setup_intr,       bus_generic_setup_intr),
107         DEVMETHOD(bus_teardown_intr,    NULL),
108
109         DEVMETHOD(bus_alloc_resource,   lbc_alloc_resource),
110         DEVMETHOD(bus_release_resource, lbc_release_resource),
111         DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
112         DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
113
114         /* OFW bus interface */
115         DEVMETHOD(ofw_bus_get_devinfo,  lbc_get_devinfo),
116         DEVMETHOD(ofw_bus_get_compat,   ofw_bus_gen_get_compat),
117         DEVMETHOD(ofw_bus_get_model,    ofw_bus_gen_get_model),
118         DEVMETHOD(ofw_bus_get_name,     ofw_bus_gen_get_name),
119         DEVMETHOD(ofw_bus_get_node,     ofw_bus_gen_get_node),
120         DEVMETHOD(ofw_bus_get_type,     ofw_bus_gen_get_type),
121
122         { 0, 0 }
123 };
124
125 static driver_t lbc_driver = {
126         "lbc",
127         lbc_methods,
128         sizeof(struct lbc_softc)
129 };
130
131 devclass_t lbc_devclass;
132
133 DRIVER_MODULE(lbc, fdtbus, lbc_driver, lbc_devclass, 0, 0);
134
135 /*
136  * Calculate address mask used by OR(n) registers. Use memory region size to
137  * determine mask value. The size must be a power of two and within the range
138  * of 32KB - 4GB. Otherwise error code is returned. Value representing
139  * 4GB size can be passed as 0xffffffff.
140  */
141 static uint32_t
142 lbc_address_mask(uint32_t size)
143 {
144         int n = 15;
145
146         if (size == ~0UL)
147                 return (0);
148
149         while (n < 32) {
150                 if (size == (1UL << n))
151                         break;
152                 n++;
153         }
154
155         if (n == 32)
156                 return (EINVAL);
157
158         return (0xffff8000 << (n - 15));
159 }
160
161 static void
162 lbc_banks_unmap(struct lbc_softc *sc)
163 {
164         int i;
165
166         for (i = 0; i < LBC_DEV_MAX; i++) {
167                 if (sc->sc_banks[i].size == 0)
168                         continue;
169
170                 law_disable(OCP85XX_TGTIF_LBC, sc->sc_banks[i].pa,
171                     sc->sc_banks[i].size);
172                 pmap_unmapdev(sc->sc_banks[i].va, sc->sc_banks[i].size);
173         }
174 }
175
176 static int
177 lbc_banks_map(struct lbc_softc *sc)
178 {
179         u_long start, size;
180         int error, i;
181
182         for (i = 0; i < LBC_DEV_MAX; i++) {
183                 if (sc->sc_banks[i].size == 0)
184                         continue;
185
186                 /* Physical address start/size. */
187                 start = sc->sc_banks[i].pa;
188                 size = sc->sc_banks[i].size;
189
190                 /*
191                  * Configure LAW for this LBC bank (CS) and map its physical
192                  * memory region into KVA.
193                  */
194                 error = law_enable(OCP85XX_TGTIF_LBC, start, size);
195                 if (error)
196                         return (error);
197
198                 sc->sc_banks[i].va = (vm_offset_t)pmap_mapdev(start, size);
199                 if (sc->sc_banks[i].va == 0) {
200                         lbc_banks_unmap(sc);
201                         return (ENOSPC);
202                 }
203         }
204         return (0);
205 }
206
207 static int
208 lbc_banks_enable(struct lbc_softc *sc)
209 {
210         u_long size;
211         uint32_t regval;
212         int error, i;
213
214         for (i = 0; i < LBC_DEV_MAX; i++) {
215                 size = sc->sc_banks[i].size;
216                 if (size == 0)
217                         continue;
218                 /*
219                  * Compute and program BR value.
220                  */
221                 regval = 0;
222                 regval |= sc->sc_banks[i].pa;
223
224                 switch (sc->sc_banks[i].width) {
225                 case 8:
226                         regval |= (1 << 11);
227                         break;
228                 case 16:
229                         regval |= (2 << 11);
230                         break;
231                 case 32:
232                         regval |= (3 << 11);
233                         break;
234                 default:
235                         error = EINVAL;
236                         goto fail;
237                 }
238                 regval |= (sc->sc_banks[i].decc << 9);
239                 regval |= (sc->sc_banks[i].wp << 8);
240                 regval |= (sc->sc_banks[i].msel << 5);
241                 regval |= (sc->sc_banks[i].atom << 2);
242                 regval |= 1;
243
244                 lbc_write_reg(sc, LBC85XX_BR(i), regval);
245
246                 /*
247                  * Compute and program OR value.
248                  */
249                 regval = 0;
250                 regval |= lbc_address_mask(size);
251
252                 switch (sc->sc_banks[i].msel) {
253                 case LBCRES_MSEL_GPCM:
254                         /* TODO Add flag support for option registers */
255                         regval |= 0x00000ff7;
256                         break;
257                 case LBCRES_MSEL_FCM:
258                         printf("FCM mode not supported yet!");
259                         error = ENOSYS;
260                         goto fail;
261                 case LBCRES_MSEL_UPMA:
262                 case LBCRES_MSEL_UPMB:
263                 case LBCRES_MSEL_UPMC:
264                         printf("UPM mode not supported yet!");
265                         error = ENOSYS;
266                         goto fail;
267                 }
268                 lbc_write_reg(sc, LBC85XX_OR(i), regval);
269         }
270
271         /*
272          * Initialize configuration register:
273          * - enable Local Bus
274          * - set data buffer control signal function
275          * - disable parity byte select
276          * - set ECC parity type
277          * - set bus monitor timing and timer prescale
278          */
279         lbc_write_reg(sc, LBC85XX_LBCR, 0);
280
281         /*
282          * Initialize clock ratio register:
283          * - disable PLL bypass mode
284          * - configure LCLK delay cycles for the assertion of LALE
285          * - set system clock divider
286          */
287         lbc_write_reg(sc, LBC85XX_LCRR, 0x00030008);
288
289         return (0);
290
291 fail:
292         lbc_banks_unmap(sc);
293         return (error);
294 }
295
296 static void
297 fdt_lbc_fixup(phandle_t node, struct lbc_softc *sc, struct lbc_devinfo *di)
298 {
299         pcell_t width;
300         int bank;
301
302         if (OF_getprop(node, "bank-width", (void *)&width, sizeof(width)) <= 0)
303                 return;
304
305         bank = di->di_bank;
306         if (sc->sc_banks[bank].size == 0)
307                 return;
308
309         /* Express width in bits. */
310         sc->sc_banks[bank].width = width * 8;
311 }
312
313 static int
314 fdt_lbc_reg_decode(phandle_t node, struct lbc_softc *sc,
315     struct lbc_devinfo *di)
316 {
317         u_long start, end, count;
318         pcell_t *reg, *regptr;
319         pcell_t addr_cells, size_cells;
320         int tuple_size, tuples;
321         int i, rv, bank;
322
323         if (fdt_addrsize_cells(OF_parent(node), &addr_cells, &size_cells) != 0)
324                 return (ENXIO);
325
326         tuple_size = sizeof(pcell_t) * (addr_cells + size_cells);
327         tuples = OF_getprop_alloc(node, "reg", tuple_size, (void **)&reg);
328         debugf("addr_cells = %d, size_cells = %d\n", addr_cells, size_cells);
329         debugf("tuples = %d, tuple size = %d\n", tuples, tuple_size);
330         if (tuples <= 0)
331                 /* No 'reg' property in this node. */
332                 return (0);
333
334         regptr = reg;
335         for (i = 0; i < tuples; i++) {
336
337                 bank = fdt_data_get((void *)reg, 1);
338                 di->di_bank = bank;
339                 reg += 1;
340
341                 /* Get address/size. */
342                 rv = fdt_data_to_res(reg, addr_cells - 1, size_cells, &start,
343                     &count);
344                 if (rv != 0) {
345                         resource_list_free(&di->di_res);
346                         goto out;
347                 }
348                 reg += addr_cells - 1 + size_cells;
349
350                 /* Calculate address range relative to VA base. */
351                 start = sc->sc_banks[bank].va + start;
352                 end = start + count - 1;
353
354                 debugf("reg addr bank = %d, start = %lx, end = %lx, "
355                     "count = %lx\n", bank, start, end, count);
356
357                 /* Use bank (CS) cell as rid. */
358                 resource_list_add(&di->di_res, SYS_RES_MEMORY, bank, start,
359                     end, count);
360         }
361         rv = 0;
362 out:
363         free(regptr, M_OFWPROP);
364         return (rv);
365 }
366
367 static int
368 lbc_probe(device_t dev)
369 {
370
371         if (!(ofw_bus_is_compatible(dev, "fsl,lbc") ||
372             ofw_bus_is_compatible(dev, "fsl,elbc")))
373                 return (ENXIO);
374
375         device_set_desc(dev, "Freescale Local Bus Controller");
376         return (BUS_PROBE_DEFAULT);
377 }
378
379 static int
380 lbc_attach(device_t dev)
381 {
382         struct lbc_softc *sc;
383         struct lbc_devinfo *di;
384         struct rman *rm;
385         u_long offset, start, size;
386         device_t cdev;
387         phandle_t node, child;
388         pcell_t *ranges, *rangesptr;
389         int tuple_size, tuples;
390         int par_addr_cells;
391         int bank, error, i;
392
393         sc = device_get_softc(dev);
394         sc->sc_dev = dev;
395
396         sc->sc_rid = 0;
397         sc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rid,
398             RF_ACTIVE);
399         if (sc->sc_res == NULL)
400                 return (ENXIO);
401
402         sc->sc_bst = rman_get_bustag(sc->sc_res);
403         sc->sc_bsh = rman_get_bushandle(sc->sc_res);
404         rangesptr = NULL;
405
406         rm = &sc->sc_rman;
407         rm->rm_type = RMAN_ARRAY;
408         rm->rm_descr = "Local Bus Space";
409         rm->rm_start = 0UL;
410         rm->rm_end = ~0UL;
411         error = rman_init(rm);
412         if (error)
413                 goto fail;
414
415         error = rman_manage_region(rm, rm->rm_start, rm->rm_end);
416         if (error) {
417                 rman_fini(rm);
418                 goto fail;
419         }
420
421         /*
422          * Process 'ranges' property.
423          */
424         node = ofw_bus_get_node(dev);
425         if ((fdt_addrsize_cells(node, &sc->sc_addr_cells,
426             &sc->sc_size_cells)) != 0) {
427                 error = ENXIO;
428                 goto fail;
429         }
430
431         par_addr_cells = fdt_parent_addr_cells(node);
432         if (par_addr_cells > 2) {
433                 device_printf(dev, "unsupported parent #addr-cells\n");
434                 error = ERANGE;
435                 goto fail;
436         }
437         tuple_size = sizeof(pcell_t) * (sc->sc_addr_cells + par_addr_cells +
438             sc->sc_size_cells);
439
440         tuples = OF_getprop_alloc(node, "ranges", tuple_size,
441             (void **)&ranges);
442         if (tuples < 0) {
443                 device_printf(dev, "could not retrieve 'ranges' property\n");
444                 error = ENXIO;
445                 goto fail;
446         }
447         rangesptr = ranges;
448
449         debugf("par addr_cells = %d, addr_cells = %d, size_cells = %d, "
450             "tuple_size = %d, tuples = %d\n", par_addr_cells,
451             sc->sc_addr_cells, sc->sc_size_cells, tuple_size, tuples);
452
453         start = 0;
454         size = 0;
455         for (i = 0; i < tuples; i++) {
456
457                 /* The first cell is the bank (chip select) number. */
458                 bank = fdt_data_get((void *)ranges, 1);
459                 if (bank < 0 || bank > LBC_DEV_MAX) {
460                         device_printf(dev, "bank out of range: %d\n", bank);
461                         error = ERANGE;
462                         goto fail;
463                 }
464                 ranges += 1;
465
466                 /*
467                  * Remaining cells of the child address define offset into
468                  * this CS.
469                  */
470                 offset = fdt_data_get((void *)ranges, sc->sc_addr_cells - 1);
471                 ranges += sc->sc_addr_cells - 1;
472
473                 /* Parent bus start address of this bank. */
474                 start = fdt_data_get((void *)ranges, par_addr_cells);
475                 ranges += par_addr_cells;
476
477                 size = fdt_data_get((void *)ranges, sc->sc_size_cells);
478                 ranges += sc->sc_size_cells;
479                 debugf("bank = %d, start = %lx, size = %lx\n", bank,
480                     start, size);
481
482                 sc->sc_banks[bank].pa = start + offset;
483                 sc->sc_banks[bank].size = size;
484
485                 /*
486                  * Attributes for the bank.
487                  *
488                  * XXX Note there are no DT bindings defined for them at the
489                  * moment, so we need to provide some defaults.
490                  */
491                 sc->sc_banks[bank].width = 16;
492                 sc->sc_banks[bank].msel = LBCRES_MSEL_GPCM;
493                 sc->sc_banks[bank].decc = LBCRES_DECC_DISABLED;
494                 sc->sc_banks[bank].atom = LBCRES_ATOM_DISABLED;
495                 sc->sc_banks[bank].wp = 0;
496         }
497
498         /*
499          * Initialize mem-mappings for the LBC banks (i.e. chip selects).
500          */
501         error = lbc_banks_map(sc);
502         if (error)
503                 goto fail;
504
505         /*
506          * Walk the localbus and add direct subordinates as our children.
507          */
508         for (child = OF_child(node); child != 0; child = OF_peer(child)) {
509
510                 di = malloc(sizeof(*di), M_LBC, M_WAITOK | M_ZERO);
511
512                 if (ofw_bus_gen_setup_devinfo(&di->di_ofw, child) != 0) {
513                         free(di, M_LBC);
514                         device_printf(dev, "could not set up devinfo\n");
515                         continue;
516                 }
517
518                 resource_list_init(&di->di_res);
519
520                 if (fdt_lbc_reg_decode(child, sc, di)) {
521                         device_printf(dev, "could not process 'reg' "
522                             "property\n");
523                         ofw_bus_gen_destroy_devinfo(&di->di_ofw);
524                         free(di, M_LBC);
525                         continue;
526                 }
527
528                 fdt_lbc_fixup(child, sc, di);
529
530                 /* Add newbus device for this FDT node */
531                 cdev = device_add_child(dev, NULL, -1);
532                 if (cdev == NULL) {
533                         device_printf(dev, "could not add child: %s\n",
534                             di->di_ofw.obd_name);
535                         resource_list_free(&di->di_res);
536                         ofw_bus_gen_destroy_devinfo(&di->di_ofw);
537                         free(di, M_LBC);
538                         continue;
539                 }
540                 debugf("added child name='%s', node=%p\n", di->di_ofw.obd_name,
541                     (void *)child);
542                 device_set_ivars(cdev, di);
543         }
544
545         /*
546          * Enable the LBC.
547          */
548         lbc_banks_enable(sc);
549
550         free(rangesptr, M_OFWPROP);
551         return (bus_generic_attach(dev));
552
553 fail:
554         free(rangesptr, M_OFWPROP);
555         bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rid, sc->sc_res);
556         return (error);
557 }
558
559 static int
560 lbc_shutdown(device_t dev)
561 {
562
563         /* TODO */
564         return(0);
565 }
566
567 static struct resource *
568 lbc_alloc_resource(device_t bus, device_t child, int type, int *rid,
569     u_long start, u_long end, u_long count, u_int flags)
570 {
571         struct lbc_softc *sc;
572         struct lbc_devinfo *di;
573         struct resource_list_entry *rle;
574         struct resource *res;
575         struct rman *rm;
576         int needactivate;
577
578         /* We only support default allocations. */
579         if (start != 0ul || end != ~0ul)
580                 return (NULL);
581
582         sc = device_get_softc(bus);
583         if (type == SYS_RES_IRQ)
584                 return (bus_alloc_resource(bus, type, rid, start, end, count,
585                     flags));
586
587         /*
588          * Request for the default allocation with a given rid: use resource
589          * list stored in the local device info.
590          */
591         if ((di = device_get_ivars(child)) == NULL)
592                 return (NULL);
593
594         if (type == SYS_RES_IOPORT)
595                 type = SYS_RES_MEMORY;
596
597         rid = &di->di_bank;
598
599         rle = resource_list_find(&di->di_res, type, *rid);
600         if (rle == NULL) {
601                 device_printf(bus, "no default resources for "
602                     "rid = %d, type = %d\n", *rid, type);
603                 return (NULL);
604         }
605         start = rle->start;
606         count = rle->count;
607         end = start + count - 1;
608
609         sc = device_get_softc(bus);
610
611         needactivate = flags & RF_ACTIVE;
612         flags &= ~RF_ACTIVE;
613
614         rm = &sc->sc_rman;
615
616         res = rman_reserve_resource(rm, start, end, count, flags, child);
617         if (res == NULL) {
618                 device_printf(bus, "failed to reserve resource %#lx - %#lx "
619                     "(%#lx)\n", start, end, count);
620                 return (NULL);
621         }
622
623         rman_set_rid(res, *rid);
624         rman_set_bustag(res, &bs_be_tag);
625         rman_set_bushandle(res, rman_get_start(res));
626
627         if (needactivate)
628                 if (bus_activate_resource(child, type, *rid, res)) {
629                         device_printf(child, "resource activation failed\n");
630                         rman_release_resource(res);
631                         return (NULL);
632                 }
633
634         return (res);
635 }
636
637 static int
638 lbc_print_child(device_t dev, device_t child)
639 {
640         struct lbc_devinfo *di;
641         struct resource_list *rl;
642         int rv;
643
644         di = device_get_ivars(child);
645         rl = &di->di_res;
646
647         rv = 0;
648         rv += bus_print_child_header(dev, child);
649         rv += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx");
650         rv += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
651         rv += bus_print_child_footer(dev, child);
652
653         return (rv);
654 }
655
656 static int
657 lbc_release_resource(device_t dev, device_t child, int type, int rid,
658     struct resource *res)
659 {
660         int err;
661
662         if (rman_get_flags(res) & RF_ACTIVE) {
663                 err = bus_deactivate_resource(child, type, rid, res);
664                 if (err)
665                         return (err);
666         }
667
668         return (rman_release_resource(res));
669 }
670
671 static const struct ofw_bus_devinfo *
672 lbc_get_devinfo(device_t bus, device_t child)
673 {
674         struct lbc_devinfo *di;
675
676         di = device_get_ivars(child);
677         return (&di->di_ofw);
678 }