Deleted Added
full compact
lbc.c (184250) lbc.c (186288)
1/*-
2 * Copyright (c) 2006-2008, Juniper Networks, Inc.
1/*-
2 * Copyright (c) 2006-2008, Juniper Networks, Inc.
3 * Copyright (c) 2008 Semihalf, Rafal Czubak
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright

--- 11 unchanged lines hidden (view full) ---

22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
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

--- 11 unchanged lines hidden (view full) ---

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>
30__FBSDID("$FreeBSD: head/sys/powerpc/mpc85xx/lbc.c 184250 2008-10-25 06:03:40Z marcel $");
31__FBSDID("$FreeBSD: head/sys/powerpc/mpc85xx/lbc.c 186288 2008-12-18 18:27:12Z raj $");
31
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/ktr.h>
35#include <sys/kernel.h>
36#include <sys/malloc.h>
37#include <sys/module.h>
38#include <sys/bus.h>
39#include <sys/rman.h>
40#include <machine/bus.h>
41#include <machine/ocpbus.h>
42
43#include <vm/vm.h>
44#include <vm/pmap.h>
45
46#include <powerpc/mpc85xx/lbc.h>
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>
47
48struct lbc_softc {
49 device_t sc_dev;
50
51 struct resource *sc_res;
52 bus_space_handle_t sc_bsh;
53 bus_space_tag_t sc_bst;
54 int sc_rid;
55
56 struct rman sc_rman;
50
51struct 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;
57 uintptr_t sc_kva;
60 vm_offset_t sc_kva[LBC_DEV_MAX];
58};
59
60struct lbc_devinfo {
61 int lbc_devtype;
61};
62
63struct lbc_devinfo {
64 int lbc_devtype;
62 int lbc_memtype;
63 /* Also the BAR number */
65 /* LBC child unit. It also represents resource table entry number */
64 int lbc_unit;
65};
66
66 int lbc_unit;
67};
68
69/* Resources for MPC8555CDS system */
70const 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
67static int lbc_probe(device_t);
68static int lbc_attach(device_t);
69static int lbc_shutdown(device_t);
70static int lbc_get_resource(device_t, device_t, int, int, u_long *,
71 u_long *);
72static struct resource *lbc_alloc_resource(device_t, device_t, int, int *,
73 u_long, u_long, u_long, u_int);
74static int lbc_print_child(device_t, device_t);

--- 28 unchanged lines hidden (view full) ---

103static driver_t lbc_driver = {
104 "lbc",
105 lbc_methods,
106 sizeof(struct lbc_softc)
107};
108devclass_t lbc_devclass;
109DRIVER_MODULE(lbc, ocpbus, lbc_driver, lbc_devclass, 0, 0);
110
95static int lbc_probe(device_t);
96static int lbc_attach(device_t);
97static int lbc_shutdown(device_t);
98static int lbc_get_resource(device_t, device_t, int, int, u_long *,
99 u_long *);
100static struct resource *lbc_alloc_resource(device_t, device_t, int, int *,
101 u_long, u_long, u_long, u_int);
102static int lbc_print_child(device_t, device_t);

--- 28 unchanged lines hidden (view full) ---

131static driver_t lbc_driver = {
132 "lbc",
133 lbc_methods,
134 sizeof(struct lbc_softc)
135};
136devclass_t lbc_devclass;
137DRIVER_MODULE(lbc, ocpbus, lbc_driver, lbc_devclass, 0, 0);
138
139static __inline void
140lbc_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
146static __inline uint32_t
147lbc_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 */
159static uint32_t
160lbc_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
111static device_t
179static device_t
112lbc_mk_child(device_t dev, int type, int mtype, int unit)
180lbc_mk_child(device_t dev, const struct lbc_resource *lbcres)
113{
114 struct lbc_devinfo *dinfo;
115 device_t child;
116
181{
182 struct lbc_devinfo *dinfo;
183 device_t child;
184
185 if (lbcres->lbr_unit > LBC_DEV_MAX - 1)
186 return (NULL);
187
117 child = device_add_child(dev, NULL, -1);
118 if (child == NULL) {
188 child = device_add_child(dev, NULL, -1);
189 if (child == NULL) {
119 device_printf(dev, "could not add child device\n");
190 device_printf(dev, "could not add LBC child device\n");
120 return (NULL);
121 }
122 dinfo = malloc(sizeof(struct lbc_devinfo), M_DEVBUF, M_WAITOK | M_ZERO);
191 return (NULL);
192 }
193 dinfo = malloc(sizeof(struct lbc_devinfo), M_DEVBUF, M_WAITOK | M_ZERO);
123 dinfo->lbc_devtype = type;
124 dinfo->lbc_memtype = mtype;
125 dinfo->lbc_unit = unit;
194 dinfo->lbc_devtype = lbcres->lbr_devtype;
195 dinfo->lbc_unit = lbcres->lbr_unit;
126 device_set_ivars(child, dinfo);
127 return (child);
128}
129
130static int
196 device_set_ivars(child, dinfo);
197 return (child);
198}
199
200static int
201lbc_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 }
293fail:
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
302static int
131lbc_probe(device_t dev)
132{
133 device_t parent;
134 uintptr_t devtype;
135 int error;
136
137 parent = device_get_parent(dev);
138 error = BUS_READ_IVAR(parent, dev, OCPBUS_IVAR_DEVTYPE, &devtype);

--- 6 unchanged lines hidden (view full) ---

145 return (BUS_PROBE_DEFAULT);
146}
147
148static int
149lbc_attach(device_t dev)
150{
151 struct lbc_softc *sc;
152 struct rman *rm;
303lbc_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);

--- 6 unchanged lines hidden (view full) ---

317 return (BUS_PROBE_DEFAULT);
318}
319
320static int
321lbc_attach(device_t dev)
322{
323 struct lbc_softc *sc;
324 struct rman *rm;
153 u_long start, size;
325 const struct lbc_resource *lbcres;
154 int error;
155
156 sc = device_get_softc(dev);
157 sc->sc_dev = dev;
158
159 sc->sc_rid = 0;
160 sc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rid,
161 RF_ACTIVE);
162 if (sc->sc_res == NULL)
163 return (ENXIO);
164
165 sc->sc_bst = rman_get_bustag(sc->sc_res);
166 sc->sc_bsh = rman_get_bushandle(sc->sc_res);
167
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
168 error = bus_get_resource(dev, SYS_RES_MEMORY, 1, &start, &size);
169 if (error)
170 goto fail;
171
172 rm = &sc->sc_rman;
173 rm->rm_type = RMAN_ARRAY;
174 rm->rm_descr = "MPC85XX Local Bus Space";
340 rm = &sc->sc_rman;
341 rm->rm_type = RMAN_ARRAY;
342 rm->rm_descr = "MPC85XX Local Bus Space";
175 rm->rm_start = start;
176 rm->rm_end = start + size - 1;
343 rm->rm_start = 0UL;
344 rm->rm_end = ~0UL;
177 error = rman_init(rm);
178 if (error)
179 goto fail;
180
181 error = rman_manage_region(rm, rm->rm_start, rm->rm_end);
182 if (error) {
183 rman_fini(rm);
184 goto fail;
185 }
186
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
187 sc->sc_kva = (uintptr_t)pmap_mapdev(start, size);
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);
188
364
189 lbc_mk_child(dev, LBC_DEVTYPE_CFI, 0, 0);
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);
190
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
191 return (bus_generic_attach(dev));
192
381 return (bus_generic_attach(dev));
382
193 fail:
383fail:
194 bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rid, sc->sc_res);
195 return (error);
196}
197
198static int
199lbc_shutdown(device_t dev)
200{
201
202 /* TODO */
203 return(0);
204}
205
206static struct resource *
207lbc_alloc_resource(device_t dev, device_t child, int type, int *rid,
208 u_long start, u_long end, u_long count, u_int flags)
209{
210 struct lbc_softc *sc;
384 bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rid, sc->sc_res);
385 return (error);
386}
387
388static int
389lbc_shutdown(device_t dev)
390{
391
392 /* TODO */
393 return(0);
394}
395
396static struct resource *
397lbc_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;
211 struct resource *rv;
212 struct rman *rm;
213 int error;
214
215 sc = device_get_softc(dev);
402 struct resource *rv;
403 struct rman *rm;
404 int error;
405
406 sc = device_get_softc(dev);
407 dinfo = device_get_ivars(child);
216
217 if (type != SYS_RES_MEMORY && type != SYS_RES_IRQ)
218 return (NULL);
219
220 /* We only support default allocations. */
221 if (start != 0ul || end != ~0ul)
222 return (NULL);
223
224 if (type == SYS_RES_IRQ)
225 return (bus_alloc_resource(dev, type, rid, start, end, count,
226 flags));
227
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
228 error = lbc_get_resource(dev, child, type, *rid, &start, &count);
229 if (error)
230 return (NULL);
231
232 rm = &sc->sc_rman;
233 end = start + count - 1;
234 rv = rman_reserve_resource(rm, start, end, count, flags, child);
235 if (rv != NULL) {
236 rman_set_bustag(rv, &bs_be_tag);
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);
237 rman_set_bushandle(rv, sc->sc_kva + rman_get_start(rv) -
238 rm->rm_start);
435 rman_set_bushandle(rv, rman_get_start(rv));
239 }
240 return (rv);
241}
242
243static int
244lbc_print_child(device_t dev, device_t child)
245{
246 u_long size, start;

--- 27 unchanged lines hidden (view full) ---

274 return (EINVAL);
275
276 dinfo = device_get_ivars(child);
277
278 switch (index) {
279 case LBC_IVAR_DEVTYPE:
280 *result = dinfo->lbc_devtype;
281 return (0);
436 }
437 return (rv);
438}
439
440static int
441lbc_print_child(device_t dev, device_t child)
442{
443 u_long size, start;

--- 27 unchanged lines hidden (view full) ---

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);
282 case LBC_IVAR_CLOCK:
283 *result = 1843200;
284 return (0);
285 case LBC_IVAR_REGSHIFT:
286 *result = 0;
287 return (0);
288 default:
289 break;
290 }
291 return (EINVAL);
292}
293
294static int
295lbc_release_resource(device_t dev, device_t child, int type, int rid,

--- 4 unchanged lines hidden (view full) ---

300}
301
302static int
303lbc_get_resource(device_t dev, device_t child, int type, int rid,
304 u_long *startp, u_long *countp)
305{
306 struct lbc_softc *sc;
307 struct lbc_devinfo *dinfo;
479 default:
480 break;
481 }
482 return (EINVAL);
483}
484
485static int
486lbc_release_resource(device_t dev, device_t child, int type, int rid,

--- 4 unchanged lines hidden (view full) ---

491}
492
493static int
494lbc_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;
308
309 if (type != SYS_RES_MEMORY)
310 return (ENOENT);
311
500
501 if (type != SYS_RES_MEMORY)
502 return (ENOENT);
503
312 /* Currently all devices have a single RID per type. */
504 /* Currently all LBC devices have a single RID per type. */
313 if (rid != 0)
314 return (ENOENT);
315
316 sc = device_get_softc(dev);
317 dinfo = device_get_ivars(child);
318
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
319 switch (dinfo->lbc_devtype) {
320 case LBC_DEVTYPE_CFI:
516 switch (dinfo->lbc_devtype) {
517 case LBC_DEVTYPE_CFI:
321 *startp = sc->sc_rman.rm_start;
322 *countp = sc->sc_rman.rm_end - sc->sc_rman.rm_start + 1;
323 break;
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 }
324 default:
526 default:
325 return(EDOOFUS);
527 return (EDOOFUS);
326 }
528 }
327 return(0);
529 return (0);
328}
530}