xref: /freebsd/sys/powerpc/mpc85xx/lbc.c (revision aa0a1e58)
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 }
679