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
69static __inline void
70lbc_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
76static __inline uint32_t
77lbc_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
83static MALLOC_DEFINE(M_LBC, "localbus", "localbus devices information");
84
85static int lbc_probe(device_t);
86static int lbc_attach(device_t);
87static int lbc_shutdown(device_t);
88static struct resource *lbc_alloc_resource(device_t, device_t, int, int *,
89    u_long, u_long, u_long, u_int);
90static int lbc_print_child(device_t, device_t);
91static int lbc_release_resource(device_t, device_t, int, int,
92    struct resource *);
93static const struct ofw_bus_devinfo *lbc_get_devinfo(device_t, device_t);
94
95/*
96 * Bus interface definition
97 */
98static 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
125static driver_t lbc_driver = {
126	"lbc",
127	lbc_methods,
128	sizeof(struct lbc_softc)
129};
130
131devclass_t lbc_devclass;
132
133DRIVER_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 */
141static uint32_t
142lbc_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
161static void
162lbc_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
176static int
177lbc_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
207static int
208lbc_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
291fail:
292	lbc_banks_unmap(sc);
293	return (error);
294}
295
296static void
297fdt_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
313static int
314fdt_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;
362out:
363	free(regptr, M_OFWPROP);
364	return (rv);
365}
366
367static int
368lbc_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
379static int
380lbc_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
553fail:
554	free(rangesptr, M_OFWPROP);
555	bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rid, sc->sc_res);
556	return (error);
557}
558
559static int
560lbc_shutdown(device_t dev)
561{
562
563	/* TODO */
564	return(0);
565}
566
567static struct resource *
568lbc_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
637static int
638lbc_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
656static int
657lbc_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
671static const struct ofw_bus_devinfo *
672lbc_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