xref: /freebsd/sys/powerpc/mpc85xx/lbc.c (revision 5022f21bd974c740b9052f149fb31745dc602965)
1 /*-
2  * Copyright (c) 2006-2008, Juniper Networks, Inc.
3  * Copyright (c) 2008 Semihalf, Rafal Czubak
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * 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 copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32 
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/ktr.h>
36 #include <sys/kernel.h>
37 #include <sys/malloc.h>
38 #include <sys/module.h>
39 #include <sys/bus.h>
40 #include <sys/rman.h>
41 #include <machine/bus.h>
42 #include <machine/ocpbus.h>
43 
44 #include <vm/vm.h>
45 #include <vm/pmap.h>
46 
47 #include <powerpc/mpc85xx/lbc.h>
48 #include <powerpc/mpc85xx/mpc85xx.h>
49 #include <powerpc/mpc85xx/ocpbus.h>
50 
51 struct lbc_softc {
52 	device_t		sc_dev;
53 
54 	struct resource		*sc_res;
55 	bus_space_handle_t	sc_bsh;
56 	bus_space_tag_t		sc_bst;
57 	int			sc_rid;
58 
59 	struct rman		sc_rman;
60 	vm_offset_t		sc_kva[LBC_DEV_MAX];
61 };
62 
63 struct lbc_devinfo {
64 	int		lbc_devtype;
65 	/* LBC child unit. It also represents resource table entry number */
66 	int		lbc_unit;
67 };
68 
69 /* Resources for MPC8555CDS system */
70 const struct lbc_resource mpc85xx_lbc_resources[] = {
71 	/* Boot flash bank */
72 	{
73 		LBC_DEVTYPE_CFI, 0, 0xff800000, 0x00800000, 16,
74 		LBCRES_MSEL_GPCM, LBCRES_DECC_DISABLED,
75 		LBCRES_ATOM_DISABLED, 0
76 	},
77 
78 	/* Second flash bank */
79 	{
80 		LBC_DEVTYPE_CFI, 1, 0xff000000, 0x00800000, 16,
81 		LBCRES_MSEL_GPCM, LBCRES_DECC_DISABLED,
82 		LBCRES_ATOM_DISABLED, 0
83 	},
84 
85 	/* DS1553 RTC/NVRAM */
86 	{
87 		LBC_DEVTYPE_RTC, 2, 0xf8000000, 0x8000, 8,
88 		LBCRES_MSEL_GPCM, LBCRES_DECC_DISABLED,
89 		LBCRES_ATOM_DISABLED, 0
90 	},
91 
92 	{0}
93 };
94 
95 static int lbc_probe(device_t);
96 static int lbc_attach(device_t);
97 static int lbc_shutdown(device_t);
98 static int lbc_get_resource(device_t, device_t, int, int, u_long *,
99     u_long *);
100 static struct resource *lbc_alloc_resource(device_t, device_t, int, int *,
101     u_long, u_long, u_long, u_int);
102 static int lbc_print_child(device_t, device_t);
103 static int lbc_release_resource(device_t, device_t, int, int,
104     struct resource *);
105 static int lbc_read_ivar(device_t, device_t, int, uintptr_t *);
106 
107 /*
108  * Bus interface definition
109  */
110 static device_method_t lbc_methods[] = {
111 	/* Device interface */
112 	DEVMETHOD(device_probe,		lbc_probe),
113 	DEVMETHOD(device_attach,	lbc_attach),
114 	DEVMETHOD(device_shutdown,	lbc_shutdown),
115 
116 	/* Bus interface */
117 	DEVMETHOD(bus_print_child,	lbc_print_child),
118 	DEVMETHOD(bus_read_ivar,	lbc_read_ivar),
119 	DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),
120 	DEVMETHOD(bus_teardown_intr,	NULL),
121 
122 	DEVMETHOD(bus_get_resource,	NULL),
123 	DEVMETHOD(bus_alloc_resource,	lbc_alloc_resource),
124 	DEVMETHOD(bus_release_resource,	lbc_release_resource),
125 	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
126 	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
127 
128 	{ 0, 0 }
129 };
130 
131 static driver_t lbc_driver = {
132 	"lbc",
133 	lbc_methods,
134 	sizeof(struct lbc_softc)
135 };
136 devclass_t lbc_devclass;
137 DRIVER_MODULE(lbc, ocpbus, lbc_driver, lbc_devclass, 0, 0);
138 
139 static __inline void
140 lbc_write_reg(struct lbc_softc *sc, bus_size_t off, uint32_t val)
141 {
142 
143 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, off, val);
144 }
145 
146 static __inline uint32_t
147 lbc_read_reg(struct lbc_softc *sc, bus_size_t off)
148 {
149 
150 	return (bus_space_read_4(sc->sc_bst, sc->sc_bsh, off));
151 }
152 
153 /*
154  * Calculate address mask used by OR(n) registers. Use memory region size to
155  * determine mask value. The size must be a power of two and within the range
156  * of 32KB - 4GB. Otherwise error code is returned. Value representing
157  * 4GB size can be passed as 0xffffffff.
158  */
159 static uint32_t
160 lbc_address_mask(uint32_t size)
161 {
162 	int n = 15;
163 
164 	if (size == ~0UL)
165 		return (0);
166 
167 	while (n < 32) {
168 		if (size == (1UL << n))
169 			break;
170 		n++;
171 	}
172 
173 	if (n == 32)
174 		return (EINVAL);
175 
176 	return (0xffff8000 << (n - 15));
177 }
178 
179 static device_t
180 lbc_mk_child(device_t dev, const struct lbc_resource *lbcres)
181 {
182 	struct lbc_devinfo *dinfo;
183 	device_t child;
184 
185 	if (lbcres->lbr_unit > LBC_DEV_MAX - 1)
186 		return (NULL);
187 
188 	child = device_add_child(dev, NULL, -1);
189 	if (child == NULL) {
190 		device_printf(dev, "could not add LBC child device\n");
191 		return (NULL);
192 	}
193 	dinfo = malloc(sizeof(struct lbc_devinfo), M_DEVBUF, M_WAITOK | M_ZERO);
194 	dinfo->lbc_devtype = lbcres->lbr_devtype;
195 	dinfo->lbc_unit = lbcres->lbr_unit;
196 	device_set_ivars(child, dinfo);
197 	return (child);
198 }
199 
200 static int
201 lbc_init_child(device_t dev, device_t child)
202 {
203 	struct lbc_softc *sc;
204 	struct lbc_devinfo *dinfo;
205 	const struct lbc_resource *res;
206 	u_long start, size;
207 	uint32_t regbuff;
208 	int error, unit;
209 
210 	sc = device_get_softc(dev);
211 	dinfo = device_get_ivars(child);
212 
213 	res = mpc85xx_lbc_resources;
214 
215 	regbuff = 0;
216 	unit = -1;
217 	for (; res->lbr_devtype; res++) {
218 		if (res->lbr_unit != dinfo->lbc_unit)
219 			continue;
220 
221 		start = res->lbr_base_addr;
222 		size = res->lbr_size;
223 		unit = res->lbr_unit;
224 
225 		/*
226 		 * Configure LAW for this LBC device and map its physical
227 		 * memory region into KVA
228 		 */
229 		error = law_enable(OCP85XX_TGTIF_LBC, start, size);
230 		if (error)
231 			return (error);
232 
233 		sc->sc_kva[unit] = (vm_offset_t)pmap_mapdev(start, size);
234 		if (sc->sc_kva[unit] == 0) {
235 			law_disable(OCP85XX_TGTIF_LBC, start, size);
236 			return (ENOSPC);
237 		}
238 
239 		/*
240 		 * Compute and program BR value
241 		 */
242 		regbuff |= start;
243 
244 		switch (res->lbr_port_size) {
245 		case 8:
246 			regbuff |= (1 << 11);
247 			break;
248 		case 16:
249 			regbuff |= (2 << 11);
250 			break;
251 		case 32:
252 			regbuff |= (3 << 11);
253 			break;
254 		default:
255 			error = EINVAL;
256 			goto fail;
257 		}
258 		regbuff |= (res->lbr_decc << 9);
259 		regbuff |= (res->lbr_wp << 8);
260 		regbuff |= (res->lbr_msel << 5);
261 		regbuff |= (res->lbr_atom << 2);
262 		regbuff |= 1;
263 
264 		lbc_write_reg(sc, LBC85XX_BR(unit), regbuff);
265 
266 		/*
267 		 * Compute and program OR value
268 		 */
269 		regbuff = 0;
270 		regbuff |= lbc_address_mask(size);
271 
272 		switch (res->lbr_msel) {
273 		case LBCRES_MSEL_GPCM:
274 			/* TODO Add flag support for option registers */
275 			regbuff |= 0x00000ff7;
276 			break;
277 		case LBCRES_MSEL_FCM:
278 			printf("FCM mode not supported yet!");
279 			error = ENOSYS;
280 			goto fail;
281 		case LBCRES_MSEL_UPMA:
282 		case LBCRES_MSEL_UPMB:
283 		case LBCRES_MSEL_UPMC:
284 			printf("UPM mode not supported yet!");
285 			error = ENOSYS;
286 			goto fail;
287 		}
288 
289 		lbc_write_reg(sc, LBC85XX_OR(unit), regbuff);
290 
291 		return (0);
292 	}
293 fail:
294 	if (unit != -1) {
295 		law_disable(OCP85XX_TGTIF_LBC, start, size);
296 		pmap_unmapdev(sc->sc_kva[unit], size);
297 		return (error);
298 	} else
299 		return (ENOENT);
300 }
301 
302 static int
303 lbc_probe(device_t dev)
304 {
305 	device_t parent;
306 	uintptr_t devtype;
307 	int error;
308 
309 	parent = device_get_parent(dev);
310 	error = BUS_READ_IVAR(parent, dev, OCPBUS_IVAR_DEVTYPE, &devtype);
311 	if (error)
312 		return (error);
313 	if (devtype != OCPBUS_DEVTYPE_LBC)
314 		return (ENXIO);
315 
316 	device_set_desc(dev, "Freescale MPC85xx Local Bus Controller");
317 	return (BUS_PROBE_DEFAULT);
318 }
319 
320 static int
321 lbc_attach(device_t dev)
322 {
323 	struct lbc_softc *sc;
324 	struct rman *rm;
325 	const struct lbc_resource *lbcres;
326 	int error;
327 
328 	sc = device_get_softc(dev);
329 	sc->sc_dev = dev;
330 
331 	sc->sc_rid = 0;
332 	sc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rid,
333 	    RF_ACTIVE);
334 	if (sc->sc_res == NULL)
335 		return (ENXIO);
336 
337 	sc->sc_bst = rman_get_bustag(sc->sc_res);
338 	sc->sc_bsh = rman_get_bushandle(sc->sc_res);
339 
340 	rm = &sc->sc_rman;
341 	rm->rm_type = RMAN_ARRAY;
342 	rm->rm_descr = "MPC85XX Local Bus Space";
343 	rm->rm_start = 0UL;
344 	rm->rm_end = ~0UL;
345 	error = rman_init(rm);
346 	if (error)
347 		goto fail;
348 
349 	error = rman_manage_region(rm, rm->rm_start, rm->rm_end);
350 	if (error) {
351 		rman_fini(rm);
352 		goto fail;
353 	}
354 
355 	/*
356 	 * Initialize configuration register:
357 	 * - enable Local Bus
358 	 * - set data buffer control signal function
359 	 * - disable parity byte select
360 	 * - set ECC parity type
361 	 * - set bus monitor timing and timer prescale
362 	 */
363 	lbc_write_reg(sc, LBC85XX_LBCR, 0x00000000);
364 
365 	/*
366 	 * Initialize clock ratio register:
367 	 * - disable PLL bypass mode
368 	 * - configure LCLK delay cycles for the assertion of LALE
369 	 * - set system clock divider
370 	 */
371 	lbc_write_reg(sc, LBC85XX_LCRR, 0x00030008);
372 
373 	lbcres = mpc85xx_lbc_resources;
374 
375 	for (; lbcres->lbr_devtype; lbcres++)
376 		if (!lbc_mk_child(dev, lbcres)) {
377 			error = ENXIO;
378 			goto fail;
379 		}
380 
381 	return (bus_generic_attach(dev));
382 
383 fail:
384 	bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rid, sc->sc_res);
385 	return (error);
386 }
387 
388 static int
389 lbc_shutdown(device_t dev)
390 {
391 
392 	/* TODO */
393 	return(0);
394 }
395 
396 static struct resource *
397 lbc_alloc_resource(device_t dev, device_t child, int type, int *rid,
398     u_long start, u_long end, u_long count, u_int flags)
399 {
400 	struct lbc_softc *sc;
401 	struct lbc_devinfo *dinfo;
402 	struct resource *rv;
403 	struct rman *rm;
404 	int error;
405 
406 	sc = device_get_softc(dev);
407 	dinfo = device_get_ivars(child);
408 
409 	if (type != SYS_RES_MEMORY && type != SYS_RES_IRQ)
410 		return (NULL);
411 
412 	/* We only support default allocations. */
413 	if (start != 0ul || end != ~0ul)
414 		return (NULL);
415 
416 	if (type == SYS_RES_IRQ)
417 		return (bus_alloc_resource(dev, type, rid, start, end, count,
418 		    flags));
419 
420 	if (!sc->sc_kva[dinfo->lbc_unit]) {
421 		error = lbc_init_child(dev, child);
422 		if (error)
423 			return (NULL);
424 	}
425 
426 	error = lbc_get_resource(dev, child, type, *rid, &start, &count);
427 	if (error)
428 		return (NULL);
429 
430 	rm = &sc->sc_rman;
431 	end = start + count - 1;
432 	rv = rman_reserve_resource(rm, start, end, count, flags, child);
433 	if (rv != NULL) {
434 		rman_set_bustag(rv, &bs_be_tag);
435 		rman_set_bushandle(rv, rman_get_start(rv));
436 	}
437 	return (rv);
438 }
439 
440 static int
441 lbc_print_child(device_t dev, device_t child)
442 {
443 	u_long size, start;
444 	int error, retval, rid;
445 
446 	retval = bus_print_child_header(dev, child);
447 
448 	rid = 0;
449 	while (1) {
450 		error = lbc_get_resource(dev, child, SYS_RES_MEMORY, rid,
451 		    &start, &size);
452 		if (error)
453 			break;
454 		retval += (rid == 0) ? printf(" iomem ") : printf(",");
455 		retval += printf("%#lx", start);
456 		if (size > 1)
457 			retval += printf("-%#lx", start + size - 1);
458 		rid++;
459 	}
460 
461 	retval += bus_print_child_footer(dev, child);
462 	return (retval);
463 }
464 
465 static int
466 lbc_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
467 {
468 	struct lbc_devinfo *dinfo;
469 
470 	if (device_get_parent(child) != dev)
471 		return (EINVAL);
472 
473 	dinfo = device_get_ivars(child);
474 
475 	switch (index) {
476 	case LBC_IVAR_DEVTYPE:
477 		*result = dinfo->lbc_devtype;
478 		return (0);
479 	default:
480 		break;
481 	}
482 	return (EINVAL);
483 }
484 
485 static int
486 lbc_release_resource(device_t dev, device_t child, int type, int rid,
487     struct resource *res)
488 {
489 
490 	return (rman_release_resource(res));
491 }
492 
493 static int
494 lbc_get_resource(device_t dev, device_t child, int type, int rid,
495     u_long *startp, u_long *countp)
496 {
497 	struct lbc_softc *sc;
498 	struct lbc_devinfo *dinfo;
499 	const struct lbc_resource *lbcres;
500 
501 	if (type != SYS_RES_MEMORY)
502 		return (ENOENT);
503 
504 	/* Currently all LBC devices have a single RID per type. */
505 	if (rid != 0)
506 		return (ENOENT);
507 
508 	sc = device_get_softc(dev);
509 	dinfo = device_get_ivars(child);
510 
511 	if ((dinfo->lbc_unit < 0) || (dinfo->lbc_unit > (LBC_DEV_MAX - 1)))
512 		return (EINVAL);
513 
514 	lbcres = mpc85xx_lbc_resources;
515 
516 	switch (dinfo->lbc_devtype) {
517 	case LBC_DEVTYPE_CFI:
518 	case LBC_DEVTYPE_RTC:
519 		for (; lbcres->lbr_devtype; lbcres++) {
520 			if (dinfo->lbc_unit == lbcres->lbr_unit) {
521 				*startp = sc->sc_kva[lbcres->lbr_unit];
522 				*countp = lbcres->lbr_size;
523 				return (0);
524 			}
525 		}
526 	default:
527 		return (EDOOFUS);
528 	}
529 	return (0);
530 }
531