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. 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>
| 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#include <sys/cdefs.h>
|
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) 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
| 135/* 136 * Calculate address mask used by OR(n) registers. Use memory region size to 137 * determine mask value. The size must be a power of two and within the range 138 * of 32KB - 4GB. Otherwise error code is returned. Value representing 139 * 4GB size can be passed as 0xffffffff. 140 */ 141static uint32_t 142lbc_address_mask(uint32_t size) 143{ 144 int n = 15; 145 146 if (size == ~0UL) 147 return (0); 148 149 while (n < 32) { 150 if (size == (1UL << n)) 151 break; 152 n++; 153 } 154 155 if (n == 32) 156 return (EINVAL); 157 158 return (0xffff8000 << (n - 15)); 159} 160
|
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}
|