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 **)®); 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} |