Deleted Added
full compact
lbc.c (186288) lbc.c (209908)
1/*-
2 * Copyright (c) 2006-2008, Juniper Networks, Inc.
3 * Copyright (c) 2008 Semihalf, Rafal Czubak
1/*-
2 * Copyright (c) 2006-2008, Juniper Networks, Inc.
3 * Copyright (c) 2008 Semihalf, Rafal Czubak
4 * Copyright (c) 2009 The FreeBSD Foundation
4 * All rights reserved.
5 *
5 * All rights reserved.
6 *
7 * Portions of this software were developed by Semihalf
8 * under sponsorship from the FreeBSD Foundation.
9 *
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.

--- 9 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>
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.

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

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>
31__FBSDID("$FreeBSD: head/sys/powerpc/mpc85xx/lbc.c 186288 2008-12-18 18:27:12Z raj $");
35__FBSDID("$FreeBSD: head/sys/powerpc/mpc85xx/lbc.c 209908 2010-07-11 21:08:29Z raj $");
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>
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>
42#include <machine/ocpbus.h>
43
44#include <vm/vm.h>
45#include <vm/pmap.h>
46
46
47#include <vm/vm.h>
48#include <vm/pmap.h>
49
47#include <powerpc/mpc85xx/lbc.h>
50#include <dev/fdt/fdt_common.h>
51#include <dev/ofw/ofw_bus.h>
52#include <dev/ofw/ofw_bus_subr.h>
53
48#include <powerpc/mpc85xx/mpc85xx.h>
54#include <powerpc/mpc85xx/mpc85xx.h>
49#include <powerpc/mpc85xx/ocpbus.h>
50
55
51struct lbc_softc {
52 device_t sc_dev;
56#include "ofw_bus_if.h"
57#include "lbc.h"
53
58
54 struct resource *sc_res;
55 bus_space_handle_t sc_bsh;
56 bus_space_tag_t sc_bst;
57 int sc_rid;
59#define DEBUG
60#undef DEBUG
58
61
59 struct rman sc_rman;
60 vm_offset_t sc_kva[LBC_DEV_MAX];
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
62
68
63struct lbc_devinfo {
64 int lbc_devtype;
65 /* LBC child unit. It also represents resource table entry number */
66 int lbc_unit;
67};
69static __inline void
70lbc_write_reg(struct lbc_softc *sc, bus_size_t off, uint32_t val)
71{
68
72
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 },
73 bus_space_write_4(sc->sc_bst, sc->sc_bsh, off, val);
74}
77
75
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 },
76static __inline uint32_t
77lbc_read_reg(struct lbc_softc *sc, bus_size_t off)
78{
84
79
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 },
80 return (bus_space_read_4(sc->sc_bst, sc->sc_bsh, off));
81}
91
82
92 {0}
93};
83static MALLOC_DEFINE(M_LBC, "localbus", "localbus devices information");
94
95static int lbc_probe(device_t);
96static int lbc_attach(device_t);
97static int lbc_shutdown(device_t);
84
85static int lbc_probe(device_t);
86static int lbc_attach(device_t);
87static 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);
103static int lbc_release_resource(device_t, device_t, int, int,
104 struct resource *);
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 *);
105static int lbc_read_ivar(device_t, device_t, int, uintptr_t *);
93static const struct ofw_bus_devinfo *lbc_get_devinfo(device_t, device_t);
106
107/*
108 * Bus interface definition
109 */
110static 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),
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),
118 DEVMETHOD(bus_read_ivar, lbc_read_ivar),
119 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
120 DEVMETHOD(bus_teardown_intr, NULL),
121
106 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
107 DEVMETHOD(bus_teardown_intr, NULL),
108
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
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
128 { 0, 0 }
129};
130
131static driver_t lbc_driver = {
132 "lbc",
133 lbc_methods,
134 sizeof(struct lbc_softc)
135};
122 { 0, 0 }
123};
124
125static driver_t lbc_driver = {
126 "lbc",
127 lbc_methods,
128 sizeof(struct lbc_softc)
129};
130
136devclass_t lbc_devclass;
131devclass_t lbc_devclass;
137DRIVER_MODULE(lbc, ocpbus, lbc_driver, lbc_devclass, 0, 0);
138
132
139static __inline void
140lbc_write_reg(struct lbc_softc *sc, bus_size_t off, uint32_t val)
141{
133DRIVER_MODULE(lbc, fdtbus, lbc_driver, lbc_devclass, 0, 0);
142
134
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)

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

171 }
172
173 if (n == 32)
174 return (EINVAL);
175
176 return (0xffff8000 << (n - 15));
177}
178
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)

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

153 }
154
155 if (n == 32)
156 return (EINVAL);
157
158 return (0xffff8000 << (n - 15));
159}
160
179static device_t
180lbc_mk_child(device_t dev, const struct lbc_resource *lbcres)
161static void
162lbc_banks_unmap(struct lbc_softc *sc)
181{
163{
182 struct lbc_devinfo *dinfo;
183 device_t child;
164 int i;
184
165
185 if (lbcres->lbr_unit > LBC_DEV_MAX - 1)
186 return (NULL);
166 for (i = 0; i < LBC_DEV_MAX; i++) {
167 if (sc->sc_banks[i].size == 0)
168 continue;
187
169
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);
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);
192 }
173 }
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
200static int
174}
175
176static int
201lbc_init_child(device_t dev, device_t child)
177lbc_banks_map(struct lbc_softc *sc)
202{
178{
203 struct lbc_softc *sc;
204 struct lbc_devinfo *dinfo;
205 const struct lbc_resource *res;
206 u_long start, size;
179 u_long start, size;
207 uint32_t regbuff;
208 int error, unit;
180 int error, i;
209
181
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)
182 for (i = 0; i < LBC_DEV_MAX; i++) {
183 if (sc->sc_banks[i].size == 0)
219 continue;
220
184 continue;
185
221 start = res->lbr_base_addr;
222 size = res->lbr_size;
223 unit = res->lbr_unit;
186 /* Physical address start/size. */
187 start = sc->sc_banks[i].pa;
188 size = sc->sc_banks[i].size;
224
225 /*
189
190 /*
226 * Configure LAW for this LBC device and map its physical
227 * memory region into KVA
191 * Configure LAW for this LBC bank (CS) and map its physical
192 * memory region into KVA.
228 */
229 error = law_enable(OCP85XX_TGTIF_LBC, start, size);
230 if (error)
231 return (error);
232
193 */
194 error = law_enable(OCP85XX_TGTIF_LBC, start, size);
195 if (error)
196 return (error);
197
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);
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);
236 return (ENOSPC);
237 }
201 return (ENOSPC);
202 }
203 }
204 return (0);
205}
238
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;
239 /*
218 /*
240 * Compute and program BR value
219 * Compute and program BR value.
241 */
220 */
242 regbuff |= start;
221 regval = 0;
222 regval |= sc->sc_banks[i].pa;
243
223
244 switch (res->lbr_port_size) {
224 switch (sc->sc_banks[i].width) {
245 case 8:
225 case 8:
246 regbuff |= (1 << 11);
226 regval |= (1 << 11);
247 break;
248 case 16:
227 break;
228 case 16:
249 regbuff |= (2 << 11);
229 regval |= (2 << 11);
250 break;
251 case 32:
230 break;
231 case 32:
252 regbuff |= (3 << 11);
232 regval |= (3 << 11);
253 break;
254 default:
255 error = EINVAL;
256 goto fail;
257 }
233 break;
234 default:
235 error = EINVAL;
236 goto fail;
237 }
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;
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;
263
243
264 lbc_write_reg(sc, LBC85XX_BR(unit), regbuff);
244 lbc_write_reg(sc, LBC85XX_BR(i), regval);
265
266 /*
245
246 /*
267 * Compute and program OR value
247 * Compute and program OR value.
268 */
248 */
269 regbuff = 0;
270 regbuff |= lbc_address_mask(size);
249 regval = 0;
250 regval |= lbc_address_mask(size);
271
251
272 switch (res->lbr_msel) {
252 switch (sc->sc_banks[i].msel) {
273 case LBCRES_MSEL_GPCM:
274 /* TODO Add flag support for option registers */
253 case LBCRES_MSEL_GPCM:
254 /* TODO Add flag support for option registers */
275 regbuff |= 0x00000ff7;
255 regval |= 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 }
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 }
288
270
289 lbc_write_reg(sc, LBC85XX_OR(unit), regbuff);
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);
290
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. */
291 return (0);
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);
292 }
360 }
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);
361 rv = 0;
362out:
363 free(regptr, M_OFWPROP);
364 return (rv);
300}
301
302static int
303lbc_probe(device_t dev)
304{
365}
366
367static int
368lbc_probe(device_t dev)
369{
305 device_t parent;
306 uintptr_t devtype;
307 int error;
308
370
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)
371 if (!(ofw_bus_is_compatible(dev, "fsl,lbc") ||
372 ofw_bus_is_compatible(dev, "fsl,elbc")))
314 return (ENXIO);
315
373 return (ENXIO);
374
316 device_set_desc(dev, "Freescale MPC85xx Local Bus Controller");
375 device_set_desc(dev, "Freescale Local Bus Controller");
317 return (BUS_PROBE_DEFAULT);
318}
319
320static int
321lbc_attach(device_t dev)
322{
323 struct lbc_softc *sc;
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;
324 struct rman *rm;
384 struct rman *rm;
325 const struct lbc_resource *lbcres;
326 int error;
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;
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);
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;
339
340 rm = &sc->sc_rman;
341 rm->rm_type = RMAN_ARRAY;
405
406 rm = &sc->sc_rman;
407 rm->rm_type = RMAN_ARRAY;
342 rm->rm_descr = "MPC85XX Local Bus Space";
408 rm->rm_descr = "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 /*
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 /*
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
422 * Process 'ranges' property.
362 */
423 */
363 lbc_write_reg(sc, LBC85XX_LBCR, 0x00000000);
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 }
364
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
365 /*
498 /*
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
499 * Initialize mem-mappings for the LBC banks (i.e. chip selects).
370 */
500 */
371 lbc_write_reg(sc, LBC85XX_LCRR, 0x00030008);
501 error = lbc_banks_map(sc);
502 if (error)
503 goto fail;
372
504
373 lbcres = mpc85xx_lbc_resources;
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)) {
374
509
375 for (; lbcres->lbr_devtype; lbcres++)
376 if (!lbc_mk_child(dev, lbcres)) {
377 error = ENXIO;
378 goto fail;
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;
379 }
380
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);
381 return (bus_generic_attach(dev));
382
383fail:
551 return (bus_generic_attach(dev));
552
553fail:
554 free(rangesptr, M_OFWPROP);
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 *
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 *
397lbc_alloc_resource(device_t dev, device_t child, int type, int *rid,
568lbc_alloc_resource(device_t bus, 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;
569 u_long start, u_long end, u_long count, u_int flags)
570{
571 struct lbc_softc *sc;
401 struct lbc_devinfo *dinfo;
402 struct resource *rv;
572 struct lbc_devinfo *di;
573 struct resource_list_entry *rle;
574 struct resource *res;
403 struct rman *rm;
575 struct rman *rm;
404 int error;
576 int needactivate;
405
577
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
578 /* We only support default allocations. */
579 if (start != 0ul || end != ~0ul)
580 return (NULL);
581
582 sc = device_get_softc(bus);
416 if (type == SYS_RES_IRQ)
583 if (type == SYS_RES_IRQ)
417 return (bus_alloc_resource(dev, type, rid, start, end, count,
584 return (bus_alloc_resource(bus, type, rid, start, end, count,
418 flags));
419
585 flags));
586
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)
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)
428 return (NULL);
429
592 return (NULL);
593
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));
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);
436 }
604 }
437 return (rv);
438}
605 start = rle->start;
606 count = rle->count;
607 end = start + count - 1;
439
608
440static int
441lbc_print_child(device_t dev, device_t child)
442{
443 u_long size, start;
444 int error, retval, rid;
609 sc = device_get_softc(bus);
445
610
446 retval = bus_print_child_header(dev, child);
611 needactivate = flags & RF_ACTIVE;
612 flags &= ~RF_ACTIVE;
447
613
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++;
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);
459 }
460
621 }
622
461 retval += bus_print_child_footer(dev, child);
462 return (retval);
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);
463}
464
465static int
635}
636
637static int
466lbc_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
638lbc_print_child(device_t dev, device_t child)
467{
639{
468 struct lbc_devinfo *dinfo;
640 struct lbc_devinfo *di;
641 struct resource_list *rl;
642 int rv;
469
643
470 if (device_get_parent(child) != dev)
471 return (EINVAL);
644 di = device_get_ivars(child);
645 rl = &di->di_res;
472
646
473 dinfo = device_get_ivars(child);
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);
474
652
475 switch (index) {
476 case LBC_IVAR_DEVTYPE:
477 *result = dinfo->lbc_devtype;
478 return (0);
479 default:
480 break;
481 }
482 return (EINVAL);
653 return (rv);
483}
484
485static int
486lbc_release_resource(device_t dev, device_t child, int type, int rid,
487 struct resource *res)
488{
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;
489
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
490 return (rman_release_resource(res));
491}
492
668 return (rman_release_resource(res));
669}
670
493static int
494lbc_get_resource(device_t dev, device_t child, int type, int rid,
495 u_long *startp, u_long *countp)
671static const struct ofw_bus_devinfo *
672lbc_get_devinfo(device_t bus, device_t child)
496{
673{
497 struct lbc_softc *sc;
498 struct lbc_devinfo *dinfo;
499 const struct lbc_resource *lbcres;
674 struct lbc_devinfo *di;
500
675
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);
676 di = device_get_ivars(child);
677 return (&di->di_ofw);
530}
678}