2a3
> * Copyright (c) 2008 Semihalf, Rafal Czubak
30c31
< __FBSDID("$FreeBSD: head/sys/powerpc/mpc85xx/lbc.c 184250 2008-10-25 06:03:40Z marcel $");
---
> __FBSDID("$FreeBSD: head/sys/powerpc/mpc85xx/lbc.c 186288 2008-12-18 18:27:12Z raj $");
46a48,49
> #include <powerpc/mpc85xx/mpc85xx.h>
> #include <powerpc/mpc85xx/ocpbus.h>
57c60
< uintptr_t sc_kva;
---
> vm_offset_t sc_kva[LBC_DEV_MAX];
62,63c65
< int lbc_memtype;
< /* Also the BAR number */
---
> /* LBC child unit. It also represents resource table entry number */
66a69,94
> /* Resources for MPC8555CDS system */
> const struct lbc_resource mpc85xx_lbc_resources[] = {
> /* Boot flash bank */
> {
> LBC_DEVTYPE_CFI, 0, 0xff800000, 0x00800000, 16,
> LBCRES_MSEL_GPCM, LBCRES_DECC_DISABLED,
> LBCRES_ATOM_DISABLED, 0
> },
>
> /* Second flash bank */
> {
> LBC_DEVTYPE_CFI, 1, 0xff000000, 0x00800000, 16,
> LBCRES_MSEL_GPCM, LBCRES_DECC_DISABLED,
> LBCRES_ATOM_DISABLED, 0
> },
>
> /* DS1553 RTC/NVRAM */
> {
> LBC_DEVTYPE_RTC, 2, 0xf8000000, 0x8000, 8,
> LBCRES_MSEL_GPCM, LBCRES_DECC_DISABLED,
> LBCRES_ATOM_DISABLED, 0
> },
>
> {0}
> };
>
110a139,178
> static __inline void
> lbc_write_reg(struct lbc_softc *sc, bus_size_t off, uint32_t val)
> {
>
> bus_space_write_4(sc->sc_bst, sc->sc_bsh, off, val);
> }
>
> static __inline uint32_t
> lbc_read_reg(struct lbc_softc *sc, bus_size_t off)
> {
>
> return (bus_space_read_4(sc->sc_bst, sc->sc_bsh, off));
> }
>
> /*
> * Calculate address mask used by OR(n) registers. Use memory region size to
> * determine mask value. The size must be a power of two and within the range
> * of 32KB - 4GB. Otherwise error code is returned. Value representing
> * 4GB size can be passed as 0xffffffff.
> */
> static uint32_t
> lbc_address_mask(uint32_t size)
> {
> int n = 15;
>
> if (size == ~0UL)
> return (0);
>
> while (n < 32) {
> if (size == (1UL << n))
> break;
> n++;
> }
>
> if (n == 32)
> return (EINVAL);
>
> return (0xffff8000 << (n - 15));
> }
>
112c180
< lbc_mk_child(device_t dev, int type, int mtype, int unit)
---
> lbc_mk_child(device_t dev, const struct lbc_resource *lbcres)
116a185,187
> if (lbcres->lbr_unit > LBC_DEV_MAX - 1)
> return (NULL);
>
119c190
< device_printf(dev, "could not add child device\n");
---
> device_printf(dev, "could not add LBC child device\n");
123,125c194,195
< dinfo->lbc_devtype = type;
< dinfo->lbc_memtype = mtype;
< dinfo->lbc_unit = unit;
---
> dinfo->lbc_devtype = lbcres->lbr_devtype;
> dinfo->lbc_unit = lbcres->lbr_unit;
130a201,302
> lbc_init_child(device_t dev, device_t child)
> {
> struct lbc_softc *sc;
> struct lbc_devinfo *dinfo;
> const struct lbc_resource *res;
> u_long start, size;
> uint32_t regbuff;
> int error, unit;
>
> sc = device_get_softc(dev);
> dinfo = device_get_ivars(child);
>
> res = mpc85xx_lbc_resources;
>
> regbuff = 0;
> unit = -1;
> for (; res->lbr_devtype; res++) {
> if (res->lbr_unit != dinfo->lbc_unit)
> continue;
>
> start = res->lbr_base_addr;
> size = res->lbr_size;
> unit = res->lbr_unit;
>
> /*
> * Configure LAW for this LBC device and map its physical
> * memory region into KVA
> */
> error = law_enable(OCP85XX_TGTIF_LBC, start, size);
> if (error)
> return (error);
>
> sc->sc_kva[unit] = (vm_offset_t)pmap_mapdev(start, size);
> if (sc->sc_kva[unit] == 0) {
> law_disable(OCP85XX_TGTIF_LBC, start, size);
> return (ENOSPC);
> }
>
> /*
> * Compute and program BR value
> */
> regbuff |= start;
>
> switch (res->lbr_port_size) {
> case 8:
> regbuff |= (1 << 11);
> break;
> case 16:
> regbuff |= (2 << 11);
> break;
> case 32:
> regbuff |= (3 << 11);
> break;
> default:
> error = EINVAL;
> goto fail;
> }
> regbuff |= (res->lbr_decc << 9);
> regbuff |= (res->lbr_wp << 8);
> regbuff |= (res->lbr_msel << 5);
> regbuff |= (res->lbr_atom << 2);
> regbuff |= 1;
>
> lbc_write_reg(sc, LBC85XX_BR(unit), regbuff);
>
> /*
> * Compute and program OR value
> */
> regbuff = 0;
> regbuff |= lbc_address_mask(size);
>
> switch (res->lbr_msel) {
> case LBCRES_MSEL_GPCM:
> /* TODO Add flag support for option registers */
> regbuff |= 0x00000ff7;
> break;
> case LBCRES_MSEL_FCM:
> printf("FCM mode not supported yet!");
> error = ENOSYS;
> goto fail;
> case LBCRES_MSEL_UPMA:
> case LBCRES_MSEL_UPMB:
> case LBCRES_MSEL_UPMC:
> printf("UPM mode not supported yet!");
> error = ENOSYS;
> goto fail;
> }
>
> lbc_write_reg(sc, LBC85XX_OR(unit), regbuff);
>
> return (0);
> }
> fail:
> if (unit != -1) {
> law_disable(OCP85XX_TGTIF_LBC, start, size);
> pmap_unmapdev(sc->sc_kva[unit], size);
> return (error);
> } else
> return (ENOENT);
> }
>
> static int
153c325
< u_long start, size;
---
> const struct lbc_resource *lbcres;
168,171d339
< error = bus_get_resource(dev, SYS_RES_MEMORY, 1, &start, &size);
< if (error)
< goto fail;
<
175,176c343,344
< rm->rm_start = start;
< rm->rm_end = start + size - 1;
---
> rm->rm_start = 0UL;
> rm->rm_end = ~0UL;
187c355,363
< sc->sc_kva = (uintptr_t)pmap_mapdev(start, size);
---
> /*
> * Initialize configuration register:
> * - enable Local Bus
> * - set data buffer control signal function
> * - disable parity byte select
> * - set ECC parity type
> * - set bus monitor timing and timer prescale
> */
> lbc_write_reg(sc, LBC85XX_LBCR, 0x00000000);
189c365,371
< lbc_mk_child(dev, LBC_DEVTYPE_CFI, 0, 0);
---
> /*
> * Initialize clock ratio register:
> * - disable PLL bypass mode
> * - configure LCLK delay cycles for the assertion of LALE
> * - set system clock divider
> */
> lbc_write_reg(sc, LBC85XX_LCRR, 0x00030008);
190a373,380
> lbcres = mpc85xx_lbc_resources;
>
> for (; lbcres->lbr_devtype; lbcres++)
> if (!lbc_mk_child(dev, lbcres)) {
> error = ENXIO;
> goto fail;
> }
>
193c383
< fail:
---
> fail:
210a401
> struct lbc_devinfo *dinfo;
215a407
> dinfo = device_get_ivars(child);
227a420,425
> if (!sc->sc_kva[dinfo->lbc_unit]) {
> error = lbc_init_child(dev, child);
> if (error)
> return (NULL);
> }
>
237,238c435
< rman_set_bushandle(rv, sc->sc_kva + rman_get_start(rv) -
< rm->rm_start);
---
> rman_set_bushandle(rv, rman_get_start(rv));
282,287d478
< case LBC_IVAR_CLOCK:
< *result = 1843200;
< return (0);
< case LBC_IVAR_REGSHIFT:
< *result = 0;
< return (0);
307a499
> const struct lbc_resource *lbcres;
312c504
< /* Currently all devices have a single RID per type. */
---
> /* Currently all LBC devices have a single RID per type. */
318a511,515
> if ((dinfo->lbc_unit < 0) || (dinfo->lbc_unit > (LBC_DEV_MAX - 1)))
> return (EINVAL);
>
> lbcres = mpc85xx_lbc_resources;
>
321,323c518,525
< *startp = sc->sc_rman.rm_start;
< *countp = sc->sc_rman.rm_end - sc->sc_rman.rm_start + 1;
< break;
---
> case LBC_DEVTYPE_RTC:
> for (; lbcres->lbr_devtype; lbcres++) {
> if (dinfo->lbc_unit == lbcres->lbr_unit) {
> *startp = sc->sc_kva[lbcres->lbr_unit];
> *countp = lbcres->lbr_size;
> return (0);
> }
> }
325c527
< return(EDOOFUS);
---
> return (EDOOFUS);
327c529
< return(0);
---
> return (0);
> * Copyright (c) 2008 Semihalf, Rafal Czubak
30c31
< __FBSDID("$FreeBSD: head/sys/powerpc/mpc85xx/lbc.c 184250 2008-10-25 06:03:40Z marcel $");
---
> __FBSDID("$FreeBSD: head/sys/powerpc/mpc85xx/lbc.c 186288 2008-12-18 18:27:12Z raj $");
46a48,49
> #include <powerpc/mpc85xx/mpc85xx.h>
> #include <powerpc/mpc85xx/ocpbus.h>
57c60
< uintptr_t sc_kva;
---
> vm_offset_t sc_kva[LBC_DEV_MAX];
62,63c65
< int lbc_memtype;
< /* Also the BAR number */
---
> /* LBC child unit. It also represents resource table entry number */
66a69,94
> /* Resources for MPC8555CDS system */
> const struct lbc_resource mpc85xx_lbc_resources[] = {
> /* Boot flash bank */
> {
> LBC_DEVTYPE_CFI, 0, 0xff800000, 0x00800000, 16,
> LBCRES_MSEL_GPCM, LBCRES_DECC_DISABLED,
> LBCRES_ATOM_DISABLED, 0
> },
>
> /* Second flash bank */
> {
> LBC_DEVTYPE_CFI, 1, 0xff000000, 0x00800000, 16,
> LBCRES_MSEL_GPCM, LBCRES_DECC_DISABLED,
> LBCRES_ATOM_DISABLED, 0
> },
>
> /* DS1553 RTC/NVRAM */
> {
> LBC_DEVTYPE_RTC, 2, 0xf8000000, 0x8000, 8,
> LBCRES_MSEL_GPCM, LBCRES_DECC_DISABLED,
> LBCRES_ATOM_DISABLED, 0
> },
>
> {0}
> };
>
110a139,178
> static __inline void
> lbc_write_reg(struct lbc_softc *sc, bus_size_t off, uint32_t val)
> {
>
> bus_space_write_4(sc->sc_bst, sc->sc_bsh, off, val);
> }
>
> static __inline uint32_t
> lbc_read_reg(struct lbc_softc *sc, bus_size_t off)
> {
>
> return (bus_space_read_4(sc->sc_bst, sc->sc_bsh, off));
> }
>
> /*
> * Calculate address mask used by OR(n) registers. Use memory region size to
> * determine mask value. The size must be a power of two and within the range
> * of 32KB - 4GB. Otherwise error code is returned. Value representing
> * 4GB size can be passed as 0xffffffff.
> */
> static uint32_t
> lbc_address_mask(uint32_t size)
> {
> int n = 15;
>
> if (size == ~0UL)
> return (0);
>
> while (n < 32) {
> if (size == (1UL << n))
> break;
> n++;
> }
>
> if (n == 32)
> return (EINVAL);
>
> return (0xffff8000 << (n - 15));
> }
>
112c180
< lbc_mk_child(device_t dev, int type, int mtype, int unit)
---
> lbc_mk_child(device_t dev, const struct lbc_resource *lbcres)
116a185,187
> if (lbcres->lbr_unit > LBC_DEV_MAX - 1)
> return (NULL);
>
119c190
< device_printf(dev, "could not add child device\n");
---
> device_printf(dev, "could not add LBC child device\n");
123,125c194,195
< dinfo->lbc_devtype = type;
< dinfo->lbc_memtype = mtype;
< dinfo->lbc_unit = unit;
---
> dinfo->lbc_devtype = lbcres->lbr_devtype;
> dinfo->lbc_unit = lbcres->lbr_unit;
130a201,302
> lbc_init_child(device_t dev, device_t child)
> {
> struct lbc_softc *sc;
> struct lbc_devinfo *dinfo;
> const struct lbc_resource *res;
> u_long start, size;
> uint32_t regbuff;
> int error, unit;
>
> sc = device_get_softc(dev);
> dinfo = device_get_ivars(child);
>
> res = mpc85xx_lbc_resources;
>
> regbuff = 0;
> unit = -1;
> for (; res->lbr_devtype; res++) {
> if (res->lbr_unit != dinfo->lbc_unit)
> continue;
>
> start = res->lbr_base_addr;
> size = res->lbr_size;
> unit = res->lbr_unit;
>
> /*
> * Configure LAW for this LBC device and map its physical
> * memory region into KVA
> */
> error = law_enable(OCP85XX_TGTIF_LBC, start, size);
> if (error)
> return (error);
>
> sc->sc_kva[unit] = (vm_offset_t)pmap_mapdev(start, size);
> if (sc->sc_kva[unit] == 0) {
> law_disable(OCP85XX_TGTIF_LBC, start, size);
> return (ENOSPC);
> }
>
> /*
> * Compute and program BR value
> */
> regbuff |= start;
>
> switch (res->lbr_port_size) {
> case 8:
> regbuff |= (1 << 11);
> break;
> case 16:
> regbuff |= (2 << 11);
> break;
> case 32:
> regbuff |= (3 << 11);
> break;
> default:
> error = EINVAL;
> goto fail;
> }
> regbuff |= (res->lbr_decc << 9);
> regbuff |= (res->lbr_wp << 8);
> regbuff |= (res->lbr_msel << 5);
> regbuff |= (res->lbr_atom << 2);
> regbuff |= 1;
>
> lbc_write_reg(sc, LBC85XX_BR(unit), regbuff);
>
> /*
> * Compute and program OR value
> */
> regbuff = 0;
> regbuff |= lbc_address_mask(size);
>
> switch (res->lbr_msel) {
> case LBCRES_MSEL_GPCM:
> /* TODO Add flag support for option registers */
> regbuff |= 0x00000ff7;
> break;
> case LBCRES_MSEL_FCM:
> printf("FCM mode not supported yet!");
> error = ENOSYS;
> goto fail;
> case LBCRES_MSEL_UPMA:
> case LBCRES_MSEL_UPMB:
> case LBCRES_MSEL_UPMC:
> printf("UPM mode not supported yet!");
> error = ENOSYS;
> goto fail;
> }
>
> lbc_write_reg(sc, LBC85XX_OR(unit), regbuff);
>
> return (0);
> }
> fail:
> if (unit != -1) {
> law_disable(OCP85XX_TGTIF_LBC, start, size);
> pmap_unmapdev(sc->sc_kva[unit], size);
> return (error);
> } else
> return (ENOENT);
> }
>
> static int
153c325
< u_long start, size;
---
> const struct lbc_resource *lbcres;
168,171d339
< error = bus_get_resource(dev, SYS_RES_MEMORY, 1, &start, &size);
< if (error)
< goto fail;
<
175,176c343,344
< rm->rm_start = start;
< rm->rm_end = start + size - 1;
---
> rm->rm_start = 0UL;
> rm->rm_end = ~0UL;
187c355,363
< sc->sc_kva = (uintptr_t)pmap_mapdev(start, size);
---
> /*
> * Initialize configuration register:
> * - enable Local Bus
> * - set data buffer control signal function
> * - disable parity byte select
> * - set ECC parity type
> * - set bus monitor timing and timer prescale
> */
> lbc_write_reg(sc, LBC85XX_LBCR, 0x00000000);
189c365,371
< lbc_mk_child(dev, LBC_DEVTYPE_CFI, 0, 0);
---
> /*
> * Initialize clock ratio register:
> * - disable PLL bypass mode
> * - configure LCLK delay cycles for the assertion of LALE
> * - set system clock divider
> */
> lbc_write_reg(sc, LBC85XX_LCRR, 0x00030008);
190a373,380
> lbcres = mpc85xx_lbc_resources;
>
> for (; lbcres->lbr_devtype; lbcres++)
> if (!lbc_mk_child(dev, lbcres)) {
> error = ENXIO;
> goto fail;
> }
>
193c383
< fail:
---
> fail:
210a401
> struct lbc_devinfo *dinfo;
215a407
> dinfo = device_get_ivars(child);
227a420,425
> if (!sc->sc_kva[dinfo->lbc_unit]) {
> error = lbc_init_child(dev, child);
> if (error)
> return (NULL);
> }
>
237,238c435
< rman_set_bushandle(rv, sc->sc_kva + rman_get_start(rv) -
< rm->rm_start);
---
> rman_set_bushandle(rv, rman_get_start(rv));
282,287d478
< case LBC_IVAR_CLOCK:
< *result = 1843200;
< return (0);
< case LBC_IVAR_REGSHIFT:
< *result = 0;
< return (0);
307a499
> const struct lbc_resource *lbcres;
312c504
< /* Currently all devices have a single RID per type. */
---
> /* Currently all LBC devices have a single RID per type. */
318a511,515
> if ((dinfo->lbc_unit < 0) || (dinfo->lbc_unit > (LBC_DEV_MAX - 1)))
> return (EINVAL);
>
> lbcres = mpc85xx_lbc_resources;
>
321,323c518,525
< *startp = sc->sc_rman.rm_start;
< *countp = sc->sc_rman.rm_end - sc->sc_rman.rm_start + 1;
< break;
---
> case LBC_DEVTYPE_RTC:
> for (; lbcres->lbr_devtype; lbcres++) {
> if (dinfo->lbc_unit == lbcres->lbr_unit) {
> *startp = sc->sc_kva[lbcres->lbr_unit];
> *countp = lbcres->lbr_size;
> return (0);
> }
> }
325c527
< return(EDOOFUS);
---
> return (EDOOFUS);
327c529
< return(0);
---
> return (0);