From 9d4753ed16c144e682520b2681c7a13d70018387 Mon Sep 17 00:00:00 2001 From: weongyo Date: Sun, 31 Jan 2010 21:18:22 +0000 Subject: Adds siba_bwn module which is used with bwn(4). Main purpose of this module is to distinguish parts of Silicon Backplane and of Broadcom Wireless. --- sys/dev/siba/siba.c | 106 +-- sys/dev/siba/siba_bwn.c | 366 ++++++++ sys/dev/siba/siba_cc.c | 4 +- sys/dev/siba/siba_core.c | 2007 +++++++++++++++++++++++++++++++++++++++++ sys/dev/siba/siba_ids.h | 48 +- sys/dev/siba/siba_pcib.c | 19 +- sys/dev/siba/sibareg.h | 403 ++++++++- sys/dev/siba/sibavar.h | 357 +++++++- sys/modules/siba_bwn/Makefile | 9 + 9 files changed, 3162 insertions(+), 157 deletions(-) create mode 100644 sys/dev/siba/siba_bwn.c create mode 100644 sys/dev/siba/siba_core.c create mode 100644 sys/modules/siba_bwn/Makefile diff --git a/sys/dev/siba/siba.c b/sys/dev/siba/siba.c index 04a5309..541585b 100644 --- a/sys/dev/siba/siba.c +++ b/sys/dev/siba/siba.c @@ -37,9 +37,9 @@ __FBSDID("$FreeBSD$"); #include -#include -#include #include +#include +#include /* * TODO: De-mipsify this code. @@ -77,7 +77,7 @@ static struct siba_devid siba_devids[] = { "MIPS core" }, { SIBA_VID_BROADCOM, SIBA_DEVID_ETHERNET, SIBA_REV_ANY, "Ethernet core" }, - { SIBA_VID_BROADCOM, SIBA_DEVID_USB, SIBA_REV_ANY, + { SIBA_VID_BROADCOM, SIBA_DEVID_USB11_HOSTDEV, SIBA_REV_ANY, "USB host controller" }, { SIBA_VID_BROADCOM, SIBA_DEVID_IPSEC, SIBA_REV_ANY, "IPSEC accelerator" }, @@ -103,7 +103,6 @@ static struct siba_devid * static struct resource_list * siba_get_reslist(device_t, device_t); static uint8_t siba_getirq(uint16_t); -static uint8_t siba_getncores(uint16_t); static int siba_print_all_resources(device_t dev); static int siba_print_child(device_t, device_t); static int siba_probe(device_t); @@ -112,30 +111,7 @@ int siba_read_ivar(device_t, device_t, int, uintptr_t *); static struct siba_devinfo * siba_setup_devinfo(device_t, uint8_t); int siba_write_ivar(device_t, device_t, int, uintptr_t); - -/* - * Earlier ChipCommon revisions have hardcoded number of cores - * present dependent on the ChipCommon ID. - */ -static uint8_t -siba_getncores(uint16_t ccid) -{ - uint8_t ncores; - - switch (ccid) { - case SIBA_CCID_SENTRY5: - ncores = 7; - break; - case SIBA_CCID_BCM4710: - case SIBA_CCID_BCM4704: - ncores = 9; - break; - default: - ncores = 0; - } - - return (ncores); -} +uint8_t siba_getncores(device_t, uint16_t); /* * On the Sentry5, the system bus IRQs are the same as the @@ -156,7 +132,7 @@ siba_getirq(uint16_t devid) case SIBA_DEVID_IPSEC: irq = 2; break; - case SIBA_DEVID_USB: + case SIBA_DEVID_USB11_HOSTDEV: irq = 3; break; case SIBA_DEVID_PCI: @@ -188,7 +164,7 @@ siba_probe(device_t dev) uint16_t ccid; int rid; - sc->sc_dev = dev; + sc->siba_dev = dev; //rman_debug = 1; /* XXX */ @@ -197,24 +173,24 @@ siba_probe(device_t dev) * was compiled with. */ rid = MIPS_MEM_RID; - sc->sc_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, + sc->siba_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); - if (sc->sc_mem == NULL) { + if (sc->siba_mem_res == NULL) { device_printf(dev, "unable to allocate probe aperture\n"); return (ENXIO); } - sc->sc_bt = rman_get_bustag(sc->sc_mem); - sc->sc_bh = rman_get_bushandle(sc->sc_mem); - sc->sc_maddr = rman_get_start(sc->sc_mem); - sc->sc_msize = rman_get_size(sc->sc_mem); + sc->siba_mem_bt = rman_get_bustag(sc->siba_mem_res); + sc->siba_mem_bh = rman_get_bushandle(sc->siba_mem_res); + sc->siba_maddr = rman_get_start(sc->siba_mem_res); + sc->siba_msize = rman_get_size(sc->siba_mem_res); if (siba_debug) { device_printf(dev, "start %08x len %08x\n", - sc->sc_maddr, sc->sc_msize); + sc->siba_maddr, sc->siba_msize); } - idlo = siba_read_4(sc, 0, SIBA_CORE_IDLO); - idhi = siba_read_4(sc, 0, SIBA_CORE_IDHI); + idlo = siba_mips_read_4(sc, 0, SIBA_IDLOW); + idhi = siba_mips_read_4(sc, 0, SIBA_IDHIGH); ccid = ((idhi & 0x8ff0) >> 4); if (siba_debug) { device_printf(dev, "idlo = %08x\n", idlo); @@ -256,7 +232,7 @@ siba_probe(device_t dev) uint16_t cc_id; uint16_t cc_rev; - ccidreg = siba_read_4(sc, 0, SIBA_CC_CCID); + ccidreg = siba_mips_read_4(sc, 0, SIBA_CC_CHIPID); cc_id = (ccidreg & SIBA_CC_IDMASK); cc_rev = (ccidreg & SIBA_CC_REVMASK) >> SIBA_CC_REVSHIFT; if (siba_debug) { @@ -264,9 +240,9 @@ siba_probe(device_t dev) ccidreg, cc_id, cc_rev); } - sc->sc_ncores = siba_getncores(cc_id); + sc->siba_ncores = siba_getncores(dev, cc_id); if (siba_debug) { - device_printf(dev, "%d cores detected.\n", sc->sc_ncores); + device_printf(dev, "%d cores detected.\n", sc->siba_ncores); } /* @@ -275,36 +251,38 @@ siba_probe(device_t dev) */ rid = MIPS_MEM_RID; int result; - result = bus_release_resource(dev, SYS_RES_MEMORY, rid, sc->sc_mem); + result = bus_release_resource(dev, SYS_RES_MEMORY, rid, + sc->siba_mem_res); if (result != 0) { device_printf(dev, "error %d releasing resource\n", result); return (ENXIO); } uint32_t total; - total = sc->sc_ncores * SIBA_CORE_LEN; + total = sc->siba_ncores * SIBA_CORE_LEN; /* XXX Don't allocate the entire window until we * enumerate the bus. Once the bus has been enumerated, * and instance variables/children instantiated + populated, * release the resource so children may attach. */ - sc->sc_mem = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, - sc->sc_maddr, sc->sc_maddr + total - 1, total, RF_ACTIVE); - if (sc->sc_mem == NULL) { + sc->siba_mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, + sc->siba_maddr, sc->siba_maddr + total - 1, total, RF_ACTIVE); + if (sc->siba_mem_res == NULL) { device_printf(dev, "unable to allocate entire aperture\n"); return (ENXIO); } - sc->sc_bt = rman_get_bustag(sc->sc_mem); - sc->sc_bh = rman_get_bushandle(sc->sc_mem); - sc->sc_maddr = rman_get_start(sc->sc_mem); - sc->sc_msize = rman_get_size(sc->sc_mem); + sc->siba_mem_bt = rman_get_bustag(sc->siba_mem_res); + sc->siba_mem_bh = rman_get_bushandle(sc->siba_mem_res); + sc->siba_maddr = rman_get_start(sc->siba_mem_res); + sc->siba_msize = rman_get_size(sc->siba_mem_res); if (siba_debug) { device_printf(dev, "after remapping: start %08x len %08x\n", - sc->sc_maddr, sc->sc_msize); + sc->siba_maddr, sc->siba_msize); } - bus_set_resource(dev, SYS_RES_MEMORY, rid, sc->sc_maddr, sc->sc_msize); + bus_set_resource(dev, SYS_RES_MEMORY, rid, sc->siba_maddr, + sc->siba_msize); /* * We need a manager for the space we claim on nexus to @@ -313,12 +291,13 @@ siba_probe(device_t dev) * otherwise it may be claimed elsewhere. * XXX move to softc */ - mem_rman.rm_start = sc->sc_maddr; - mem_rman.rm_end = sc->sc_maddr + sc->sc_msize - 1; + mem_rman.rm_start = sc->siba_maddr; + mem_rman.rm_end = sc->siba_maddr + sc->siba_msize - 1; mem_rman.rm_type = RMAN_ARRAY; mem_rman.rm_descr = "SiBa I/O memory addresses"; if (rman_init(&mem_rman) != 0 || - rman_manage_region(&mem_rman, mem_rman.rm_start, mem_rman.rm_end) != 0) { + rman_manage_region(&mem_rman, mem_rman.rm_start, + mem_rman.rm_end) != 0) { panic("%s: mem_rman", __func__); } @@ -344,7 +323,7 @@ siba_attach(device_t dev) * NB: only one core may be mapped at any time if the siba bus * is the child of a PCI or PCMCIA bus. */ - for (idx = 0; idx < sc->sc_ncores; idx++) { + for (idx = 0; idx < sc->siba_ncores; idx++) { sdi = siba_setup_devinfo(dev, idx); child = device_add_child(dev, NULL, -1); if (child == NULL) @@ -483,13 +462,14 @@ siba_setup_devinfo(device_t dev, uint8_t idx) sdi = malloc(sizeof(*sdi), M_DEVBUF, M_WAITOK | M_ZERO); resource_list_init(&sdi->sdi_rl); - idlo = siba_read_4(sc, idx, SIBA_CORE_IDLO); - idhi = siba_read_4(sc, idx, SIBA_CORE_IDHI); + idlo = siba_mips_read_4(sc, idx, SIBA_IDLOW); + idhi = siba_mips_read_4(sc, idx, SIBA_IDHIGH); - vendorid = (idhi & SIBA_IDHIGH_VC) >> SIBA_IDHIGH_VC_SHIFT; + vendorid = (idhi & SIBA_IDHIGH_VENDORMASK) >> + SIBA_IDHIGH_VENDOR_SHIFT; devid = ((idhi & 0x8ff0) >> 4); - rev = (idhi & SIBA_IDHIGH_RCLO); - rev |= (idhi & SIBA_IDHIGH_RCHI) >> SIBA_IDHIGH_RCHI_SHIFT; + rev = (idhi & SIBA_IDHIGH_REVLO); + rev |= (idhi & SIBA_IDHIGH_REVHI) >> SIBA_IDHIGH_REVHI_SHIFT; sdi->sdi_vid = vendorid; sdi->sdi_devid = devid; @@ -500,7 +480,7 @@ siba_setup_devinfo(device_t dev, uint8_t idx) /* * Determine memory window on bus and irq if one is needed. */ - baseaddr = sc->sc_maddr + (idx * SIBA_CORE_LEN); + baseaddr = sc->siba_maddr + (idx * SIBA_CORE_LEN); resource_list_add(&sdi->sdi_rl, SYS_RES_MEMORY, MIPS_MEM_RID, /* XXX */ baseaddr, baseaddr + SIBA_CORE_LEN - 1, SIBA_CORE_LEN); diff --git a/sys/dev/siba/siba_bwn.c b/sys/dev/siba/siba_bwn.c new file mode 100644 index 0000000..a5513bd --- /dev/null +++ b/sys/dev/siba/siba_bwn.c @@ -0,0 +1,366 @@ +/*- + * Copyright (c) 2009-2010 Weongyo Jeong + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * Sonics Silicon Backplane front-end for bwn(4). + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +/* + * PCI glue. + */ + +struct siba_bwn_softc { + /* Child driver using MSI. */ + device_t ssc_msi_child; + struct siba_softc ssc_siba; +}; + +#define BS_BAR 0x10 +#define PCI_VENDOR_BROADCOM 0x14e4 +#define N(a) (sizeof(a) / sizeof(a[0])) + +static const struct siba_dev { + uint16_t vid; + uint16_t did; + const char *desc; +} siba_devices[] = { + { PCI_VENDOR_BROADCOM, 0x4301, "Broadcom BCM4301 802.11b Wireless" }, + { PCI_VENDOR_BROADCOM, 0x4306, "Unknown" }, + { PCI_VENDOR_BROADCOM, 0x4307, "Broadcom BCM4307 802.11b Wireless" }, + { PCI_VENDOR_BROADCOM, 0x4311, "Broadcom BCM4311 802.11b/g Wireless" }, + { PCI_VENDOR_BROADCOM, 0x4312, + "Broadcom BCM4312 802.11a/b/g Wireless" }, + { PCI_VENDOR_BROADCOM, 0x4315, "Broadcom BCM4312 802.11b/g Wireless" }, + { PCI_VENDOR_BROADCOM, 0x4318, "Broadcom BCM4318 802.11b/g Wireless" }, + { PCI_VENDOR_BROADCOM, 0x4319, + "Broadcom BCM4318 802.11a/b/g Wireless" }, + { PCI_VENDOR_BROADCOM, 0x4320, "Broadcom BCM4306 802.11b/g Wireless" }, + { PCI_VENDOR_BROADCOM, 0x4321, "Broadcom BCM4306 802.11a Wireless" }, + { PCI_VENDOR_BROADCOM, 0x4324, + "Broadcom BCM4309 802.11a/b/g Wireless" }, + { PCI_VENDOR_BROADCOM, 0x4325, "Broadcom BCM4306 802.11b/g Wireless" }, + { PCI_VENDOR_BROADCOM, 0x4328, "Unknown" }, + { PCI_VENDOR_BROADCOM, 0x4329, "Unknown" }, + { PCI_VENDOR_BROADCOM, 0x432b, "Unknown" } +}; + +device_t siba_add_child(device_t, struct siba_softc *, int, const char *, + int); +int siba_core_attach(struct siba_softc *); +int siba_core_detach(struct siba_softc *); +int siba_core_suspend(struct siba_softc *); +int siba_core_resume(struct siba_softc *); + +static int +siba_bwn_probe(device_t dev) +{ + int i; + uint16_t did, vid; + + did = pci_get_device(dev); + vid = pci_get_vendor(dev); + + for (i = 0; i < N(siba_devices); i++) { + if (siba_devices[i].did == did && siba_devices[i].vid == vid) { + device_set_desc(dev, siba_devices[i].desc); + return (BUS_PROBE_DEFAULT); + } + } + return (ENXIO); +} + +static int +siba_bwn_attach(device_t dev) +{ + struct siba_bwn_softc *ssc = device_get_softc(dev); + struct siba_softc *siba = &ssc->ssc_siba; + + siba->siba_dev = dev; + siba->siba_type = SIBA_TYPE_PCI; + + /* + * Enable bus mastering. + */ + pci_enable_busmaster(dev); + + /* + * Setup memory-mapping of PCI registers. + */ + siba->siba_mem_rid = SIBA_PCIR_BAR; + siba->siba_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, + &siba->siba_mem_rid, RF_ACTIVE); + if (siba->siba_mem_res == NULL) { + device_printf(dev, "cannot map register space\n"); + return (ENXIO); + } + siba->siba_mem_bt = rman_get_bustag(siba->siba_mem_res); + siba->siba_mem_bh = rman_get_bushandle(siba->siba_mem_res); + + /* Get more PCI information */ + siba->siba_pci_did = pci_get_device(dev); + siba->siba_pci_vid = pci_get_vendor(dev); + siba->siba_pci_subvid = pci_get_subvendor(dev); + siba->siba_pci_subdid = pci_get_subdevice(dev); + + return (siba_core_attach(siba)); +} + +static int +siba_bwn_detach(device_t dev) +{ + struct siba_bwn_softc *ssc = device_get_softc(dev); + struct siba_softc *siba = &ssc->ssc_siba; + + /* check if device was removed */ + siba->siba_invalid = !bus_child_present(dev); + + pci_disable_busmaster(dev); + bus_generic_detach(dev); + siba_core_detach(siba); + + bus_release_resource(dev, SYS_RES_MEMORY, BS_BAR, siba->siba_mem_res); + + return (0); +} + +static int +siba_bwn_shutdown(device_t dev) +{ + device_t *devlistp; + int devcnt, error = 0, i; + + error = device_get_children(dev, &devlistp, &devcnt); + if (error != 0) + return (error); + + for (i = 0 ; i < devcnt ; i++) + device_shutdown(devlistp[i]); + free(devlistp, M_TEMP); + return (0); +} + +static int +siba_bwn_suspend(device_t dev) +{ + struct siba_bwn_softc *ssc = device_get_softc(dev); + struct siba_softc *siba = &ssc->ssc_siba; + device_t *devlistp; + int devcnt, error = 0, i, j; + + error = device_get_children(dev, &devlistp, &devcnt); + if (error != 0) + return (error); + + for (i = 0 ; i < devcnt ; i++) { + error = DEVICE_SUSPEND(devlistp[i]); + if (error) { + for (j = 0; j < i; i++) + DEVICE_RESUME(devlistp[j]); + return (error); + } + } + free(devlistp, M_TEMP); + return (siba_core_suspend(siba)); +} + +static int +siba_bwn_resume(device_t dev) +{ + struct siba_bwn_softc *ssc = device_get_softc(dev); + struct siba_softc *siba = &ssc->ssc_siba; + device_t *devlistp; + int devcnt, error = 0, i; + + error = siba_core_resume(siba); + if (error != 0) + return (error); + + error = device_get_children(dev, &devlistp, &devcnt); + if (error != 0) + return (error); + + for (i = 0 ; i < devcnt ; i++) + DEVICE_RESUME(devlistp[i]); + free(devlistp, M_TEMP); + return (0); +} + +static device_t +siba_bwn_add_child(device_t dev, int order, const char *name, int unit) +{ + struct siba_bwn_softc *ssc = device_get_softc(dev); + struct siba_softc *siba = &ssc->ssc_siba; + + return (siba_add_child(dev, siba, order, name, unit)); +} + +/* proxying to the parent */ +static struct resource * +siba_bwn_alloc_resource(device_t dev, device_t child, int type, int *rid, + u_long start, u_long end, u_long count, u_int flags) +{ + + return (BUS_ALLOC_RESOURCE(device_get_parent(dev), dev, + type, rid, start, end, count, flags)); +} + +/* proxying to the parent */ +static int +siba_bwn_release_resource(device_t dev, device_t child, int type, + int rid, struct resource *r) +{ + + return (BUS_RELEASE_RESOURCE(device_get_parent(dev), dev, type, + rid, r)); +} + +/* proxying to the parent */ +static int +siba_bwn_setup_intr(device_t dev, device_t child, struct resource *irq, + int flags, driver_filter_t *filter, driver_intr_t *intr, void *arg, + void **cookiep) +{ + + return (BUS_SETUP_INTR(device_get_parent(dev), dev, irq, flags, + filter, intr, arg, cookiep)); +} + +/* proxying to the parent */ +static int +siba_bwn_teardown_intr(device_t dev, device_t child, struct resource *irq, + void *cookie) +{ + + return (BUS_TEARDOWN_INTR(device_get_parent(dev), dev, irq, cookie)); +} + +static int +siba_bwn_find_extcap(device_t dev, device_t child, int capability, + int *capreg) +{ + + return (pci_find_extcap(dev, capability, capreg)); +} + +static int +siba_bwn_alloc_msi(device_t dev, device_t child, int *count) +{ + struct siba_bwn_softc *ssc; + int error; + + ssc = device_get_softc(dev); + if (ssc->ssc_msi_child != NULL) + return (EBUSY); + error = pci_alloc_msi(dev, count); + if (error == 0) + ssc->ssc_msi_child = child; + return (error); +} + +static int +siba_bwn_release_msi(device_t dev, device_t child) +{ + struct siba_bwn_softc *ssc; + int error; + + ssc = device_get_softc(dev); + if (ssc->ssc_msi_child != child) + return (ENXIO); + error = pci_release_msi(dev); + if (error == 0) + ssc->ssc_msi_child = NULL; + return (error); +} + +static int +siba_bwn_msi_count(device_t dev, device_t child) +{ + + return (pci_msi_count(dev)); +} + +static device_method_t siba_bwn_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, siba_bwn_probe), + DEVMETHOD(device_attach, siba_bwn_attach), + DEVMETHOD(device_detach, siba_bwn_detach), + DEVMETHOD(device_shutdown, siba_bwn_shutdown), + DEVMETHOD(device_suspend, siba_bwn_suspend), + DEVMETHOD(device_resume, siba_bwn_resume), + + /* Bus interface */ + DEVMETHOD(bus_add_child, siba_bwn_add_child), + DEVMETHOD(bus_alloc_resource, siba_bwn_alloc_resource), + DEVMETHOD(bus_release_resource, siba_bwn_release_resource), + DEVMETHOD(bus_setup_intr, siba_bwn_setup_intr), + DEVMETHOD(bus_teardown_intr, siba_bwn_teardown_intr), + + /* PCI interface */ + DEVMETHOD(pci_find_extcap, siba_bwn_find_extcap), + DEVMETHOD(pci_alloc_msi, siba_bwn_alloc_msi), + DEVMETHOD(pci_release_msi, siba_bwn_release_msi), + DEVMETHOD(pci_msi_count, siba_bwn_msi_count), + + { 0,0 } +}; +static driver_t siba_bwn_driver = { + "siba_bwn", + siba_bwn_methods, + sizeof(struct siba_bwn_softc) +}; +static devclass_t siba_bwn_devclass; +DRIVER_MODULE(siba_bwn, pci, siba_bwn_driver, siba_bwn_devclass, 0, 0); +MODULE_VERSION(siba_bwn, 1); diff --git a/sys/dev/siba/siba_cc.c b/sys/dev/siba/siba_cc.c index cd78f0b..db0aac5 100644 --- a/sys/dev/siba/siba_cc.c +++ b/sys/dev/siba/siba_cc.c @@ -55,9 +55,9 @@ __FBSDID("$FreeBSD$"); #include -#include -#include #include +#include +#include static int siba_cc_attach(device_t); static int siba_cc_probe(device_t); diff --git a/sys/dev/siba/siba_core.c b/sys/dev/siba/siba_core.c new file mode 100644 index 0000000..b2168f5 --- /dev/null +++ b/sys/dev/siba/siba_core.c @@ -0,0 +1,2007 @@ +/*- + * Copyright (c) 2009-2010 Weongyo Jeong + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * the Sonics Silicon Backplane driver. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#ifdef SIBA_DEBUG +enum { + SIBA_DEBUG_SCAN = 0x00000001, /* scan */ + SIBA_DEBUG_PMU = 0x00000002, /* PMU */ + SIBA_DEBUG_PLL = 0x00000004, /* PLL */ + SIBA_DEBUG_SWITCHCORE = 0x00000008, /* switching core */ + SIBA_DEBUG_SPROM = 0x00000010, /* SPROM */ + SIBA_DEBUG_CORE = 0x00000020, /* handling cores */ + SIBA_DEBUG_ANY = 0xffffffff +}; +#define DPRINTF(siba, m, fmt, ...) do { \ + if (siba->siba_debug & (m)) \ + printf(fmt, __VA_ARGS__); \ +} while (0) +#else +#define DPRINTF(siba, m, fmt, ...) do { (void) siba; } while (0) +#endif +#define N(a) (sizeof(a) / sizeof(a[0])) + +static void siba_pci_gpio(struct siba_softc *, uint32_t, int); +static void siba_scan(struct siba_softc *); +static int siba_switchcore(struct siba_softc *, uint8_t); +static int siba_pci_switchcore_sub(struct siba_softc *, uint8_t); +static uint32_t siba_scan_read_4(struct siba_softc *, uint8_t, uint16_t); +static uint16_t siba_dev2chipid(struct siba_softc *); +static uint16_t siba_pci_read_2(struct siba_dev_softc *, uint16_t); +static uint32_t siba_pci_read_4(struct siba_dev_softc *, uint16_t); +static void siba_pci_write_2(struct siba_dev_softc *, uint16_t, uint16_t); +static void siba_pci_write_4(struct siba_dev_softc *, uint16_t, uint32_t); +static void siba_cc_clock(struct siba_cc *, + enum siba_clock); +static void siba_cc_pmu_init(struct siba_cc *); +static void siba_cc_power_init(struct siba_cc *); +static void siba_cc_powerup_delay(struct siba_cc *); +static int siba_cc_clockfreq(struct siba_cc *, int); +static void siba_cc_pmu1_pll0_init(struct siba_cc *, uint32_t); +static void siba_cc_pmu0_pll0_init(struct siba_cc *, uint32_t); +static enum siba_clksrc siba_cc_clksrc(struct siba_cc *); +static const struct siba_cc_pmu1_plltab *siba_cc_pmu1_plltab_find(uint32_t); +static uint32_t siba_cc_pll_read(struct siba_cc *, uint32_t); +static void siba_cc_pll_write(struct siba_cc *, uint32_t, + uint32_t); +static const struct siba_cc_pmu0_plltab * + siba_cc_pmu0_plltab_findentry(uint32_t); +static int siba_pci_sprom(struct siba_softc *, struct siba_sprom *); +static int siba_sprom_read(struct siba_softc *, uint16_t *, uint16_t); +static int sprom_check_crc(const uint16_t *, size_t); +static uint8_t siba_crc8(uint8_t, uint8_t); +static void siba_sprom_r123(struct siba_sprom *, const uint16_t *); +static void siba_sprom_r45(struct siba_sprom *, const uint16_t *); +static void siba_sprom_r8(struct siba_sprom *, const uint16_t *); +static int8_t siba_sprom_r123_antgain(uint8_t, const uint16_t *, uint16_t, + uint16_t); +static uint32_t siba_tmslow_reject_bitmask(struct siba_dev_softc *); +static uint32_t siba_pcicore_read_4(struct siba_pci *, uint16_t); +static void siba_pcicore_write_4(struct siba_pci *, uint16_t, uint32_t); +static uint32_t siba_pcie_read(struct siba_pci *, uint32_t); +static void siba_pcie_write(struct siba_pci *, uint32_t, uint32_t); +static void siba_pcie_mdio_write(struct siba_pci *, uint8_t, uint8_t, + uint16_t); +static void siba_pci_read_multi_1(struct siba_dev_softc *, void *, size_t, + uint16_t); +static void siba_pci_read_multi_2(struct siba_dev_softc *, void *, size_t, + uint16_t); +static void siba_pci_read_multi_4(struct siba_dev_softc *, void *, size_t, + uint16_t); +static void siba_pci_write_multi_1(struct siba_dev_softc *, const void *, + size_t, uint16_t); +static void siba_pci_write_multi_2(struct siba_dev_softc *, const void *, + size_t, uint16_t); +static void siba_pci_write_multi_4(struct siba_dev_softc *, const void *, + size_t, uint16_t); +static const char *siba_core_name(uint16_t); +static void siba_pcicore_init(struct siba_pci *); +device_t siba_add_child(device_t, struct siba_softc *, int, const char *, + int); +int siba_core_attach(struct siba_softc *); +int siba_core_detach(struct siba_softc *); +int siba_core_suspend(struct siba_softc *); +int siba_core_resume(struct siba_softc *); +uint8_t siba_getncores(device_t, uint16_t); + +static const struct siba_bus_ops siba_pci_ops = { + .read_2 = siba_pci_read_2, + .read_4 = siba_pci_read_4, + .write_2 = siba_pci_write_2, + .write_4 = siba_pci_write_4, + .read_multi_1 = siba_pci_read_multi_1, + .read_multi_2 = siba_pci_read_multi_2, + .read_multi_4 = siba_pci_read_multi_4, + .write_multi_1 = siba_pci_write_multi_1, + .write_multi_2 = siba_pci_write_multi_2, + .write_multi_4 = siba_pci_write_multi_4, +}; + +static const struct siba_cc_pmu_res_updown siba_cc_pmu_4325_updown[] = + SIBA_CC_PMU_4325_RES_UPDOWN; +static const struct siba_cc_pmu_res_depend siba_cc_pmu_4325_depend[] = + SIBA_CC_PMU_4325_RES_DEPEND; +static const struct siba_cc_pmu_res_updown siba_cc_pmu_4328_updown[] = + SIBA_CC_PMU_4328_RES_UPDOWN; +static const struct siba_cc_pmu_res_depend siba_cc_pmu_4328_depend[] = + SIBA_CC_PMU_4328_RES_DEPEND; +static const struct siba_cc_pmu0_plltab siba_cc_pmu0_plltab[] = + SIBA_CC_PMU0_PLLTAB_ENTRY; +static const struct siba_cc_pmu1_plltab siba_cc_pmu1_plltab[] = + SIBA_CC_PMU1_PLLTAB_ENTRY; + +int +siba_core_attach(struct siba_softc *siba) +{ + struct siba_cc *scc; + int error; + + KASSERT(siba->siba_type == SIBA_TYPE_PCI, + ("unsupported BUS type (%#x)", siba->siba_type)); + + siba->siba_ops = &siba_pci_ops; + + siba_pci_gpio(siba, SIBA_GPIO_CRYSTAL | SIBA_GPIO_PLL, 1); + siba_scan(siba); + + /* XXX init PCI or PCMCIA host devices */ + + siba_powerup(siba, 0); + + /* init ChipCommon */ + scc = &siba->siba_cc; + if (scc->scc_dev != NULL) { + siba_cc_pmu_init(scc); + siba_cc_power_init(scc); + siba_cc_clock(scc, SIBA_CLOCK_FAST); + siba_cc_powerup_delay(scc); + } + + /* fetch various internal informations for PCI */ + siba->siba_board_vendor = pci_read_config(siba->siba_dev, + PCIR_SUBVEND_0, 2); + siba->siba_board_type = pci_read_config(siba->siba_dev, PCIR_SUBDEV_0, + 2); + siba->siba_board_rev = pci_read_config(siba->siba_dev, PCIR_REVID, 2); + error = siba_pci_sprom(siba, &siba->siba_sprom); + if (error) { + siba_powerdown(siba); + return (error); + } + + siba_powerdown(siba); + return (0); +} + +int +siba_core_detach(struct siba_softc *siba) +{ + device_t *devlistp; + int devcnt, error = 0, i; + + error = device_get_children(siba->siba_dev, &devlistp, &devcnt); + if (error != 0) + return (0); + + for ( i = 0 ; i < devcnt ; i++) + device_delete_child(siba->siba_dev, devlistp[i]); + free(devlistp, M_TEMP); + return (0); +} + +static void +siba_pci_gpio(struct siba_softc *siba, uint32_t what, int on) +{ + uint32_t in, out; + uint16_t status; + + if (siba->siba_type != SIBA_TYPE_PCI) + return; + + out = pci_read_config(siba->siba_dev, SIBA_GPIO_OUT, 4); + if (on == 0) { + if (what & SIBA_GPIO_PLL) + out |= SIBA_GPIO_PLL; + if (what & SIBA_GPIO_CRYSTAL) + out &= ~SIBA_GPIO_CRYSTAL; + pci_write_config(siba->siba_dev, SIBA_GPIO_OUT, out, 4); + pci_write_config(siba->siba_dev, SIBA_GPIO_OUT_EN, + pci_read_config(siba->siba_dev, + SIBA_GPIO_OUT_EN, 4) | what, 4); + return; + } + + in = pci_read_config(siba->siba_dev, SIBA_GPIO_IN, 4); + if ((in & SIBA_GPIO_CRYSTAL) != SIBA_GPIO_CRYSTAL) { + if (what & SIBA_GPIO_CRYSTAL) { + out |= SIBA_GPIO_CRYSTAL; + if (what & SIBA_GPIO_PLL) + out |= SIBA_GPIO_PLL; + pci_write_config(siba->siba_dev, SIBA_GPIO_OUT, out, 4); + pci_write_config(siba->siba_dev, + SIBA_GPIO_OUT_EN, pci_read_config(siba->siba_dev, + SIBA_GPIO_OUT_EN, 4) | what, 4); + DELAY(1000); + } + if (what & SIBA_GPIO_PLL) { + out &= ~SIBA_GPIO_PLL; + pci_write_config(siba->siba_dev, SIBA_GPIO_OUT, out, 4); + DELAY(5000); + } + } + + status = pci_read_config(siba->siba_dev, PCIR_STATUS, 2); + status &= ~PCIM_STATUS_STABORT; + pci_write_config(siba->siba_dev, PCIR_STATUS, status, 2); +} + +static void +siba_scan(struct siba_softc *siba) +{ + struct siba_dev_softc *sd; + uint32_t idhi, tmp; + int base, dev_i = 0, error, i, is_pcie, n_80211 = 0, n_cc = 0, + n_pci = 0; + + KASSERT(siba->siba_type == SIBA_TYPE_PCI, + ("unsupported BUS type (%#x)", siba->siba_type)); + + siba->siba_ndevs = 0; + error = siba_switchcore(siba, 0); /* need the first core */ + if (error) + return; + + idhi = siba_scan_read_4(siba, 0, SIBA_IDHIGH); + if (SIBA_IDHIGH_CORECODE(idhi) == SIBA_DEVID_CHIPCOMMON) { + tmp = siba_scan_read_4(siba, 0, SIBA_CC_CHIPID); + siba->siba_chipid = SIBA_CC_ID(tmp); + siba->siba_chiprev = SIBA_CC_REV(tmp); + siba->siba_chippkg = SIBA_CC_PKG(tmp); + if (SIBA_IDHIGH_REV(idhi) >= 4) + siba->siba_ndevs = SIBA_CC_NCORES(tmp); + siba->siba_cc.scc_caps = siba_scan_read_4(siba, 0, + SIBA_CC_CAPS); + } else { + if (siba->siba_type == SIBA_TYPE_PCI) { + siba->siba_chipid = siba_dev2chipid(siba); + siba->siba_chiprev = pci_read_config(siba->siba_dev, + PCIR_REVID, 2); + siba->siba_chippkg = 0; + } else { + siba->siba_chipid = 0x4710; + siba->siba_chiprev = 0; + siba->siba_chippkg = 0; + } + } + if (siba->siba_ndevs == 0) + siba->siba_ndevs = siba_getncores(siba->siba_dev, + siba->siba_chipid); + if (siba->siba_ndevs > SIBA_MAX_CORES) { + device_printf(siba->siba_dev, + "too many siba cores (max %d %d)\n", + SIBA_MAX_CORES, siba->siba_ndevs); + return; + } + + /* looking basic information about each cores/devices */ + for (i = 0; i < siba->siba_ndevs; i++) { + error = siba_switchcore(siba, i); + if (error) + return; + sd = &(siba->siba_devs[dev_i]); + idhi = siba_scan_read_4(siba, i, SIBA_IDHIGH); + sd->sd_bus = siba; + sd->sd_id.sd_device = SIBA_IDHIGH_CORECODE(idhi); + sd->sd_id.sd_rev = SIBA_IDHIGH_REV(idhi); + sd->sd_id.sd_vendor = SIBA_IDHIGH_VENDOR(idhi); + sd->sd_ops = siba->siba_ops; + sd->sd_coreidx = i; + + DPRINTF(siba, SIBA_DEBUG_SCAN, + "core %d (%s) found (cc %#xrev %#x vendor %#x)\n", + i, siba_core_name(sd->sd_id.sd_device), + sd->sd_id.sd_device, sd->sd_id.sd_rev, sd->sd_id.vendor); + + switch (sd->sd_id.sd_device) { + case SIBA_DEVID_CHIPCOMMON: + n_cc++; + if (n_cc > 1) { + device_printf(siba->siba_dev, + "warn: multiple ChipCommon\n"); + break; + } + siba->siba_cc.scc_dev = sd; + break; + case SIBA_DEVID_80211: + n_80211++; + if (n_80211 > 1) { + device_printf(siba->siba_dev, + "warn: multiple 802.11 core\n"); + continue; + } + break; + case SIBA_DEVID_PCI: + case SIBA_DEVID_PCIE: + n_pci++; + error = pci_find_extcap(siba->siba_dev, PCIY_EXPRESS, + &base); + is_pcie = (error == 0) ? 1 : 0; + + if (n_pci > 1) { + device_printf(siba->siba_dev, + "warn: multiple PCI(E) cores\n"); + break; + } + if (sd->sd_id.sd_device == SIBA_DEVID_PCI && + is_pcie == 1) + continue; + if (sd->sd_id.sd_device == SIBA_DEVID_PCIE && + is_pcie == 0) + continue; + siba->siba_pci.spc_dev = sd; + break; + case SIBA_DEVID_MODEM: + case SIBA_DEVID_PCMCIA: + break; + default: + device_printf(siba->siba_dev, + "unsupported coreid (%s)\n", + siba_core_name(sd->sd_id.sd_device)); + break; + } + dev_i++; + } + siba->siba_ndevs = dev_i; +} + +static int +siba_switchcore(struct siba_softc *siba, uint8_t idx) +{ + + switch (siba->siba_type) { + case SIBA_TYPE_PCI: + return (siba_pci_switchcore_sub(siba, idx)); + default: + KASSERT(0 == 1, + ("%s: unsupported bustype %#x", __func__, + siba->siba_type)); + } + return (0); +} + +static int +siba_pci_switchcore_sub(struct siba_softc *siba, uint8_t idx) +{ +#define RETRY_MAX 50 + int i; + uint32_t dir; + + dir = SIBA_REGWIN(idx); + + for (i = 0; i < RETRY_MAX; i++) { + pci_write_config(siba->siba_dev, SIBA_BAR0, dir, 4); + if (pci_read_config(siba->siba_dev, SIBA_BAR0, 4) == dir) + return (0); + DELAY(10); + } + return (ENODEV); +#undef RETRY_MAX +} + +static int +siba_pci_switchcore(struct siba_softc *siba, struct siba_dev_softc *sd) +{ + int error; + + DPRINTF(siba, SIBA_DEBUG_SWITCHCORE, "Switching to %s core, index %d\n", + siba_core_name(sd->sd_id.sd_device), sd->sd_coreidx); + + error = siba_pci_switchcore_sub(siba, sd->sd_coreidx); + if (error == 0) + siba->siba_curdev = sd; + + return (error); +} + +static uint32_t +siba_scan_read_4(struct siba_softc *siba, uint8_t coreidx, + uint16_t offset) +{ + + (void)coreidx; + KASSERT(siba->siba_type == SIBA_TYPE_PCI, + ("unsupported BUS type (%#x)", siba->siba_type)); + + return (SIBA_READ_4(siba, offset)); +} + +static uint16_t +siba_dev2chipid(struct siba_softc *siba) +{ + uint16_t chipid = 0; + + switch (siba->siba_pci_did) { + case 0x4301: + chipid = 0x4301; + break; + case 0x4305: + case 0x4306: + case 0x4307: + chipid = 0x4307; + break; + case 0x4403: + chipid = 0x4402; + break; + case 0x4610: + case 0x4611: + case 0x4612: + case 0x4613: + case 0x4614: + case 0x4615: + chipid = 0x4610; + break; + case 0x4710: + case 0x4711: + case 0x4712: + case 0x4713: + case 0x4714: + case 0x4715: + chipid = 0x4710; + break; + case 0x4320: + case 0x4321: + case 0x4322: + case 0x4323: + case 0x4324: + case 0x4325: + chipid = 0x4309; + break; + case PCI_DEVICE_ID_BCM4401: + case PCI_DEVICE_ID_BCM4401B0: + case PCI_DEVICE_ID_BCM4401B1: + chipid = 0x4401; + break; + default: + device_printf(siba->siba_dev, "unknown PCI did (%d)\n", + siba->siba_pci_did); + } + + return (chipid); +} + +/* + * Earlier ChipCommon revisions have hardcoded number of cores + * present dependent on the ChipCommon ID. + */ +uint8_t +siba_getncores(device_t dev, uint16_t chipid) +{ + switch (chipid) { + case 0x4401: + case 0x4402: + return (3); + case 0x4301: + case 0x4307: + return (5); + case 0x4306: + return (6); + case SIBA_CCID_SENTRY5: + return (7); + case 0x4310: + return (8); + case SIBA_CCID_BCM4710: + case 0x4610: + case SIBA_CCID_BCM4704: + return (9); + default: + device_printf(dev, "unknown the chipset ID %#x\n", chipid); + } + + return (1); +} + +static const char * +siba_core_name(uint16_t coreid) +{ + + switch (coreid) { + case SIBA_DEVID_CHIPCOMMON: + return ("ChipCommon"); + case SIBA_DEVID_ILINE20: + return ("ILine 20"); + case SIBA_DEVID_SDRAM: + return ("SDRAM"); + case SIBA_DEVID_PCI: + return ("PCI"); + case SIBA_DEVID_MIPS: + return ("MIPS"); + case SIBA_DEVID_ETHERNET: + return ("Fast Ethernet"); + case SIBA_DEVID_MODEM: + return ("Modem"); + case SIBA_DEVID_USB11_HOSTDEV: + return ("USB 1.1 Hostdev"); + case SIBA_DEVID_ADSL: + return ("ADSL"); + case SIBA_DEVID_ILINE100: + return ("ILine 100"); + case SIBA_DEVID_IPSEC: + return ("IPSEC"); + case SIBA_DEVID_PCMCIA: + return ("PCMCIA"); + case SIBA_DEVID_INTERNAL_MEM: + return ("Internal Memory"); + case SIBA_DEVID_SDRAMDDR: + return ("MEMC SDRAM"); + case SIBA_DEVID_EXTIF: + return ("EXTIF"); + case SIBA_DEVID_80211: + return ("IEEE 802.11"); + case SIBA_DEVID_MIPS_3302: + return ("MIPS 3302"); + case SIBA_DEVID_USB11_HOST: + return ("USB 1.1 Host"); + case SIBA_DEVID_USB11_DEV: + return ("USB 1.1 Device"); + case SIBA_DEVID_USB20_HOST: + return ("USB 2.0 Host"); + case SIBA_DEVID_USB20_DEV: + return ("USB 2.0 Device"); + case SIBA_DEVID_SDIO_HOST: + return ("SDIO Host"); + case SIBA_DEVID_ROBOSWITCH: + return ("Roboswitch"); + case SIBA_DEVID_PARA_ATA: + return ("PATA"); + case SIBA_DEVID_SATA_XORDMA: + return ("SATA XOR-DMA"); + case SIBA_DEVID_ETHERNET_GBIT: + return ("GBit Ethernet"); + case SIBA_DEVID_PCIE: + return ("PCI-Express"); + case SIBA_DEVID_MIMO_PHY: + return ("MIMO PHY"); + case SIBA_DEVID_SRAM_CTRLR: + return ("SRAM Controller"); + case SIBA_DEVID_MINI_MACPHY: + return ("Mini MACPHY"); + case SIBA_DEVID_ARM_1176: + return ("ARM 1176"); + case SIBA_DEVID_ARM_7TDMI: + return ("ARM 7TDMI"); + } + return ("unknown"); +} + +static uint16_t +siba_pci_read_2(struct siba_dev_softc *sd, uint16_t offset) +{ + struct siba_softc *siba = sd->sd_bus; + + if (siba->siba_curdev != sd && siba_pci_switchcore(siba, sd) != 0) + return (0xffff); + + return (SIBA_READ_2(siba, offset)); +} + +static uint32_t +siba_pci_read_4(struct siba_dev_softc *sd, uint16_t offset) +{ + struct siba_softc *siba = sd->sd_bus; + + if (siba->siba_curdev != sd && siba_pci_switchcore(siba, sd) != 0) + return (0xffff); + + return (SIBA_READ_4(siba, offset)); +} + +static void +siba_pci_write_2(struct siba_dev_softc *sd, uint16_t offset, uint16_t value) +{ + struct siba_softc *siba = sd->sd_bus; + + if (siba->siba_curdev != sd && siba_pci_switchcore(siba, sd) != 0) + return; + + SIBA_WRITE_2(siba, offset, value); +} + +static void +siba_pci_write_4(struct siba_dev_softc *sd, uint16_t offset, uint32_t value) +{ + struct siba_softc *siba = sd->sd_bus; + + if (siba->siba_curdev != sd && siba_pci_switchcore(siba, sd) != 0) + return; + + SIBA_WRITE_4(siba, offset, value); +} + +static void +siba_pci_read_multi_1(struct siba_dev_softc *sd, void *buffer, size_t count, + uint16_t offset) +{ + struct siba_softc *siba = sd->sd_bus; + + if (siba->siba_curdev != sd && siba_pci_switchcore(siba, sd) != 0) { + memset(buffer, 0xff, count); + return; + } + + SIBA_READ_MULTI_1(siba, offset, buffer, count); +} + +static void +siba_pci_read_multi_2(struct siba_dev_softc *sd, void *buffer, size_t count, + uint16_t offset) +{ + struct siba_softc *siba = sd->sd_bus; + + if (siba->siba_curdev != sd && siba_pci_switchcore(siba, sd) != 0) { + memset(buffer, 0xff, count); + return; + } + + KASSERT(!(count & 1), ("%s:%d: fail", __func__, __LINE__)); + SIBA_READ_MULTI_2(siba, offset, buffer, count >> 1); +} + +static void +siba_pci_read_multi_4(struct siba_dev_softc *sd, void *buffer, size_t count, + uint16_t offset) +{ + struct siba_softc *siba = sd->sd_bus; + + if (siba->siba_curdev != sd && siba_pci_switchcore(siba, sd) != 0) { + memset(buffer, 0xff, count); + return; + } + + KASSERT(!(count & 3), ("%s:%d: fail", __func__, __LINE__)); + SIBA_READ_MULTI_4(siba, offset, buffer, count >> 2); +} + +static void +siba_pci_write_multi_1(struct siba_dev_softc *sd, const void *buffer, + size_t count, uint16_t offset) +{ + struct siba_softc *siba = sd->sd_bus; + + if (siba->siba_curdev != sd && siba_pci_switchcore(siba, sd) != 0) + return; + + SIBA_WRITE_MULTI_1(siba, offset, buffer, count); +} + +static void +siba_pci_write_multi_2(struct siba_dev_softc *sd, const void *buffer, + size_t count, uint16_t offset) +{ + struct siba_softc *siba = sd->sd_bus; + + if (siba->siba_curdev != sd && siba_pci_switchcore(siba, sd) != 0) + return; + + KASSERT(!(count & 1), ("%s:%d: fail", __func__, __LINE__)); + SIBA_WRITE_MULTI_2(siba, offset, buffer, count >> 1); +} + +static void +siba_pci_write_multi_4(struct siba_dev_softc *sd, const void *buffer, + size_t count, uint16_t offset) +{ + struct siba_softc *siba = sd->sd_bus; + + if (siba->siba_curdev != sd && siba_pci_switchcore(siba, sd) != 0) + return; + + KASSERT(!(count & 3), ("%s:%d: fail", __func__, __LINE__)); + SIBA_WRITE_MULTI_4(siba, offset, buffer, count >> 2); +} + +void +siba_powerup(struct siba_softc *siba, int dynamic) +{ + + siba_pci_gpio(siba, SIBA_GPIO_CRYSTAL | SIBA_GPIO_PLL, 1); + siba_cc_clock(&siba->siba_cc, + (dynamic != 0) ? SIBA_CLOCK_DYNAMIC : SIBA_CLOCK_FAST); +} + +static void +siba_cc_clock(struct siba_cc *scc, enum siba_clock clock) +{ + struct siba_dev_softc *sd = scc->scc_dev; + struct siba_softc *siba; + uint32_t tmp; + + if (sd == NULL) + return; + siba = sd->sd_bus; + /* + * chipcommon < r6 (no dynamic clock control) + * chipcommon >= r10 (unknown) + */ + if (sd->sd_id.sd_rev < 6 || sd->sd_id.sd_rev >= 10 || + (scc->scc_caps & SIBA_CC_CAPS_PWCTL) == 0) + return; + + switch (clock) { + case SIBA_CLOCK_DYNAMIC: + tmp = SIBA_CC_READ32(scc, SIBA_CC_CLKSLOW) & + ~(SIBA_CC_CLKSLOW_ENXTAL | SIBA_CC_CLKSLOW_FSLOW | + SIBA_CC_CLKSLOW_IPLL); + if ((tmp & SIBA_CC_CLKSLOW_SRC) != SIBA_CC_CLKSLOW_SRC_CRYSTAL) + tmp |= SIBA_CC_CLKSLOW_ENXTAL; + SIBA_CC_WRITE32(scc, SIBA_CC_CLKSLOW, tmp); + if (tmp & SIBA_CC_CLKSLOW_ENXTAL) + siba_pci_gpio(siba, SIBA_GPIO_CRYSTAL, 0); + break; + case SIBA_CLOCK_SLOW: + SIBA_CC_WRITE32(scc, SIBA_CC_CLKSLOW, + SIBA_CC_READ32(scc, SIBA_CC_CLKSLOW) | + SIBA_CC_CLKSLOW_FSLOW); + break; + case SIBA_CLOCK_FAST: + /* crystal on */ + siba_pci_gpio(siba, SIBA_GPIO_CRYSTAL, 1); + SIBA_CC_WRITE32(scc, SIBA_CC_CLKSLOW, + (SIBA_CC_READ32(scc, SIBA_CC_CLKSLOW) | + SIBA_CC_CLKSLOW_IPLL) & ~SIBA_CC_CLKSLOW_FSLOW); + break; + default: + KASSERT(0 == 1, + ("%s: unsupported clock %#x", __func__, clock)); + } +} + +uint16_t +siba_read_2(struct siba_dev_softc *sd, uint16_t offset) +{ + + return (sd->sd_ops->read_2(sd, offset)); +} + +uint32_t +siba_read_4(struct siba_dev_softc *sd, uint16_t offset) +{ + + return (sd->sd_ops->read_4(sd, offset)); +} + +void +siba_write_2(struct siba_dev_softc *sd, uint16_t offset, uint16_t value) +{ + + sd->sd_ops->write_2(sd, offset, value); +} + +void +siba_write_4(struct siba_dev_softc *sd, uint16_t offset, uint32_t value) +{ + + sd->sd_ops->write_4(sd, offset, value); +} + +void +siba_read_multi_1(struct siba_dev_softc *sd, void *buffer, size_t count, + uint16_t offset) +{ + + sd->sd_ops->read_multi_1(sd, buffer, count, offset); +} + +void +siba_read_multi_2(struct siba_dev_softc *sd, void *buffer, size_t count, + uint16_t offset) +{ + + sd->sd_ops->read_multi_2(sd, buffer, count, offset); +} + +void +siba_read_multi_4(struct siba_dev_softc *sd, void *buffer, size_t count, + uint16_t offset) +{ + + sd->sd_ops->read_multi_4(sd, buffer, count, offset); +} + +void +siba_write_multi_1(struct siba_dev_softc *sd, const void *buffer, + size_t count, uint16_t offset) +{ + + sd->sd_ops->write_multi_1(sd, buffer, count, offset); +} + +void +siba_write_multi_2(struct siba_dev_softc *sd, const void *buffer, + size_t count, uint16_t offset) +{ + + sd->sd_ops->write_multi_2(sd, buffer, count, offset); +} + +void +siba_write_multi_4(struct siba_dev_softc *sd, const void *buffer, + size_t count, uint16_t offset) +{ + + sd->sd_ops->write_multi_4(sd, buffer, count, offset); +} + +static void +siba_cc_pmu_init(struct siba_cc *scc) +{ + const struct siba_cc_pmu_res_updown *updown = NULL; + const struct siba_cc_pmu_res_depend *depend = NULL; + struct siba_dev_softc *sd = scc->scc_dev; + struct siba_softc *siba = sd->sd_bus; + uint32_t min = 0, max = 0, pmucap; + unsigned int i, updown_size, depend_size; + + if ((scc->scc_caps & SIBA_CC_CAPS_PMU) == 0) + return; + + pmucap = SIBA_CC_READ32(scc, SIBA_CC_PMUCAPS); + scc->scc_pmu.rev = (pmucap & SIBA_CC_PMUCAPS_REV); + + DPRINTF(siba, SIBA_DEBUG_PMU, "PMU(r%u) found (caps %#x)\n", + scc->scc_pmu.rev, pmucap); + + if (scc->scc_pmu.rev >= 1) { + if (siba->siba_chiprev < 2 && siba->siba_chipid == 0x4325) + SIBA_CC_MASK32(scc, SIBA_CC_PMUCTL, + ~SIBA_CC_PMUCTL_NOILP); + else + SIBA_CC_SET32(scc, SIBA_CC_PMUCTL, + SIBA_CC_PMUCTL_NOILP); + } + + /* initialize PLL & PMU resources */ + switch (siba->siba_chipid) { + case 0x4312: + siba_cc_pmu1_pll0_init(scc, 0 /* use default */); + /* use the default: min = 0xcbb max = 0x7ffff */ + break; + case 0x4325: + siba_cc_pmu1_pll0_init(scc, 0 /* use default */); + + updown = siba_cc_pmu_4325_updown; + updown_size = N(siba_cc_pmu_4325_updown); + depend = siba_cc_pmu_4325_depend; + depend_size = N(siba_cc_pmu_4325_depend); + + min = (1 << SIBA_CC_PMU_4325_BURST) | + (1 << SIBA_CC_PMU_4325_LN); + if (SIBA_CC_READ32(scc, SIBA_CC_CHIPSTAT) & + SIBA_CC_CHST_4325_PMUTOP_2B) + min |= (1 << SIBA_CC_PMU_4325_CLBURST); + max = 0xfffff; + break; + case 0x4328: + siba_cc_pmu0_pll0_init(scc, 0 /* use default */); + + updown = siba_cc_pmu_4328_updown; + updown_size = N(siba_cc_pmu_4328_updown); + depend = siba_cc_pmu_4328_depend; + depend_size = N(siba_cc_pmu_4328_depend); + + min = (1 << SIBA_CC_PMU_4328_EXT_SWITCH_PWM) | + (1 << SIBA_CC_PMU_4328_BB_SWITCH_PWM) | + (1 << SIBA_CC_PMU_4328_CRYSTAL_EN); + + max = 0xfffff; + break; + case 0x5354: + siba_cc_pmu0_pll0_init(scc, 0 /* use default */); + + max = 0xfffff; + break; + default: + device_printf(siba->siba_dev, + "unknown chipid %#x for PLL & PMU init\n", + siba->siba_chipid); + } + + if (updown) { + for (i = 0; i < updown_size; i++) { + SIBA_CC_WRITE32(scc, SIBA_CC_PMU_TABSEL, + updown[i].res); + SIBA_CC_WRITE32(scc, SIBA_CC_PMU_UPDNTM, + updown[i].updown); + } + } + if (depend) { + for (i = 0; i < depend_size; i++) { + SIBA_CC_WRITE32(scc, SIBA_CC_PMU_TABSEL, + depend[i].res); + switch (depend[i].task) { + case SIBA_CC_PMU_DEP_SET: + SIBA_CC_WRITE32(scc, SIBA_CC_PMU_DEPMSK, + depend[i].depend); + break; + case SIBA_CC_PMU_DEP_ADD: + SIBA_CC_SET32(scc, SIBA_CC_PMU_DEPMSK, + depend[i].depend); + break; + case SIBA_CC_PMU_DEP_REMOVE: + SIBA_CC_MASK32(scc, SIBA_CC_PMU_DEPMSK, + ~(depend[i].depend)); + break; + default: + KASSERT(0 == 1, + ("%s:%d: assertion failed", + __func__, __LINE__)); + } + } + } + + if (min) + SIBA_CC_WRITE32(scc, SIBA_CC_PMU_MINRES, min); + if (max) + SIBA_CC_WRITE32(scc, SIBA_CC_PMU_MAXRES, max); +} + +static void +siba_cc_power_init(struct siba_cc *scc) +{ + struct siba_softc *siba = scc->scc_dev->sd_bus; + int maxfreq; + + if (siba->siba_chipid == 0x4321) { + if (siba->siba_chiprev == 0) + SIBA_CC_WRITE32(scc, SIBA_CC_CHIPCTL, 0x3a4); + else if (siba->siba_chiprev == 1) + SIBA_CC_WRITE32(scc, SIBA_CC_CHIPCTL, 0xa4); + } + + if ((scc->scc_caps & SIBA_CC_CAPS_PWCTL) == 0) + return; + + if (scc->scc_dev->sd_id.sd_rev >= 10) + SIBA_CC_WRITE32(scc, SIBA_CC_CLKSYSCTL, + (SIBA_CC_READ32(scc, SIBA_CC_CLKSYSCTL) & + 0xffff) | 0x40000); + else { + maxfreq = siba_cc_clockfreq(scc, 1); + SIBA_CC_WRITE32(scc, SIBA_CC_PLLONDELAY, + (maxfreq * 150 + 999999) / 1000000); + SIBA_CC_WRITE32(scc, SIBA_CC_FREFSELDELAY, + (maxfreq * 15 + 999999) / 1000000); + } +} + +static void +siba_cc_powerup_delay(struct siba_cc *scc) +{ + struct siba_softc *siba = scc->scc_dev->sd_bus; + int min; + + if (siba->siba_type != SIBA_TYPE_PCI || + !(scc->scc_caps & SIBA_CC_CAPS_PWCTL)) + return; + + min = siba_cc_clockfreq(scc, 0); + scc->scc_powerup_delay = + (((SIBA_CC_READ32(scc, SIBA_CC_PLLONDELAY) + 2) * 1000000) + + (min - 1)) / min; +} + +static int +siba_cc_clockfreq(struct siba_cc *scc, int max) +{ + enum siba_clksrc src; + int div = 1, limit = 0; + + src = siba_cc_clksrc(scc); + if (scc->scc_dev->sd_id.sd_rev < 6) { + div = (src == SIBA_CC_CLKSRC_PCI) ? 64 : + (src == SIBA_CC_CLKSRC_CRYSTAL) ? 32 : 1; + KASSERT(div != 1, + ("%s: unknown clock %d", __func__, src)); + } else if (scc->scc_dev->sd_id.sd_rev < 10) { + switch (src) { + case SIBA_CC_CLKSRC_CRYSTAL: + case SIBA_CC_CLKSRC_PCI: + div = ((SIBA_CC_READ32(scc, SIBA_CC_CLKSLOW) >> 16) + + 1) * 4; + break; + case SIBA_CC_CLKSRC_LOWPW: + break; + } + } else + div = ((SIBA_CC_READ32(scc, SIBA_CC_CLKSYSCTL) >> 16) + 1) * 4; + + switch (src) { + case SIBA_CC_CLKSRC_CRYSTAL: + limit = (max) ? 20200000 : 19800000; + break; + case SIBA_CC_CLKSRC_LOWPW: + limit = (max) ? 43000 : 25000; + break; + case SIBA_CC_CLKSRC_PCI: + limit = (max) ? 34000000 : 25000000; + break; + } + + return (limit / div); +} + +static void +siba_cc_pmu1_pll0_init(struct siba_cc *scc, uint32_t freq) +{ + struct siba_dev_softc *sd = scc->scc_dev; + struct siba_softc *siba = sd->sd_bus; + const struct siba_cc_pmu1_plltab *e = NULL; + uint32_t bufsth = 0, pll, pmu; + unsigned int i; + + KASSERT(freq == 0, ("%s:%d: assertion vail", __func__, __LINE__)); + if (siba->siba_chipid == 0x4312) { + scc->scc_pmu.freq = 20000; + return; + } + + e = siba_cc_pmu1_plltab_find(SIBA_CC_PMU1_DEFAULT_FREQ); + KASSERT(e != NULL, ("%s:%d: assertion vail", __func__, __LINE__)); + scc->scc_pmu.freq = e->freq; + + pmu = SIBA_CC_READ32(scc, SIBA_CC_PMUCTL); + if (SIBA_CC_PMUCTL_XF_VAL(pmu) == e->xf) + return; + + DPRINTF(siba, SIBA_DEBUG_PLL, "change PLL value to %u.%03u MHz\n", + (e->freq / 1000), (e->freq % 1000)); + + /* turn PLL off */ + switch (siba->siba_chipid) { + case 0x4325: + bufsth = 0x222222; + SIBA_CC_MASK32(scc, SIBA_CC_PMU_MINRES, + ~((1 << SIBA_CC_PMU_4325_BBPLL_PWR) | + (1 << SIBA_CC_PMU_4325_HT))); + SIBA_CC_MASK32(scc, SIBA_CC_PMU_MAXRES, + ~((1 << SIBA_CC_PMU_4325_BBPLL_PWR) | + (1 << SIBA_CC_PMU_4325_HT))); + break; + default: + KASSERT(0 == 1, + ("%s:%d: assertion failed", __func__, __LINE__)); + } + for (i = 0; i < 1500; i++) { + if (!(SIBA_CC_READ32(scc, SIBA_CC_CLKCTLSTATUS) & + SIBA_CC_CLKCTLSTATUS_HT)) + break; + DELAY(10); + } + if (SIBA_CC_READ32(scc, SIBA_CC_CLKCTLSTATUS) & SIBA_CC_CLKCTLSTATUS_HT) + device_printf(siba->siba_dev, "failed to turn PLL off!\n"); + + pll = siba_cc_pll_read(scc, SIBA_CC_PMU1_PLL0); + pll &= ~(SIBA_CC_PMU1_PLL0_P1DIV | SIBA_CC_PMU1_PLL0_P2DIV); + pll |= ((uint32_t)e->p1div << 20) & SIBA_CC_PMU1_PLL0_P1DIV; + pll |= ((uint32_t)e->p2div << 24) & SIBA_CC_PMU1_PLL0_P2DIV; + siba_cc_pll_write(scc, SIBA_CC_PMU1_PLL0, pll); + + pll = siba_cc_pll_read(scc, SIBA_CC_PMU1_PLL2); + pll &= ~(SIBA_CC_PMU1_PLL2_NDIVINT | SIBA_CC_PMU1_PLL2_NDIVMODE); + pll |= ((uint32_t)e->ndiv_int << 20) & SIBA_CC_PMU1_PLL2_NDIVINT; + pll |= (1 << 17) & SIBA_CC_PMU1_PLL2_NDIVMODE; + siba_cc_pll_write(scc, SIBA_CC_PMU1_PLL2, pll); + + pll = siba_cc_pll_read(scc, SIBA_CC_PMU1_PLL3); + pll &= ~SIBA_CC_PMU1_PLL3_NDIVFRAC; + pll |= ((uint32_t)e->ndiv_frac << 0) & SIBA_CC_PMU1_PLL3_NDIVFRAC; + siba_cc_pll_write(scc, SIBA_CC_PMU1_PLL3, pll); + + if (bufsth) { + pll = siba_cc_pll_read(scc, SIBA_CC_PMU1_PLL5); + pll &= ~SIBA_CC_PMU1_PLL5_CLKDRV; + pll |= (bufsth << 8) & SIBA_CC_PMU1_PLL5_CLKDRV; + siba_cc_pll_write(scc, SIBA_CC_PMU1_PLL5, pll); + } + + pmu = SIBA_CC_READ32(scc, SIBA_CC_PMUCTL); + pmu &= ~(SIBA_CC_PMUCTL_ILP | SIBA_CC_PMUCTL_XF); + pmu |= ((((uint32_t)e->freq + 127) / 128 - 1) << 16) & + SIBA_CC_PMUCTL_ILP; + pmu |= ((uint32_t)e->xf << 2) & SIBA_CC_PMUCTL_XF; + SIBA_CC_WRITE32(scc, SIBA_CC_PMUCTL, pmu); +} + +static void +siba_cc_pmu0_pll0_init(struct siba_cc *scc, uint32_t xtalfreq) +{ + struct siba_dev_softc *sd = scc->scc_dev; + struct siba_softc *siba = sd->sd_bus; + const struct siba_cc_pmu0_plltab *e = NULL; + uint32_t pmu, tmp, pll; + unsigned int i; + + if ((siba->siba_chipid == 0x5354) && !xtalfreq) + xtalfreq = 25000; + if (xtalfreq) + e = siba_cc_pmu0_plltab_findentry(xtalfreq); + if (!e) + e = siba_cc_pmu0_plltab_findentry( + SIBA_CC_PMU0_DEFAULT_XTALFREQ); + KASSERT(e != NULL, ("%s:%d: fail", __func__, __LINE__)); + xtalfreq = e->freq; + scc->scc_pmu.freq = e->freq; + + pmu = SIBA_CC_READ32(scc, SIBA_CC_PMUCTL); + if (((pmu & SIBA_CC_PMUCTL_XF) >> 2) == e->xf) + return; + + DPRINTF(siba, SIBA_DEBUG_PLL, "change PLL value to %u.%03u mhz\n", + (xtalfreq / 1000), (xtalfreq % 1000)); + + KASSERT(siba->siba_chipid == 0x4328 || siba->siba_chipid == 0x5354, + ("%s:%d: fail", __func__, __LINE__)); + + switch (siba->siba_chipid) { + case 0x4328: + SIBA_CC_MASK32(scc, SIBA_CC_PMU_MINRES, + ~(1 << SIBA_CC_PMU_4328_BB_PLL_PU)); + SIBA_CC_MASK32(scc, SIBA_CC_PMU_MAXRES, + ~(1 << SIBA_CC_PMU_4328_BB_PLL_PU)); + break; + case 0x5354: + SIBA_CC_MASK32(scc, SIBA_CC_PMU_MINRES, + ~(1 << SIBA_CC_PMU_5354_BB_PLL_PU)); + SIBA_CC_MASK32(scc, SIBA_CC_PMU_MAXRES, + ~(1 << SIBA_CC_PMU_5354_BB_PLL_PU)); + break; + } + for (i = 1500; i; i--) { + tmp = SIBA_CC_READ32(scc, SIBA_CC_CLKCTLSTATUS); + if (!(tmp & SIBA_CC_CLKCTLSTATUS_HT)) + break; + DELAY(10); + } + tmp = SIBA_CC_READ32(scc, SIBA_CC_CLKCTLSTATUS); + if (tmp & SIBA_CC_CLKCTLSTATUS_HT) + device_printf(siba->siba_dev, "failed to turn PLL off!\n"); + + /* set PDIV */ + pll = siba_cc_pll_read(scc, SIBA_CC_PMU0_PLL0); + if (xtalfreq >= SIBA_CC_PMU0_PLL0_PDIV_FREQ) + pll |= SIBA_CC_PMU0_PLL0_PDIV_MSK; + else + pll &= ~SIBA_CC_PMU0_PLL0_PDIV_MSK; + siba_cc_pll_write(scc, SIBA_CC_PMU0_PLL0, pll); + + /* set WILD */ + pll = siba_cc_pll_read(scc, SIBA_CC_PMU0_PLL1); + pll &= ~(SIBA_CC_PMU0_PLL1_STOPMOD | SIBA_CC_PMU0_PLL1_IMSK | + SIBA_CC_PMU0_PLL1_FMSK); + pll |= ((uint32_t)e->wb_int << 28) & SIBA_CC_PMU0_PLL1_IMSK; + pll |= ((uint32_t)e->wb_frac << 8) & SIBA_CC_PMU0_PLL1_FMSK; + if (e->wb_frac == 0) + pll |= SIBA_CC_PMU0_PLL1_STOPMOD; + siba_cc_pll_write(scc, SIBA_CC_PMU0_PLL1, pll); + + /* set WILD */ + pll = siba_cc_pll_read(scc, SIBA_CC_PMU0_PLL2); + pll &= ~SIBA_CC_PMU0_PLL2_IMSKHI; + pll |= (((uint32_t)e->wb_int >> 4) << 0) & SIBA_CC_PMU0_PLL2_IMSKHI; + siba_cc_pll_write(scc, SIBA_CC_PMU0_PLL2, pll); + + /* set freq and divisor. */ + pmu = SIBA_CC_READ32(scc, SIBA_CC_PMUCTL); + pmu &= ~SIBA_CC_PMUCTL_ILP; + pmu |= (((xtalfreq + 127) / 128 - 1) << 16) & SIBA_CC_PMUCTL_ILP; + pmu &= ~SIBA_CC_PMUCTL_XF; + pmu |= ((uint32_t)e->xf << 2) & SIBA_CC_PMUCTL_XF; + SIBA_CC_WRITE32(scc, SIBA_CC_PMUCTL, pmu); +} + +static enum siba_clksrc +siba_cc_clksrc(struct siba_cc *scc) +{ + struct siba_dev_softc *sd = scc->scc_dev; + struct siba_softc *siba = sd->sd_bus; + + if (sd->sd_id.sd_rev < 6) { + if (siba->siba_type == SIBA_TYPE_PCI) { + if (pci_read_config(siba->siba_dev, SIBA_GPIO_OUT, 4) & + 0x10) + return (SIBA_CC_CLKSRC_PCI); + return (SIBA_CC_CLKSRC_CRYSTAL); + } + if (siba->siba_type == SIBA_TYPE_SSB || + siba->siba_type == SIBA_TYPE_PCMCIA) + return (SIBA_CC_CLKSRC_CRYSTAL); + } + if (sd->sd_id.sd_rev < 10) { + switch (SIBA_CC_READ32(scc, SIBA_CC_CLKSLOW) & 0x7) { + case 0: + return (SIBA_CC_CLKSRC_LOWPW); + case 1: + return (SIBA_CC_CLKSRC_CRYSTAL); + case 2: + return (SIBA_CC_CLKSRC_PCI); + default: + break; + } + } + + return (SIBA_CC_CLKSRC_CRYSTAL); +} + +static const struct siba_cc_pmu1_plltab * +siba_cc_pmu1_plltab_find(uint32_t crystalfreq) +{ + const struct siba_cc_pmu1_plltab *e; + unsigned int i; + + for (i = 0; i < N(siba_cc_pmu1_plltab); i++) { + e = &siba_cc_pmu1_plltab[i]; + if (crystalfreq == e->freq) + return (e); + } + + return (NULL); +} + +static uint32_t +siba_cc_pll_read(struct siba_cc *scc, uint32_t offset) +{ + + SIBA_CC_WRITE32(scc, SIBA_CC_PLLCTL_ADDR, offset); + return (SIBA_CC_READ32(scc, SIBA_CC_PLLCTL_DATA)); +} + +static void +siba_cc_pll_write(struct siba_cc *scc, uint32_t offset, uint32_t value) +{ + + SIBA_CC_WRITE32(scc, SIBA_CC_PLLCTL_ADDR, offset); + SIBA_CC_WRITE32(scc, SIBA_CC_PLLCTL_DATA, value); +} + +static const struct siba_cc_pmu0_plltab * +siba_cc_pmu0_plltab_findentry(uint32_t crystalfreq) +{ + const struct siba_cc_pmu0_plltab *e; + unsigned int i; + + for (i = 0; i < N(siba_cc_pmu0_plltab); i++) { + e = &siba_cc_pmu0_plltab[i]; + if (e->freq == crystalfreq) + return (e); + } + + return (NULL); +} + +static int +siba_pci_sprom(struct siba_softc *siba, struct siba_sprom *sprom) +{ + int error = ENOMEM; + uint16_t *buf; + + buf = malloc(SIBA_SPROMSIZE_R123 * sizeof(uint16_t), + M_DEVBUF, M_NOWAIT | M_ZERO); + if (buf == NULL) + return (ENOMEM); + siba_sprom_read(siba, buf, SIBA_SPROMSIZE_R123); + error = sprom_check_crc(buf, siba->siba_spromsize); + if (error) { + free(buf, M_DEVBUF); + buf = malloc(SIBA_SPROMSIZE_R4 * sizeof(uint16_t), + M_DEVBUF, M_NOWAIT | M_ZERO); + if (buf == NULL) + return (ENOMEM); + siba_sprom_read(siba, buf, SIBA_SPROMSIZE_R4); + error = sprom_check_crc(buf, siba->siba_spromsize); + if (error) + device_printf(siba->siba_dev, "warn: bad SPROM CRC\n"); + } + + bzero(sprom, sizeof(*sprom)); + + sprom->rev = buf[siba->siba_spromsize - 1] & 0x00FF; + DPRINTF(siba, SIBA_DEBUG_SPROM, "SPROM rev %d\n", + sprom->rev); + memset(sprom->mac_eth, 0xff, 6); + memset(sprom->mac_80211a, 0xff, 6); + if ((siba->siba_chipid & 0xff00) == 0x4400) { + sprom->rev = 1; + siba_sprom_r123(sprom, buf); + } else if (siba->siba_chipid == 0x4321) { + sprom->rev = 4; + siba_sprom_r45(sprom, buf); + } else { + switch (sprom->rev) { + case 1: + case 2: + case 3: + siba_sprom_r123(sprom, buf); + break; + case 4: + case 5: + siba_sprom_r45(sprom, buf); + break; + case 8: + siba_sprom_r8(sprom, buf); + break; + default: + device_printf(siba->siba_dev, + "unknown SPROM revision %d.\n", sprom->rev); + siba_sprom_r123(sprom, buf); + } + } + + if (sprom->bf_lo == 0xffff) + sprom->bf_lo = 0; + if (sprom->bf_hi == 0xffff) + sprom->bf_hi = 0; + + free(buf, M_DEVBUF); + return (error); +} + +static int +siba_sprom_read(struct siba_softc *siba, uint16_t *sprom, uint16_t len) +{ + int i; + + for (i = 0; i < len; i++) + sprom[i] = SIBA_READ_2(siba, SIBA_SPROM_BASE + (i * 2)); + + siba->siba_spromsize = len; + return (0); +} + +static int +sprom_check_crc(const uint16_t *sprom, size_t size) +{ + int word; + uint8_t crc0, crc1 = 0xff; + + crc0 = (sprom[size - 1] & SIBA_SPROM_REV_CRC) >> 8; + for (word = 0; word < size - 1; word++) { + crc1 = siba_crc8(crc1, sprom[word] & 0x00ff); + crc1 = siba_crc8(crc1, (sprom[word] & 0xff00) >> 8); + } + crc1 = siba_crc8(crc1, sprom[size - 1] & 0x00ff); + crc1 ^= 0xff; + + return ((crc0 != crc1) ? EPROTO : 0); +} + +static uint8_t +siba_crc8(uint8_t crc, uint8_t data) +{ + static const uint8_t ct[] = { + 0x00, 0xf7, 0xb9, 0x4e, 0x25, 0xd2, 0x9c, 0x6b, + 0x4a, 0xbd, 0xf3, 0x04, 0x6f, 0x98, 0xd6, 0x21, + 0x94, 0x63, 0x2d, 0xda, 0xb1, 0x46, 0x08, 0xff, + 0xde, 0x29, 0x67, 0x90, 0xfb, 0x0c, 0x42, 0xb5, + 0x7f, 0x88, 0xc6, 0x31, 0x5a, 0xad, 0xe3, 0x14, + 0x35, 0xc2, 0x8c, 0x7b, 0x10, 0xe7, 0xa9, 0x5e, + 0xeb, 0x1c, 0x52, 0xa5, 0xce, 0x39, 0x77, 0x80, + 0xa1, 0x56, 0x18, 0xef, 0x84, 0x73, 0x3d, 0xca, + 0xfe, 0x09, 0x47, 0xb0, 0xdb, 0x2c, 0x62, 0x95, + 0xb4, 0x43, 0x0d, 0xfa, 0x91, 0x66, 0x28, 0xdf, + 0x6a, 0x9d, 0xd3, 0x24, 0x4f, 0xb8, 0xf6, 0x01, + 0x20, 0xd7, 0x99, 0x6e, 0x05, 0xf2, 0xbc, 0x4b, + 0x81, 0x76, 0x38, 0xcf, 0xa4, 0x53, 0x1d, 0xea, + 0xcb, 0x3c, 0x72, 0x85, 0xee, 0x19, 0x57, 0xa0, + 0x15, 0xe2, 0xac, 0x5b, 0x30, 0xc7, 0x89, 0x7e, + 0x5f, 0xa8, 0xe6, 0x11, 0x7a, 0x8d, 0xc3, 0x34, + 0xab, 0x5c, 0x12, 0xe5, 0x8e, 0x79, 0x37, 0xc0, + 0xe1, 0x16, 0x58, 0xaf, 0xc4, 0x33, 0x7d, 0x8a, + 0x3f, 0xc8, 0x86, 0x71, 0x1a, 0xed, 0xa3, 0x54, + 0x75, 0x82, 0xcc, 0x3b, 0x50, 0xa7, 0xe9, 0x1e, + 0xd4, 0x23, 0x6d, 0x9a, 0xf1, 0x06, 0x48, 0xbf, + 0x9e, 0x69, 0x27, 0xd0, 0xbb, 0x4c, 0x02, 0xf5, + 0x40, 0xb7, 0xf9, 0x0e, 0x65, 0x92, 0xdc, 0x2b, + 0x0a, 0xfd, 0xb3, 0x44, 0x2f, 0xd8, 0x96, 0x61, + 0x55, 0xa2, 0xec, 0x1b, 0x70, 0x87, 0xc9, 0x3e, + 0x1f, 0xe8, 0xa6, 0x51, 0x3a, 0xcd, 0x83, 0x74, + 0xc1, 0x36, 0x78, 0x8f, 0xe4, 0x13, 0x5d, 0xaa, + 0x8b, 0x7c, 0x32, 0xc5, 0xae, 0x59, 0x17, 0xe0, + 0x2a, 0xdd, 0x93, 0x64, 0x0f, 0xf8, 0xb6, 0x41, + 0x60, 0x97, 0xd9, 0x2e, 0x45, 0xb2, 0xfc, 0x0b, + 0xbe, 0x49, 0x07, 0xf0, 0x9b, 0x6c, 0x22, 0xd5, + 0xf4, 0x03, 0x4d, 0xba, 0xd1, 0x26, 0x68, 0x9f, + }; + return (ct[crc ^ data]); +} + +#define SIBA_LOWEST_SET_BIT(__mask) ((((__mask) - 1) & (__mask)) ^ (__mask)) +#define SIBA_OFFSET(offset) \ + (((offset) - SIBA_SPROM_BASE) / sizeof(uint16_t)) +#define SIBA_SHIFTOUT_SUB(__x, __mask) \ + (((__x) & (__mask)) / SIBA_LOWEST_SET_BIT(__mask)) +#define SIBA_SHIFTOUT(_var, _offset, _mask) \ + out->_var = SIBA_SHIFTOUT_SUB(in[SIBA_OFFSET(_offset)], (_mask)) + +static void +siba_sprom_r123(struct siba_sprom *out, const uint16_t *in) +{ + int i; + uint16_t v; + int8_t gain; + uint16_t loc[3]; + + if (out->rev == 3) + loc[0] = SIBA_SPROM3_MAC_80211BG; + else { + loc[0] = SIBA_SPROM1_MAC_80211BG; + loc[1] = SIBA_SPROM1_MAC_ETH; + loc[2] = SIBA_SPROM1_MAC_80211A; + } + for (i = 0; i < 3; i++) { + v = in[SIBA_OFFSET(loc[0]) + i]; + *(((uint16_t *)out->mac_80211bg) + i) = htobe16(v); + } + if (out->rev < 3) { + for (i = 0; i < 3; i++) { + v = in[SIBA_OFFSET(loc[1]) + i]; + *(((uint16_t *)out->mac_eth) + i) = htobe16(v); + } + for (i = 0; i < 3; i++) { + v = in[SIBA_OFFSET(loc[2]) + i]; + *(((uint16_t *)out->mac_80211a) + i) = htobe16(v); + } + } + SIBA_SHIFTOUT(mii_eth0, SIBA_SPROM1_ETHPHY, + SIBA_SPROM1_ETHPHY_MII_ETH0); + SIBA_SHIFTOUT(mii_eth1, SIBA_SPROM1_ETHPHY, + SIBA_SPROM1_ETHPHY_MII_ETH1); + SIBA_SHIFTOUT(mdio_eth0, SIBA_SPROM1_ETHPHY, + SIBA_SPROM1_ETHPHY_MDIO_ETH0); + SIBA_SHIFTOUT(mdio_eth1, SIBA_SPROM1_ETHPHY, + SIBA_SPROM1_ETHPHY_MDIO_ETH1); + SIBA_SHIFTOUT(brev, SIBA_SPROM1_BOARDINFO, SIBA_SPROM1_BOARDINFO_BREV); + SIBA_SHIFTOUT(ccode, SIBA_SPROM1_BOARDINFO, + SIBA_SPROM1_BOARDINFO_CCODE); + SIBA_SHIFTOUT(ant_a, SIBA_SPROM1_BOARDINFO, SIBA_SPROM1_BOARDINFO_ANTA); + SIBA_SHIFTOUT(ant_bg, SIBA_SPROM1_BOARDINFO, + SIBA_SPROM1_BOARDINFO_ANTBG); + SIBA_SHIFTOUT(pa0b0, SIBA_SPROM1_PA0B0, 0xffff); + SIBA_SHIFTOUT(pa0b1, SIBA_SPROM1_PA0B1, 0xffff); + SIBA_SHIFTOUT(pa0b2, SIBA_SPROM1_PA0B2, 0xffff); + SIBA_SHIFTOUT(pa1b0, SIBA_SPROM1_PA1B0, 0xffff); + SIBA_SHIFTOUT(pa1b1, SIBA_SPROM1_PA1B1, 0xffff); + SIBA_SHIFTOUT(pa1b2, SIBA_SPROM1_PA1B2, 0xffff); + SIBA_SHIFTOUT(gpio0, SIBA_SPROM1_GPIOA, SIBA_SPROM1_GPIOA_P0); + SIBA_SHIFTOUT(gpio1, SIBA_SPROM1_GPIOA, SIBA_SPROM1_GPIOA_P1); + SIBA_SHIFTOUT(gpio2, SIBA_SPROM1_GPIOB, SIBA_SPROM1_GPIOB_P2); + SIBA_SHIFTOUT(gpio3, SIBA_SPROM1_GPIOB, SIBA_SPROM1_GPIOB_P3); + SIBA_SHIFTOUT(maxpwr_a, SIBA_SPROM1_MAXPWR, SIBA_SPROM1_MAXPWR_A); + SIBA_SHIFTOUT(maxpwr_bg, SIBA_SPROM1_MAXPWR, SIBA_SPROM1_MAXPWR_BG); + SIBA_SHIFTOUT(tssi_a, SIBA_SPROM1_TSSI, SIBA_SPROM1_TSSI_A); + SIBA_SHIFTOUT(tssi_bg, SIBA_SPROM1_TSSI, SIBA_SPROM1_TSSI_BG); + SIBA_SHIFTOUT(bf_lo, SIBA_SPROM1_BFLOW, 0xffff); + if (out->rev >= 2) + SIBA_SHIFTOUT(bf_hi, SIBA_SPROM2_BFHIGH, 0xffff); + + /* antenna gain */ + gain = siba_sprom_r123_antgain(out->rev, in, SIBA_SPROM1_AGAIN_BG, 0); + out->again.ghz24.a0 = out->again.ghz24.a1 = gain; + out->again.ghz24.a2 = out->again.ghz24.a3 = gain; + gain = siba_sprom_r123_antgain(out->rev, in, SIBA_SPROM1_AGAIN_A, 8); + out->again.ghz5.a0 = out->again.ghz5.a1 = gain; + out->again.ghz5.a2 = out->again.ghz5.a3 = gain; +} + +static void +siba_sprom_r45(struct siba_sprom *out, const uint16_t *in) +{ + int i; + uint16_t v; + uint16_t mac_80211bg_offset; + + if (out->rev == 4) + mac_80211bg_offset = SIBA_SPROM4_MAC_80211BG; + else + mac_80211bg_offset = SIBA_SPROM5_MAC_80211BG; + for (i = 0; i < 3; i++) { + v = in[SIBA_OFFSET(mac_80211bg_offset) + i]; + *(((uint16_t *)out->mac_80211bg) + i) = htobe16(v); + } + SIBA_SHIFTOUT(mii_eth0, SIBA_SPROM4_ETHPHY, SIBA_SPROM4_ETHPHY_ET0A); + SIBA_SHIFTOUT(mii_eth1, SIBA_SPROM4_ETHPHY, SIBA_SPROM4_ETHPHY_ET1A); + if (out->rev == 4) { + SIBA_SHIFTOUT(ccode, SIBA_SPROM4_CCODE, 0xffff); + SIBA_SHIFTOUT(bf_lo, SIBA_SPROM4_BFLOW, 0xffff); + SIBA_SHIFTOUT(bf_hi, SIBA_SPROM4_BFHIGH, 0xffff); + } else { + SIBA_SHIFTOUT(ccode, SIBA_SPROM5_CCODE, 0xffff); + SIBA_SHIFTOUT(bf_lo, SIBA_SPROM5_BFLOW, 0xffff); + SIBA_SHIFTOUT(bf_hi, SIBA_SPROM5_BFHIGH, 0xffff); + } + SIBA_SHIFTOUT(ant_a, SIBA_SPROM4_ANTAVAIL, SIBA_SPROM4_ANTAVAIL_A); + SIBA_SHIFTOUT(ant_bg, SIBA_SPROM4_ANTAVAIL, SIBA_SPROM4_ANTAVAIL_BG); + SIBA_SHIFTOUT(maxpwr_bg, SIBA_SPROM4_MAXP_BG, SIBA_SPROM4_MAXP_BG_MASK); + SIBA_SHIFTOUT(tssi_bg, SIBA_SPROM4_MAXP_BG, SIBA_SPROM4_TSSI_BG); + SIBA_SHIFTOUT(maxpwr_a, SIBA_SPROM4_MAXP_A, SIBA_SPROM4_MAXP_A_MASK); + SIBA_SHIFTOUT(tssi_a, SIBA_SPROM4_MAXP_A, SIBA_SPROM4_TSSI_A); + if (out->rev == 4) { + SIBA_SHIFTOUT(gpio0, SIBA_SPROM4_GPIOA, SIBA_SPROM4_GPIOA_P0); + SIBA_SHIFTOUT(gpio1, SIBA_SPROM4_GPIOA, SIBA_SPROM4_GPIOA_P1); + SIBA_SHIFTOUT(gpio2, SIBA_SPROM4_GPIOB, SIBA_SPROM4_GPIOB_P2); + SIBA_SHIFTOUT(gpio3, SIBA_SPROM4_GPIOB, SIBA_SPROM4_GPIOB_P3); + } else { + SIBA_SHIFTOUT(gpio0, SIBA_SPROM5_GPIOA, SIBA_SPROM5_GPIOA_P0); + SIBA_SHIFTOUT(gpio1, SIBA_SPROM5_GPIOA, SIBA_SPROM5_GPIOA_P1); + SIBA_SHIFTOUT(gpio2, SIBA_SPROM5_GPIOB, SIBA_SPROM5_GPIOB_P2); + SIBA_SHIFTOUT(gpio3, SIBA_SPROM5_GPIOB, SIBA_SPROM5_GPIOB_P3); + } + + /* antenna gain */ + SIBA_SHIFTOUT(again.ghz24.a0, SIBA_SPROM4_AGAIN01, SIBA_SPROM4_AGAIN0); + SIBA_SHIFTOUT(again.ghz24.a1, SIBA_SPROM4_AGAIN01, SIBA_SPROM4_AGAIN1); + SIBA_SHIFTOUT(again.ghz24.a2, SIBA_SPROM4_AGAIN23, SIBA_SPROM4_AGAIN2); + SIBA_SHIFTOUT(again.ghz24.a3, SIBA_SPROM4_AGAIN23, SIBA_SPROM4_AGAIN3); + bcopy(&out->again.ghz24, &out->again.ghz5, sizeof(out->again.ghz5)); +} + +static void +siba_sprom_r8(struct siba_sprom *out, const uint16_t *in) +{ + int i; + uint16_t v; + + for (i = 0; i < 3; i++) { + v = in[SIBA_OFFSET(SIBA_SPROM1_MAC_80211BG) + i]; + *(((uint16_t *)out->mac_80211bg) + i) = htobe16(v); + } + SIBA_SHIFTOUT(ccode, SIBA_SPROM8_CCODE, 0xffff); + SIBA_SHIFTOUT(bf_lo, SIBA_SPROM8_BFLOW, 0xffff); + SIBA_SHIFTOUT(bf_hi, SIBA_SPROM8_BFHIGH, 0xffff); + SIBA_SHIFTOUT(ant_a, SIBA_SPROM8_ANTAVAIL, SIBA_SPROM8_ANTAVAIL_A); + SIBA_SHIFTOUT(ant_bg, SIBA_SPROM8_ANTAVAIL, SIBA_SPROM8_ANTAVAIL_BG); + SIBA_SHIFTOUT(maxpwr_bg, SIBA_SPROM8_MAXP_BG, SIBA_SPROM8_MAXP_BG_MASK); + SIBA_SHIFTOUT(tssi_bg, SIBA_SPROM8_MAXP_BG, SIBA_SPROM8_TSSI_BG); + SIBA_SHIFTOUT(maxpwr_a, SIBA_SPROM8_MAXP_A, SIBA_SPROM8_MAXP_A_MASK); + SIBA_SHIFTOUT(tssi_a, SIBA_SPROM8_MAXP_A, SIBA_SPROM8_TSSI_A); + SIBA_SHIFTOUT(gpio0, SIBA_SPROM8_GPIOA, SIBA_SPROM8_GPIOA_P0); + SIBA_SHIFTOUT(gpio1, SIBA_SPROM8_GPIOA, SIBA_SPROM8_GPIOA_P1); + SIBA_SHIFTOUT(gpio2, SIBA_SPROM8_GPIOB, SIBA_SPROM8_GPIOB_P2); + SIBA_SHIFTOUT(gpio3, SIBA_SPROM8_GPIOB, SIBA_SPROM8_GPIOB_P3); + + /* antenna gain */ + SIBA_SHIFTOUT(again.ghz24.a0, SIBA_SPROM8_AGAIN01, SIBA_SPROM8_AGAIN0); + SIBA_SHIFTOUT(again.ghz24.a1, SIBA_SPROM8_AGAIN01, SIBA_SPROM8_AGAIN1); + SIBA_SHIFTOUT(again.ghz24.a2, SIBA_SPROM8_AGAIN23, SIBA_SPROM8_AGAIN2); + SIBA_SHIFTOUT(again.ghz24.a3, SIBA_SPROM8_AGAIN23, SIBA_SPROM8_AGAIN3); + bcopy(&out->again.ghz24, &out->again.ghz5, sizeof(out->again.ghz5)); +} + +static int8_t +siba_sprom_r123_antgain(uint8_t sprom_revision, const uint16_t *in, + uint16_t mask, uint16_t shift) +{ + uint16_t v; + uint8_t gain; + + v = in[SIBA_OFFSET(SIBA_SPROM1_AGAIN)]; + gain = (v & mask) >> shift; + gain = (gain == 0xff) ? 2 : (sprom_revision == 1) ? gain << 2 : + ((gain & 0xc0) >> 6) | ((gain & 0x3f) << 2); + + return ((int8_t)gain); +} + +#undef SIBA_LOWEST_SET_BIT +#undef SIBA_OFFSET +#undef SIBA_SHIFTOUT_SUB +#undef SIBA_SHIFTOUT + +int +siba_powerdown(struct siba_softc *siba) +{ + struct siba_cc *scc; + + if (siba->siba_type == SIBA_TYPE_SSB) + return (0); + + scc = &siba->siba_cc; + if (!scc->scc_dev || scc->scc_dev->sd_id.sd_rev < 5) + return (0); + siba_cc_clock(scc, SIBA_CLOCK_SLOW); + siba_pci_gpio(siba, SIBA_GPIO_CRYSTAL | SIBA_GPIO_PLL, 0); + return (0); +} + +static void +siba_pcicore_init(struct siba_pci *spc) +{ + struct siba_dev_softc *sd = spc->spc_dev; + struct siba_softc *siba; + + if (sd == NULL) + return; + + siba = sd->sd_bus; + if (!siba_dev_isup(sd)) + siba_dev_up(sd, 0); + + KASSERT(spc->spc_hostmode == 0, + ("%s:%d: hostmode", __func__, __LINE__)); + /* disable PCI interrupt */ + siba_write_4(spc->spc_dev, SIBA_INTR_MASK, 0); +} + +int +siba_dev_isup(struct siba_dev_softc *sd) +{ + uint32_t reject, val; + + reject = siba_tmslow_reject_bitmask(sd); + val = siba_read_4(sd, SIBA_TGSLOW); + val &= SIBA_TGSLOW_CLOCK | SIBA_TGSLOW_RESET | reject; + + return (val == SIBA_TGSLOW_CLOCK); +} + +void +siba_dev_up(struct siba_dev_softc *sd, uint32_t flags) +{ + uint32_t val; + + siba_dev_down(sd, flags); + siba_write_4(sd, SIBA_TGSLOW, SIBA_TGSLOW_RESET | SIBA_TGSLOW_CLOCK | + SIBA_TGSLOW_FGC | flags); + siba_read_4(sd, SIBA_TGSLOW); + DELAY(1); + + if (siba_read_4(sd, SIBA_TGSHIGH) & SIBA_TGSHIGH_SERR) + siba_write_4(sd, SIBA_TGSHIGH, 0); + + val = siba_read_4(sd, SIBA_IAS); + if (val & (SIBA_IAS_INBAND_ERR | SIBA_IAS_TIMEOUT)) { + val &= ~(SIBA_IAS_INBAND_ERR | SIBA_IAS_TIMEOUT); + siba_write_4(sd, SIBA_IAS, val); + } + + siba_write_4(sd, SIBA_TGSLOW, + SIBA_TGSLOW_CLOCK | SIBA_TGSLOW_FGC | flags); + siba_read_4(sd, SIBA_TGSLOW); + DELAY(1); + + siba_write_4(sd, SIBA_TGSLOW, SIBA_TGSLOW_CLOCK | flags); + siba_read_4(sd, SIBA_TGSLOW); + DELAY(1); +} + +static uint32_t +siba_tmslow_reject_bitmask(struct siba_dev_softc *sd) +{ + uint32_t rev = siba_read_4(sd, SIBA_IDLOW) & SIBA_IDLOW_SSBREV; + + switch (rev) { + case SIBA_IDLOW_SSBREV_22: + return (SIBA_TGSLOW_REJECT_22); + case SIBA_IDLOW_SSBREV_23: + return (SIBA_TGSLOW_REJECT_23); + case SIBA_IDLOW_SSBREV_24: + case SIBA_IDLOW_SSBREV_25: + case SIBA_IDLOW_SSBREV_26: + case SIBA_IDLOW_SSBREV_27: + return (SIBA_TGSLOW_REJECT_23); + default: + KASSERT(0 == 1, + ("%s:%d: unknown backplane rev %#x\n", + __func__, __LINE__, rev)); + } + return (SIBA_TGSLOW_REJECT_22 | SIBA_TGSLOW_REJECT_23); +} + +void +siba_dev_down(struct siba_dev_softc *sd, uint32_t flags) +{ + struct siba_softc *siba = sd->sd_bus; + uint32_t reject, val; + int i; + + if (siba_read_4(sd, SIBA_TGSLOW) & SIBA_TGSLOW_RESET) + return; + + reject = siba_tmslow_reject_bitmask(sd); + siba_write_4(sd, SIBA_TGSLOW, reject | SIBA_TGSLOW_CLOCK); + + for (i = 0; i < 1000; i++) { + val = siba_read_4(sd, SIBA_TGSLOW); + if (val & reject) + break; + DELAY(10); + } + if ((val & reject) == 0) { + device_printf(siba->siba_dev, "timeout (bit %#x reg %#x)\n", + reject, SIBA_TGSLOW); + } + for (i = 0; i < 1000; i++) { + val = siba_read_4(sd, SIBA_TGSHIGH); + if (!(val & SIBA_TGSHIGH_BUSY)) + break; + DELAY(10); + } + if ((val & SIBA_TGSHIGH_BUSY) != 0) { + device_printf(siba->siba_dev, "timeout (bit %#x reg %#x)\n", + SIBA_TGSHIGH_BUSY, SIBA_TGSHIGH); + } + + siba_write_4(sd, SIBA_TGSLOW, SIBA_TGSLOW_FGC | SIBA_TGSLOW_CLOCK | + reject | SIBA_TGSLOW_RESET | flags); + siba_read_4(sd, SIBA_TGSLOW); + DELAY(1); + siba_write_4(sd, SIBA_TGSLOW, reject | SIBA_TGSLOW_RESET | flags); + siba_read_4(sd, SIBA_TGSLOW); + DELAY(1); +} + +static void +siba_pcicore_setup(struct siba_pci *spc, struct siba_dev_softc *sd) +{ + struct siba_dev_softc *psd = spc->spc_dev; + struct siba_softc *siba = psd->sd_bus; + uint32_t tmp; + + if (psd->sd_id.sd_device == SIBA_DEVID_PCI) { + siba_pcicore_write_4(spc, SIBA_PCICORE_SBTOPCI2, + siba_pcicore_read_4(spc, SIBA_PCICORE_SBTOPCI2) | + SIBA_PCICORE_SBTOPCI_PREF | SIBA_PCICORE_SBTOPCI_BURST); + + if (psd->sd_id.sd_rev < 5) { + tmp = siba_read_4(psd, SIBA_IMCFGLO); + tmp &= ~SIBA_IMCFGLO_SERTO; + tmp = (tmp | 2) & ~SIBA_IMCFGLO_REQTO; + tmp |= 3 << 4 /* SIBA_IMCFGLO_REQTO_SHIFT */; + siba_write_4(psd, SIBA_IMCFGLO, tmp); + + /* broadcast value */ + sd = (siba->siba_cc.scc_dev != NULL) ? + siba->siba_cc.scc_dev : siba->siba_pci.spc_dev; + if (sd != NULL) { + siba_write_4(sd, SIBA_PCICORE_BCAST_ADDR, + 0xfd8); + siba_read_4(sd, SIBA_PCICORE_BCAST_ADDR); + siba_write_4(sd, SIBA_PCICORE_BCAST_DATA, 0); + siba_read_4(sd, SIBA_PCICORE_BCAST_DATA); + } + } else if (psd->sd_id.sd_rev >= 11) { + tmp = siba_pcicore_read_4(spc, SIBA_PCICORE_SBTOPCI2); + tmp |= SIBA_PCICORE_SBTOPCI_MRM; + siba_pcicore_write_4(spc, SIBA_PCICORE_SBTOPCI2, tmp); + } + } else { + KASSERT(psd->sd_id.sd_device == SIBA_DEVID_PCIE, ("only PCIE")); + if ((psd->sd_id.sd_rev == 0) || (psd->sd_id.sd_rev == 1)) + siba_pcie_write(spc, 0x4, + siba_pcie_read(spc, 0x4) | 0x8); + if (psd->sd_id.sd_rev == 0) { + siba_pcie_mdio_write(spc, 0x1f, 2, 0x8128); /* Timer */ + siba_pcie_mdio_write(spc, 0x1f, 6, 0x0100); /* CDR */ + siba_pcie_mdio_write(spc, 0x1f, 7, 0x1466); /* CDR BW */ + } else if (psd->sd_id.sd_rev == 1) + siba_pcie_write(spc, 0x100, + siba_pcie_read(spc, 0x100) | 0x40); + } + spc->spc_inited = 1; +} + +void +siba_pcicore_intr(struct siba_pci *spc, struct siba_dev_softc *sd) +{ + struct siba_dev_softc *psd = spc->spc_dev; + struct siba_softc *siba; + uint32_t tmp; + + if (sd->sd_bus->siba_type != SIBA_TYPE_PCI || !psd) + return; + + siba = psd->sd_bus; + /* enable interrupts */ + if (siba->siba_dev != NULL && + (psd->sd_id.sd_rev >= 6 || psd->sd_id.sd_device == SIBA_DEVID_PCIE)) { + tmp = pci_read_config(siba->siba_dev, SIBA_IRQMASK, 4); + tmp |= (1 << sd->sd_coreidx) << 8; + pci_write_config(siba->siba_dev, SIBA_IRQMASK, tmp, 4); + } else { + tmp = siba_read_4(sd, SIBA_TPS); + tmp &= SIBA_TPS_BPFLAG; + siba_write_4(psd, SIBA_INTR_MASK, + siba_read_4(psd, SIBA_INTR_MASK) | (1 << tmp)); + } + + /* setup PCIcore */ + if (spc->spc_inited == 0) + siba_pcicore_setup(spc, sd); +} + +static uint32_t +siba_pcicore_read_4(struct siba_pci *spc, uint16_t offset) +{ + + return (siba_read_4(spc->spc_dev, offset)); +} + +static void +siba_pcicore_write_4(struct siba_pci *spc, uint16_t offset, uint32_t value) +{ + + siba_write_4(spc->spc_dev, offset, value); +} + +static uint32_t +siba_pcie_read(struct siba_pci *spc, uint32_t address) +{ + + siba_pcicore_write_4(spc, 0x130, address); + return (siba_pcicore_read_4(spc, 0x134)); +} + +static void +siba_pcie_write(struct siba_pci *spc, uint32_t address, uint32_t data) +{ + + siba_pcicore_write_4(spc, 0x130, address); + siba_pcicore_write_4(spc, 0x134, data); +} + +static void +siba_pcie_mdio_write(struct siba_pci *spc, uint8_t device, uint8_t address, + uint16_t data) +{ + int i; + + siba_pcicore_write_4(spc, SIBA_PCICORE_MDIO_CTL, 0x80 | 0x2); + siba_pcicore_write_4(spc, SIBA_PCICORE_MDIO_DATA, + (1 << 30) | (1 << 28) | + ((uint32_t)device << 22) | ((uint32_t)address << 18) | + (1 << 17) | data); + DELAY(10); + for (i = 0; i < 10; i++) { + if (siba_pcicore_read_4(spc, SIBA_PCICORE_MDIO_CTL) & 0x100) + break; + DELAY(1000); + } + siba_pcicore_write_4(spc, SIBA_PCICORE_MDIO_CTL, 0); +} + +uint32_t +siba_dma_translation(struct siba_dev_softc *sd) +{ + + KASSERT(sd->sd_bus->siba_type == SIBA_TYPE_PCI, + ("unsupported bustype %d\n", sd->sd_bus->siba_type)); + return (SIBA_PCI_DMA); +} + +void +siba_barrier(struct siba_dev_softc *sd, int flags) +{ + struct siba_softc *siba = sd->sd_bus; + + SIBA_BARRIER(siba, flags); +} + +/* + * Attach it as child. + */ +device_t +siba_add_child(device_t dev, struct siba_softc *siba, int order, + const char *name, int unit) +{ + struct siba_dev_softc *sd; + device_t child; + int idx = 0, i; + + child = device_add_child(dev, name, unit); + if (child == NULL) + return (NULL); + + siba_powerup(siba, 0); + siba_pcicore_init(&siba->siba_pci); + siba_powerdown(siba); + + for (i = 0; i < siba->siba_ndevs; i++) { + sd = &(siba->siba_devs[i]); + + if (sd->sd_id.sd_device != SIBA_DEVID_80211) { + DPRINTF(siba, SIBA_DEBUG_CORE, + "skip to register coreid %#x (%s)\n", + sd->sd_id.sd_device, + siba_core_name(sd->sd_id.sd_device)); + continue; + } + + DPRINTF(siba, SIBA_DEBUG_CORE, + "siba: attaching coreid %#x (%s) idx %d\n", + sd->sd_id.sd_device, + siba_core_name(sd->sd_id.sd_device), idx); + + KASSERT(sd->sd_id.sd_device == SIBA_DEVID_80211, + ("%s:%d: SIBA_DEVID_80211 is only supportted currently.", + __func__, __LINE__)); + + device_set_ivars(child, sd); + device_probe_and_attach(child); + idx++; + } + return (child); +} + +static void +siba_cc_suspend(struct siba_cc *scc) +{ + + siba_cc_clock(scc, SIBA_CLOCK_SLOW); +} + +static void +siba_cc_resume(struct siba_cc *scc) +{ + + siba_cc_power_init(scc); + siba_cc_clock(scc, SIBA_CLOCK_FAST); +} + +int +siba_core_suspend(struct siba_softc *siba) +{ + + siba_cc_suspend(&siba->siba_cc); + siba_pci_gpio(siba, SIBA_GPIO_CRYSTAL | SIBA_GPIO_PLL, 0); + return (0); +} + +int +siba_core_resume(struct siba_softc *siba) +{ + + siba->siba_pci.spc_inited = 0; + siba->siba_curdev = NULL; + + siba_powerup(siba, 0); + /* XXX setup H/W for PCMCIA??? */ + siba_cc_resume(&siba->siba_cc); + siba_powerdown(siba); + + return (0); +} diff --git a/sys/dev/siba/siba_ids.h b/sys/dev/siba/siba_ids.h index c7acd20..b5aaf34 100644 --- a/sys/dev/siba/siba_ids.h +++ b/sys/dev/siba/siba_ids.h @@ -39,23 +39,45 @@ struct siba_devid { uint8_t sd_rev; char *sd_desc; }; +#define SIBA_DEV(_vendor, _cid, _rev, _msg) \ + { SIBA_VID_##_vendor, SIBA_DEVID_##_cid, _rev, _msg } /* * Device IDs */ -#define SIBA_DEVID_ANY 0xffff -#define SIBA_DEVID_CHIPCOMMON 0x0800 -#define SIBA_DEVID_INSIDELINE 0x0801 -#define SIBA_DEVID_SDRAM 0x0803 -#define SIBA_DEVID_PCI 0x0804 -#define SIBA_DEVID_MIPS 0x0805 -#define SIBA_DEVID_ETHERNET 0x0806 -#define SIBA_DEVID_MODEM 0x0807 -#define SIBA_DEVID_USB 0x0808 -#define SIBA_DEVID_IPSEC 0x080b -#define SIBA_DEVID_SDRAMDDR 0x080f -#define SIBA_DEVID_EXTIF 0x0811 -#define SIBA_DEVID_MIPS_3302 0x0816 +#define SIBA_DEVID_ANY 0xffff +#define SIBA_DEVID_CHIPCOMMON 0x800 +#define SIBA_DEVID_ILINE20 0x801 +#define SIBA_DEVID_SDRAM 0x803 +#define SIBA_DEVID_PCI 0x804 +#define SIBA_DEVID_MIPS 0x805 +#define SIBA_DEVID_ETHERNET 0x806 +#define SIBA_DEVID_MODEM 0x807 +#define SIBA_DEVID_USB11_HOSTDEV 0x808 +#define SIBA_DEVID_ADSL 0x809 +#define SIBA_DEVID_ILINE100 0x80a +#define SIBA_DEVID_IPSEC 0x80b +#define SIBA_DEVID_PCMCIA 0x80d +#define SIBA_DEVID_INTERNAL_MEM 0x80e +#define SIBA_DEVID_SDRAMDDR 0x80f +#define SIBA_DEVID_EXTIF 0x811 +#define SIBA_DEVID_80211 0x812 +#define SIBA_DEVID_MIPS_3302 0x816 +#define SIBA_DEVID_USB11_HOST 0x817 +#define SIBA_DEVID_USB11_DEV 0x818 +#define SIBA_DEVID_USB20_HOST 0x819 +#define SIBA_DEVID_USB20_DEV 0x81a +#define SIBA_DEVID_SDIO_HOST 0x81b +#define SIBA_DEVID_ROBOSWITCH 0x81c +#define SIBA_DEVID_PARA_ATA 0x81d +#define SIBA_DEVID_SATA_XORDMA 0x81e +#define SIBA_DEVID_ETHERNET_GBIT 0x81f +#define SIBA_DEVID_PCIE 0x820 +#define SIBA_DEVID_MIMO_PHY 0x821 +#define SIBA_DEVID_SRAM_CTRLR 0x822 +#define SIBA_DEVID_MINI_MACPHY 0x823 +#define SIBA_DEVID_ARM_1176 0x824 +#define SIBA_DEVID_ARM_7TDMI 0x825 /* * Vendor IDs diff --git a/sys/dev/siba/siba_pcib.c b/sys/dev/siba/siba_pcib.c index d43f54c..5175aa7 100644 --- a/sys/dev/siba/siba_pcib.c +++ b/sys/dev/siba/siba_pcib.c @@ -55,9 +55,9 @@ __FBSDID("$FreeBSD$"); #include "pcib_if.h" -#include -#include #include +#include +#include #include #ifndef MIPS_MEM_RID @@ -79,10 +79,6 @@ __FBSDID("$FreeBSD$"); #define SBPCI_CFGBASE 0x0C000000 #define SBPCI_CFGSIZE 0x01000000 -#define SBPCI_SBTOPCI0 0x100 -#define SBPCI_SBTOPCI1 0x104 -#define SBPCI_SBTOPCI2 0x108 - /* * TODO: implement type 1 config space access (ie beyond bus 0) * we may need to tweak the windows to do this @@ -187,9 +183,12 @@ siba_pcib_attach(device_t dev) * XXX we need to be able to do type 1 too. * we probably don't need to be able to do i/o cycles. */ - SBPCI_WRITE_4(sc, SBPCI_SBTOPCI0, 1); /* I/O read/write window */ - SBPCI_WRITE_4(sc, SBPCI_SBTOPCI1, 2); /* type 0 configuration only */ - SBPCI_WRITE_4(sc, SBPCI_SBTOPCI2, 1 << 30); /* memory only */ + + /* I/O read/write window */ + SBPCI_WRITE_4(sc, SIBA_PCICORE_SBTOPCI0, 1); + /* type 0 configuration only */ + SBPCI_WRITE_4(sc, SIBA_PCICORE_SBTOPCI1, 2); + SBPCI_WRITE_4(sc, SIBA_PCICORE_SBTOPCI2, 1 << 30); /* memory only */ DELAY(500); /* XXX resource managers */ @@ -365,7 +364,7 @@ siba_pcib_read_config(device_t dev, u_int bus, u_int slot, u_int func, /* * The configuration tag on the broadcom is weird. */ - SBPCI_WRITE_4(sc, SBPCI_SBTOPCI1, 2); /* XXX again??? */ + SBPCI_WRITE_4(sc, SIBA_PCICORE_SBTOPCI1, 2); /* XXX again??? */ cfgtag = ((1 << slot) << 16) | (func << 8); cfgaddr = SBPCI_CFGBASE | cfgtag | (reg & ~3); diff --git a/sys/dev/siba/sibareg.h b/sys/dev/siba/sibareg.h index dc1b7f7..9aa9e7c 100644 --- a/sys/dev/siba/sibareg.h +++ b/sys/dev/siba/sibareg.h @@ -34,40 +34,383 @@ #ifndef _SIBA_SIBAREG_H_ #define _SIBA_SIBAREG_H_ +#define PCI_DEVICE_ID_BCM4401 0x4401 +#define PCI_DEVICE_ID_BCM4401B0 0x4402 +#define PCI_DEVICE_ID_BCM4401B1 0x170c +#define SIBA_PCIR_BAR PCIR_BAR(0) +#define SIBA_CCID_BCM4710 0x4710 +#define SIBA_CCID_BCM4704 0x4704 +#define SIBA_CCID_SENTRY5 0x5365 + +/* + * ChipCommon registers. + */ +#define SIBA_CC_CHIPID 0x0000 +#define SIBA_CC_IDMASK 0x0000ffff +#define SIBA_CC_ID(id) (id & SIBA_CC_IDMASK) +#define SIBA_CC_REVMASK 0x000f0000 +#define SIBA_CC_REVSHIFT 16 +#define SIBA_CC_REV(id) \ + ((id & SIBA_CC_REVMASK) >> SIBA_CC_REVSHIFT) +#define SIBA_CC_PKGMASK 0x00F00000 +#define SIBA_CC_PKGSHIFT 20 +#define SIBA_CC_PKG(id) \ + ((id & SIBA_CC_PKGMASK) >> SIBA_CC_PKGSHIFT) +#define SIBA_CC_NCORESMASK 0x0F000000 +#define SIBA_CC_NCORESSHIFT 24 +#define SIBA_CC_NCORES(id) \ + ((id & SIBA_CC_NCORESMASK) >> SIBA_CC_NCORESSHIFT) +#define SIBA_CC_CAPS 0x0004 +#define SIBA_CC_CAPS_PWCTL 0x00040000 +#define SIBA_CC_CAPS_PMU 0x10000000 /* PMU (rev >= 20) */ +#define SIBA_CC_CHIPCTL 0x0028 /* rev >= 11 */ +#define SIBA_CC_CHIPSTAT 0x002C /* rev >= 11 */ +#define SIBA_CC_BCAST_ADDR 0x0050 /* Broadcast Address */ +#define SIBA_CC_BCAST_DATA 0x0054 /* Broadcast Data */ +#define SIBA_CC_PLLONDELAY 0x00B0 /* Rev >= 4 only */ +#define SIBA_CC_FREFSELDELAY 0x00B4 /* Rev >= 4 only */ +#define SIBA_CC_CLKSLOW 0x00b8 /* 6 <= Rev <= 9 only */ +#define SIBA_CC_CLKSLOW_SRC 0x00000007 +#define SIBA_CC_CLKSLOW_SRC_CRYSTAL 0x00000001 +#define SIBA_CC_CLKSLOW_FSLOW 0x00000800 +#define SIBA_CC_CLKSLOW_IPLL 0x00001000 +#define SIBA_CC_CLKSLOW_ENXTAL 0x00002000 +#define SIBA_CC_CLKSYSCTL 0x00C0 /* Rev >= 3 only */ +#define SIBA_CC_CLKCTLSTATUS 0x01e0 +#define SIBA_CC_CLKCTLSTATUS_HT 0x00010000 +#define SIBA_CC_UART0 0x0300 /* offset of UART0 */ +#define SIBA_CC_UART1 0x0400 /* offset of UART1 */ +#define SIBA_CC_PMUCTL 0x0600 /* PMU control */ +#define SIBA_CC_PMUCTL_ILP 0xffff0000 /* mask */ +#define SIBA_CC_PMUCTL_NOILP 0x00000200 +#define SIBA_CC_PMUCTL_XF 0x0000007c /* crystal freq */ +#define SIBA_CC_PMUCTL_XF_VAL(id) ((id & 0x0000007c) >> 2) +#define SIBA_CC_PMUCAPS 0x0604 +#define SIBA_CC_PMUCAPS_REV 0x000000ff +#define SIBA_CC_PMU_MINRES 0x0618 +#define SIBA_CC_PMU_MAXRES 0x061c +#define SIBA_CC_PMU_TABSEL 0x0620 +#define SIBA_CC_PMU_DEPMSK 0x0624 +#define SIBA_CC_PMU_UPDNTM 0x0628 +#define SIBA_CC_PLLCTL_ADDR 0x0660 +#define SIBA_CC_PLLCTL_DATA 0x0664 + +#define SIBA_CC_PMU0_PLL0 0 +#define SIBA_CC_PMU0_PLL0_PDIV_MSK 0x00000001 +#define SIBA_CC_PMU0_PLL0_PDIV_FREQ 25000 +#define SIBA_CC_PMU0_PLL1 1 +#define SIBA_CC_PMU0_PLL1_IMSK 0xf0000000 +#define SIBA_CC_PMU0_PLL1_FMSK 0x0fffff00 +#define SIBA_CC_PMU0_PLL1_STOPMOD 0x00000040 +#define SIBA_CC_PMU0_PLL2 2 +#define SIBA_CC_PMU0_PLL2_IMSKHI 0x0000000f +#define SIBA_CC_PMU1_PLL0 0 +#define SIBA_CC_PMU1_PLL0_P1DIV 0x00f00000 +#define SIBA_CC_PMU1_PLL0_P2DIV 0x0f000000 +#define SIBA_CC_PMU1_PLL2 2 +#define SIBA_CC_PMU1_PLL2_NDIVMODE 0x000e0000 +#define SIBA_CC_PMU1_PLL2_NDIVINT 0x1ff00000 +#define SIBA_CC_PMU1_PLL3 3 +#define SIBA_CC_PMU1_PLL3_NDIVFRAC 0x00ffffff +#define SIBA_CC_PMU1_PLL5 5 +#define SIBA_CC_PMU1_PLL5_CLKDRV 0xffffff00 + +#define SIBA_CC_PMU0_DEFAULT_XTALFREQ 20000 +#define SIBA_CC_PMU1_DEFAULT_FREQ 15360 + +#define SIBA_CC_PMU1_PLLTAB_ENTRY \ +{ \ + { 12000, 1, 3, 22, 0x9, 0xffffef }, \ + { 13000, 2, 1, 6, 0xb, 0x483483 }, \ + { 14400, 3, 1, 10, 0xa, 0x1c71c7 }, \ + { 15360, 4, 1, 5, 0xb, 0x755555 }, \ + { 16200, 5, 1, 10, 0x5, 0x6e9e06 }, \ + { 16800, 6, 1, 10, 0x5, 0x3cf3cf }, \ + { 19200, 7, 1, 9, 0x5, 0x17b425 }, \ + { 19800, 8, 1, 11, 0x4, 0xa57eb }, \ + { 20000, 9, 1, 11, 0x4, 0 }, \ + { 24000, 10, 3, 11, 0xa, 0 }, \ + { 25000, 11, 5, 16, 0xb, 0 }, \ + { 26000, 12, 1, 2, 0x10, 0xec4ec4 }, \ + { 30000, 13, 3, 8, 0xb, 0 }, \ + { 38400, 14, 1, 5, 0x4, 0x955555 }, \ + { 40000, 15, 1, 2, 0xb, 0 } \ +} + +#define SIBA_CC_PMU0_PLLTAB_ENTRY \ +{ \ + { 12000, 1, 73, 349525, }, { 13000, 2, 67, 725937, }, \ + { 14400, 3, 61, 116508, }, { 15360, 4, 57, 305834, }, \ + { 16200, 5, 54, 336579, }, { 16800, 6, 52, 399457, }, \ + { 19200, 7, 45, 873813, }, { 19800, 8, 44, 466033, }, \ + { 20000, 9, 44, 0, }, { 25000, 10, 70, 419430, }, \ + { 26000, 11, 67, 725937, }, { 30000, 12, 58, 699050, }, \ + { 38400, 13, 45, 873813, }, { 40000, 14, 45, 0, }, \ +} + +#define SIBA_CC_PMU_4325_BURST 1 +#define SIBA_CC_PMU_4325_CLBURST 3 +#define SIBA_CC_PMU_4325_LN 10 +#define SIBA_CC_PMU_4325_CRYSTAL 13 +#define SIBA_CC_PMU_4325_RX_PWR 15 +#define SIBA_CC_PMU_4325_TX_PWR 16 +#define SIBA_CC_PMU_4325_LOGEN_PWR 18 +#define SIBA_CC_PMU_4325_AFE_PWR 19 +#define SIBA_CC_PMU_4325_BBPLL_PWR 20 +#define SIBA_CC_PMU_4325_HT 21 +#define SIBA_CC_PMU_4328_EXT_SWITCH_PWM 0 +#define SIBA_CC_PMU_4328_BB_SWITCH_PWM 1 +#define SIBA_CC_PMU_4328_BB_SWITCH_BURST 2 +#define SIBA_CC_PMU_4328_BB_EXT_SWITCH_BURST 3 +#define SIBA_CC_PMU_4328_ILP_REQUEST 4 +#define SIBA_CC_PMU_4328_RADSWITCH_PWM 5 /* radio switch */ +#define SIBA_CC_PMU_4328_RADSWITCH_BURST 6 +#define SIBA_CC_PMU_4328_ROM_SWITCH 7 +#define SIBA_CC_PMU_4328_PA_REF 8 +#define SIBA_CC_PMU_4328_RADIO 9 +#define SIBA_CC_PMU_4328_AFE 10 +#define SIBA_CC_PMU_4328_PLL 11 +#define SIBA_CC_PMU_4328_BG_FILTBYP 12 +#define SIBA_CC_PMU_4328_TX_FILTBYP 13 +#define SIBA_CC_PMU_4328_RX_FILTBYP 14 +#define SIBA_CC_PMU_4328_CRYSTAL_PU 15 +#define SIBA_CC_PMU_4328_CRYSTAL_EN 16 +#define SIBA_CC_PMU_4328_BB_PLL_FILTBYP 17 +#define SIBA_CC_PMU_4328_RF_PLL_FILTBYP 18 +#define SIBA_CC_PMU_4328_BB_PLL_PU 19 +#define SIBA_CC_PMU_5354_BB_PLL_PU 19 + +#define SIBA_CC_PMU_4325_RES_UPDOWN \ +{ \ + { SIBA_CC_PMU_4325_CRYSTAL, 0x1501 } \ +} + +#define SIBA_CC_PMU_4325_RES_DEPEND \ +{ \ + { SIBA_CC_PMU_4325_HT, SIBA_CC_PMU_DEP_ADD, \ + ((1 << SIBA_CC_PMU_4325_RX_PWR) | \ + (1 << SIBA_CC_PMU_4325_TX_PWR) | \ + (1 << SIBA_CC_PMU_4325_LOGEN_PWR) | \ + (1 << SIBA_CC_PMU_4325_AFE_PWR)) } \ +} + +#define SIBA_CC_PMU_4328_RES_UPDOWN \ +{ \ + { SIBA_CC_PMU_4328_EXT_SWITCH_PWM, 0x0101 }, \ + { SIBA_CC_PMU_4328_BB_SWITCH_PWM, 0x1f01 }, \ + { SIBA_CC_PMU_4328_BB_SWITCH_BURST, 0x010f }, \ + { SIBA_CC_PMU_4328_BB_EXT_SWITCH_BURST, 0x0101 }, \ + { SIBA_CC_PMU_4328_ILP_REQUEST, 0x0202 }, \ + { SIBA_CC_PMU_4328_RADSWITCH_PWM, 0x0f01 }, \ + { SIBA_CC_PMU_4328_RADSWITCH_BURST, 0x0f01 }, \ + { SIBA_CC_PMU_4328_ROM_SWITCH, 0x0101 }, \ + { SIBA_CC_PMU_4328_PA_REF, 0x0f01 }, \ + { SIBA_CC_PMU_4328_RADIO, 0x0f01 }, \ + { SIBA_CC_PMU_4328_AFE, 0x0f01 }, \ + { SIBA_CC_PMU_4328_PLL, 0x0f01 }, \ + { SIBA_CC_PMU_4328_BG_FILTBYP, 0x0101 }, \ + { SIBA_CC_PMU_4328_TX_FILTBYP, 0x0101 }, \ + { SIBA_CC_PMU_4328_RX_FILTBYP, 0x0101 }, \ + { SIBA_CC_PMU_4328_CRYSTAL_PU, 0x0101 }, \ + { SIBA_CC_PMU_4328_CRYSTAL_EN, 0xa001 }, \ + { SIBA_CC_PMU_4328_BB_PLL_FILTBYP, 0x0101 }, \ + { SIBA_CC_PMU_4328_RF_PLL_FILTBYP, 0x0101 }, \ + { SIBA_CC_PMU_4328_BB_PLL_PU, 0x0701 }, \ +} + +#define SIBA_CC_PMU_4328_RES_DEPEND \ +{ \ + { SIBA_CC_PMU_4328_ILP_REQUEST, SIBA_CC_PMU_DEP_SET, \ + ((1 << SIBA_CC_PMU_4328_EXT_SWITCH_PWM) | \ + (1 << SIBA_CC_PMU_4328_BB_SWITCH_PWM)) }, \ +} + +#define SIBA_CC_CHST_4325_PMUTOP_2B 0x00000200 + +#define SIBA_BAR0 0x80 +#define SIBA_IRQMASK 0x94 +#define SIBA_GPIO_IN 0xb0 +#define SIBA_GPIO_OUT 0xb4 +#define SIBA_GPIO_OUT_EN 0xb8 +#define SIBA_GPIO_CRYSTAL 0x40 +#define SIBA_GPIO_PLL 0x80 + +#define SIBA_REGWIN(x) \ + (SIBA_ENUM_START + ((x) * SIBA_CORE_LEN)) #define SIBA_CORE_LEN 0x00001000 /* Size of cfg per core */ #define SIBA_CFG_END 0x00010000 /* Upper bound of cfg space */ #define SIBA_MAX_CORES (SIBA_CFG_END/SIBA_CORE_LEN) /* #max cores */ +#define SIBA_ENUM_START 0x18000000U +#define SIBA_ENUM_END 0x18010000U -/* offset of high ID register */ -#define SIBA_CORE_IDLO 0x00000ff8 -#define SIBA_CORE_IDHI 0x00000ffc +#define SIBA_DMA_TRANSLATION_MASK 0xc0000000 -/* - * Offsets of ChipCommon core registers. - * XXX: move to siba_cc - */ -#define SIBA_CC_UART0 0x00000300 /* offset of UART0 */ -#define SIBA_CC_UART1 0x00000400 /* offset of UART1 */ - -#define SIBA_CC_CCID 0x0000 -#define SIBA_CC_IDMASK 0x0000FFFF -#define SIBA_CC_REVMASK 0x000F0000 -#define SIBA_CC_REVSHIFT 16 -#define SIBA_CC_PACKMASK 0x00F00000 -#define SIBA_CC_PACKSHIFT 20 -#define SIBA_CC_NRCORESMASK 0x0F000000 -#define SIBA_CC_NRCORESSHIFT 24 - -#define SIBA_IDHIGH_RCLO 0x0000000F /* Revision Code (low part) */ -#define SIBA_IDHIGH_CC 0x00008FF0 /* Core Code */ -#define SIBA_IDHIGH_CC_SHIFT 4 -#define SIBA_IDHIGH_RCHI 0x00007000 /* Revision Code (high part) */ -#define SIBA_IDHIGH_RCHI_SHIFT 8 -#define SIBA_IDHIGH_VC 0xFFFF0000 /* Vendor Code */ -#define SIBA_IDHIGH_VC_SHIFT 16 - -#define SIBA_CCID_BCM4710 0x4710 -#define SIBA_CCID_BCM4704 0x4704 -#define SIBA_CCID_SENTRY5 0x5365 +#define SIBA_PCI_DMA 0x40000000U +#define SIBA_TPS 0x0f18 +#define SIBA_TPS_BPFLAG 0x0000003f +#define SIBA_IAS 0x0f90 /* Initiator Agent State */ +#define SIBA_IAS_INBAND_ERR 0x00020000 +#define SIBA_IAS_TIMEOUT 0x00040000 +#define SIBA_INTR_MASK 0x0f94 +#define SIBA_TGSLOW 0x0f98 +#define SIBA_TGSLOW_RESET 0x00000001 /* target state low */ +#define SIBA_TGSLOW_REJECT_22 0x00000002 +#define SIBA_TGSLOW_REJECT_23 0x00000004 +#define SIBA_TGSLOW_CLOCK 0x00010000 +#define SIBA_TGSLOW_FGC 0x00020000 +#define SIBA_TGSHIGH 0x0f9c +#define SIBA_TGSHIGH_SERR 0x00000001 +#define SIBA_TGSHIGH_BUSY 0x00000004 +#define SIBA_TGSHIGH_DMA64 0x10000000 +#define SIBA_IMCFGLO 0x0fa8 +#define SIBA_IMCFGLO_SERTO 0x00000007 +#define SIBA_IMCFGLO_REQTO 0x00000070 +#define SIBA_IDLOW 0x0ff8 +#define SIBA_IDLOW_SSBREV 0xf0000000 +#define SIBA_IDLOW_SSBREV_22 0x00000000 +#define SIBA_IDLOW_SSBREV_23 0x10000000 +#define SIBA_IDLOW_SSBREV_24 0x40000000 +#define SIBA_IDLOW_SSBREV_25 0x50000000 +#define SIBA_IDLOW_SSBREV_26 0x60000000 +#define SIBA_IDLOW_SSBREV_27 0x70000000 +#define SIBA_IDHIGH 0x0ffc +#define SIBA_IDHIGH_CORECODEMASK 0x00008FF0 /* Core Code */ +#define SIBA_IDHIGH_CORECODE_SHIFT 4 +#define SIBA_IDHIGH_CORECODE(id) \ + ((id & SIBA_IDHIGH_CORECODEMASK) >> SIBA_IDHIGH_CORECODE_SHIFT) +/* Revision Code (low part) */ +#define SIBA_IDHIGH_REVLO 0x0000000f +/* Revision Code (high part) */ +#define SIBA_IDHIGH_REVHI 0x00007000 +#define SIBA_IDHIGH_REVHI_SHIFT 8 +#define SIBA_IDHIGH_REV(id) \ + ((id & SIBA_IDHIGH_REVLO) | ((id & SIBA_IDHIGH_REVHI) >> \ + SIBA_IDHIGH_REVHI_SHIFT)) +#define SIBA_IDHIGH_VENDORMASK 0xFFFF0000 /* Vendor Code */ +#define SIBA_IDHIGH_VENDOR_SHIFT 16 +#define SIBA_IDHIGH_VENDOR(id) \ + ((id & SIBA_IDHIGH_VENDORMASK) >> SIBA_IDHIGH_VENDOR_SHIFT) + +#define SIBA_SPROMSIZE_R123 64 +#define SIBA_SPROMSIZE_R4 220 +#define SIBA_SPROM_BASE 0x1000 +#define SIBA_SPROM_REV_CRC 0xff00 +#define SIBA_SPROM1_MAC_80211BG 0x1048 +#define SIBA_SPROM1_MAC_ETH 0x104e +#define SIBA_SPROM1_MAC_80211A 0x1054 +#define SIBA_SPROM1_ETHPHY 0x105a +#define SIBA_SPROM1_ETHPHY_MII_ETH0 0x001f +#define SIBA_SPROM1_ETHPHY_MII_ETH1 0x03e0 +#define SIBA_SPROM1_ETHPHY_MDIO_ETH0 (1 << 14) +#define SIBA_SPROM1_ETHPHY_MDIO_ETH1 (1 << 15) +#define SIBA_SPROM1_BOARDINFO 0x105c +#define SIBA_SPROM1_BOARDINFO_BREV 0x00ff +#define SIBA_SPROM1_BOARDINFO_CCODE 0x0f00 +#define SIBA_SPROM1_BOARDINFO_ANTBG 0x3000 +#define SIBA_SPROM1_BOARDINFO_ANTA 0xc000 +#define SIBA_SPROM1_PA0B0 0x105e +#define SIBA_SPROM1_PA0B1 0x1060 +#define SIBA_SPROM1_PA0B2 0x1062 +#define SIBA_SPROM1_GPIOA 0x1064 +#define SIBA_SPROM1_GPIOA_P0 0x00ff +#define SIBA_SPROM1_GPIOA_P1 0xff00 +#define SIBA_SPROM1_GPIOB 0x1066 +#define SIBA_SPROM1_GPIOB_P2 0x00ff +#define SIBA_SPROM1_GPIOB_P3 0xff00 +#define SIBA_SPROM1_MAXPWR 0x1068 +#define SIBA_SPROM1_MAXPWR_BG 0x00ff +#define SIBA_SPROM1_MAXPWR_A 0xff00 +#define SIBA_SPROM1_PA1B0 0x106a +#define SIBA_SPROM1_PA1B1 0x106c +#define SIBA_SPROM1_PA1B2 0x106e +#define SIBA_SPROM1_TSSI 0x1070 +#define SIBA_SPROM1_TSSI_BG 0x00ff +#define SIBA_SPROM1_TSSI_A 0xff00 +#define SIBA_SPROM1_BFLOW 0x1072 +#define SIBA_SPROM1_AGAIN 0x1074 +#define SIBA_SPROM1_AGAIN_BG 0x00ff +#define SIBA_SPROM1_AGAIN_A 0xff00 +#define SIBA_SPROM2_BFHIGH 0x1038 +#define SIBA_SPROM3_MAC_80211BG 0x104a +#define SIBA_SPROM4_MAC_80211BG 0x104c +#define SIBA_SPROM4_ETHPHY 0x105a +#define SIBA_SPROM4_ETHPHY_ET0A 0x001f +#define SIBA_SPROM4_ETHPHY_ET1A 0x03e0 +#define SIBA_SPROM4_CCODE 0x1052 +#define SIBA_SPROM4_ANTAVAIL 0x105d +#define SIBA_SPROM4_ANTAVAIL_A 0x00ff +#define SIBA_SPROM4_ANTAVAIL_BG 0xff00 +#define SIBA_SPROM4_BFLOW 0x1044 +#define SIBA_SPROM4_AGAIN01 0x105e +#define SIBA_SPROM4_AGAIN0 0x00ff +#define SIBA_SPROM4_AGAIN1 0xff00 +#define SIBA_SPROM4_AGAIN23 0x1060 +#define SIBA_SPROM4_AGAIN2 0x00ff +#define SIBA_SPROM4_AGAIN3 0xff00 +#define SIBA_SPROM4_BFHIGH 0x1046 +#define SIBA_SPROM4_MAXP_BG 0x1080 +#define SIBA_SPROM4_MAXP_BG_MASK 0x00ff +#define SIBA_SPROM4_TSSI_BG 0xff00 +#define SIBA_SPROM4_MAXP_A 0x108a +#define SIBA_SPROM4_MAXP_A_MASK 0x00ff +#define SIBA_SPROM4_TSSI_A 0xff00 +#define SIBA_SPROM4_GPIOA 0x1056 +#define SIBA_SPROM4_GPIOA_P0 0x00ff +#define SIBA_SPROM4_GPIOA_P1 0xff00 +#define SIBA_SPROM4_GPIOB 0x1058 +#define SIBA_SPROM4_GPIOB_P2 0x00ff +#define SIBA_SPROM4_GPIOB_P3 0xff00 +#define SIBA_SPROM5_BFLOW 0x104a +#define SIBA_SPROM5_BFHIGH 0x104c +#define SIBA_SPROM5_MAC_80211BG 0x1052 +#define SIBA_SPROM5_CCODE 0x1044 +#define SIBA_SPROM5_GPIOA 0x1076 +#define SIBA_SPROM5_GPIOA_P0 0x00ff +#define SIBA_SPROM5_GPIOA_P1 0xff00 +#define SIBA_SPROM5_GPIOB 0x1078 +#define SIBA_SPROM5_GPIOB_P2 0x00ff +#define SIBA_SPROM5_GPIOB_P3 0xff00 +#define SIBA_SPROM8_BFLOW 0x1084 +#define SIBA_SPROM8_BFHIGH 0x1086 +#define SIBA_SPROM8_CCODE 0x1092 +#define SIBA_SPROM8_ANTAVAIL 0x109c +#define SIBA_SPROM8_ANTAVAIL_A 0xff00 +#define SIBA_SPROM8_ANTAVAIL_BG 0x00ff +#define SIBA_SPROM8_AGAIN01 0x109e +#define SIBA_SPROM8_AGAIN0 0x00ff +#define SIBA_SPROM8_AGAIN1 0xff00 +#define SIBA_SPROM8_AGAIN23 0x10a0 +#define SIBA_SPROM8_AGAIN2 0x00ff +#define SIBA_SPROM8_AGAIN3 0xff00 +#define SIBA_SPROM8_GPIOA 0x1096 +#define SIBA_SPROM8_GPIOA_P0 0x00ff +#define SIBA_SPROM8_GPIOA_P1 0xff00 +#define SIBA_SPROM8_GPIOB 0x1098 +#define SIBA_SPROM8_GPIOB_P2 0x00ff +#define SIBA_SPROM8_GPIOB_P3 0xff00 +#define SIBA_SPROM8_MAXP_BG 0x10c0 +#define SIBA_SPROM8_MAXP_BG_MASK 0x00ff +#define SIBA_SPROM8_TSSI_BG 0xff00 +#define SIBA_SPROM8_MAXP_A 0x10c8 +#define SIBA_SPROM8_MAXP_A_MASK 0x00ff +#define SIBA_SPROM8_TSSI_A 0xff00 + +#define SIBA_BOARDVENDOR_DELL 0x1028 +#define SIBA_BOARDVENDOR_BCM 0x14e4 +#define SIBA_BOARD_BCM4309G 0x0421 +#define SIBA_BOARD_MP4318 0x044a +#define SIBA_BOARD_BU4306 0x0416 +#define SIBA_BOARD_BU4309 0x040a + +#define SIBA_PCICORE_BCAST_ADDR SIBA_CC_BCAST_ADDR +#define SIBA_PCICORE_BCAST_DATA SIBA_CC_BCAST_DATA +#define SIBA_PCICORE_SBTOPCI0 0x0100 +#define SIBA_PCICORE_SBTOPCI1 0x0104 +#define SIBA_PCICORE_SBTOPCI2 0x0108 +#define SIBA_PCICORE_MDIO_CTL 0x0128 +#define SIBA_PCICORE_MDIO_DATA 0x012c +#define SIBA_PCICORE_SBTOPCI_PREF 0x00000004 +#define SIBA_PCICORE_SBTOPCI_BURST 0x00000008 +#define SIBA_PCICORE_SBTOPCI_MRM 0x00000020 #endif /* _SIBA_SIBAREG_H_ */ diff --git a/sys/dev/siba/sibavar.h b/sys/dev/siba/sibavar.h index f9c231b..93d4ff7 100644 --- a/sys/dev/siba/sibavar.h +++ b/sys/dev/siba/sibavar.h @@ -31,62 +31,341 @@ #include -struct siba_softc { - device_t sc_dev; /* Device ID */ - struct resource *sc_mem; /* Memory window on nexus */ - - bus_space_tag_t sc_bt; - bus_space_handle_t sc_bh; - bus_addr_t sc_maddr; - bus_size_t sc_msize; +struct siba_softc; +struct siba_dev_softc; - uint8_t sc_ncores; +enum siba_device_ivars { + SIBA_IVAR_VENDOR, + SIBA_IVAR_DEVICE, + SIBA_IVAR_REVID, + SIBA_IVAR_CORE_INDEX }; -struct siba_devinfo { - struct resource_list sdi_rl; - /*devhandle_t sdi_devhandle; XXX*/ - /*struct rman sdi_intr_rman;*/ +#define SIBA_ACCESSOR(var, ivar, type) \ + __BUS_ACCESSOR(siba, var, SIBA, ivar, type) - /* Accessors are needed for ivars below. */ - uint16_t sdi_vid; - uint16_t sdi_devid; - uint8_t sdi_rev; - uint8_t sdi_idx; /* core index on bus */ - uint8_t sdi_irq; /* TODO */ +SIBA_ACCESSOR(vendor, VENDOR, uint16_t) +SIBA_ACCESSOR(device, DEVICE, uint16_t) +SIBA_ACCESSOR(revid, REVID, uint8_t) +SIBA_ACCESSOR(core_index, CORE_INDEX, uint8_t) + +#undef SIBA_ACCESSOR + +/* XXX just for SPROM1? */ +enum { + SIBA_CCODE_WORLD, + SIBA_CCODE_THAILAND, + SIBA_CCODE_ISRAEL, + SIBA_CCODE_JORDAN, + SIBA_CCODE_CHINA, + SIBA_CCODE_JAPAN, + SIBA_CCODE_USA_CANADA_ANZ, + SIBA_CCODE_EUROPE, + SIBA_CCODE_USA_LOW, + SIBA_CCODE_JAPAN_HIGH, + SIBA_CCODE_ALL, + SIBA_CCODE_NONE, }; -#define siba_read_2(sc, core, reg) \ - bus_space_read_2((sc)->sc_bt, (sc)->sc_bh, \ +#define siba_mips_read_2(sc, core, reg) \ + bus_space_read_2((sc)->siba_mem_bt, (sc)->siba_mem_bh, \ (core * SIBA_CORE_LEN) + (reg)) -#define siba_read_4(sc, core, reg) \ - bus_space_read_4((sc)->sc_bt, (sc)->sc_bh, \ +#define siba_mips_read_4(sc, core, reg) \ + bus_space_read_4((sc)->siba_mem_bt, (sc)->siba_mem_bh, \ (core * SIBA_CORE_LEN) + (reg)) -#define siba_write_2(sc, core, reg, val) \ - bus_space_write_2((sc)->sc_bt, (sc)->sc_bh, \ +#define siba_mips_write_2(sc, core, reg, val) \ + bus_space_write_2((sc)->siba_mem_bt, (sc)->siba_mem_bh, \ (core * SIBA_CORE_LEN) + (reg), (val)) -#define siba_write_4(sc, core, reg, val) \ - bus_space_write_4((sc)->sc_bt, (sc)->sc_bh, \ +#define siba_mips_write_4(sc, core, reg, val) \ + bus_space_write_4((sc)->siba_mem_bt, (sc)->siba_mem_bh, \ (core * SIBA_CORE_LEN) + (reg), (val)) -enum siba_device_ivars { - SIBA_IVAR_VENDOR, - SIBA_IVAR_DEVICE, - SIBA_IVAR_REVID, - SIBA_IVAR_CORE_INDEX +#define SIBA_READ_4(siba, reg) \ + bus_space_read_4((siba)->siba_mem_bt, (siba)->siba_mem_bh, (reg)) +#define SIBA_READ_2(siba, reg) \ + bus_space_read_2((siba)->siba_mem_bt, (siba)->siba_mem_bh, (reg)) +#define SIBA_READ_MULTI_1(siba, reg, addr, count) \ + bus_space_read_multi_1((siba)->siba_mem_bt, (siba)->siba_mem_bh,\ + (reg), (addr), (count)) +#define SIBA_READ_MULTI_2(siba, reg, addr, count) \ + bus_space_read_multi_2((siba)->siba_mem_bt, (siba)->siba_mem_bh,\ + (reg), (addr), (count)) +#define SIBA_READ_MULTI_4(siba, reg, addr, count) \ + bus_space_read_multi_4((siba)->siba_mem_bt, (siba)->siba_mem_bh,\ + (reg), (addr), (count)) + +#define SIBA_WRITE_4(siba, reg, val) \ + bus_space_write_4((siba)->siba_mem_bt, (siba)->siba_mem_bh, \ + (reg), (val)) +#define SIBA_WRITE_2(siba, reg, val) \ + bus_space_write_2((siba)->siba_mem_bt, (siba)->siba_mem_bh, \ + (reg), (val)) +#define SIBA_WRITE_MULTI_1(siba, reg, addr, count) \ + bus_space_write_multi_1((siba)->siba_mem_bt, (siba)->siba_mem_bh,\ + (reg), (addr), (count)) +#define SIBA_WRITE_MULTI_2(siba, reg, addr, count) \ + bus_space_write_multi_2((siba)->siba_mem_bt, (siba)->siba_mem_bh,\ + (reg), (addr), (count)) +#define SIBA_WRITE_MULTI_4(siba, reg, addr, count) \ + bus_space_write_multi_4((siba)->siba_mem_bt, (siba)->siba_mem_bh,\ + (reg), (addr), (count)) + +#define SIBA_BARRIER(siba, flags) \ + bus_space_barrier((siba)->siba_mem_bt, (siba)->siba_mem_bh, (0),\ + (0), (flags)) + +#define SIBA_SETBITS_4(siba, reg, bits) \ + SIBA_WRITE_4((siba), (reg), SIBA_READ_4((siba), (reg)) | (bits)) +#define SIBA_SETBITS_2(siba, reg, bits) \ + SIBA_WRITE_2((siba), (reg), SIBA_READ_2((siba), (reg)) | (bits)) + +#define SIBA_FILT_SETBITS_4(siba, reg, filt, bits) \ + SIBA_WRITE_4((siba), (reg), (SIBA_READ_4((siba), \ + (reg)) & (filt)) | (bits)) +#define SIBA_FILT_SETBITS_2(siba, reg, filt, bits) \ + SIBA_WRITE_2((siba), (reg), (SIBA_READ_2((siba), \ + (reg)) & (filt)) | (bits)) + +#define SIBA_CLRBITS_4(siba, reg, bits) \ + SIBA_WRITE_4((siba), (reg), SIBA_READ_4((siba), (reg)) & ~(bits)) +#define SIBA_CLRBITS_2(siba, reg, bits) \ + SIBA_WRITE_2((siba), (reg), SIBA_READ_2((siba), (reg)) & ~(bits)) + +#define SIBA_CC_READ32(scc, offset) \ + siba_read_4((scc)->scc_dev, offset) +#define SIBA_CC_WRITE32(scc, offset, val) \ + siba_write_4((scc)->scc_dev, offset, val) +#define SIBA_CC_MASK32(scc, offset, mask) \ + SIBA_CC_WRITE32(scc, offset, SIBA_CC_READ32(scc, offset) & (mask)) +#define SIBA_CC_SET32(scc, offset, set) \ + SIBA_CC_WRITE32(scc, offset, SIBA_CC_READ32(scc, offset) | (set)) +#define SIBA_CC_MASKSET32(scc, offset, mask, set) \ + SIBA_CC_WRITE32(scc, offset, \ + (SIBA_CC_READ32(scc, offset) & (mask)) | (set)) + +enum siba_type { + SIBA_TYPE_SSB, + SIBA_TYPE_PCI, + SIBA_TYPE_PCMCIA, }; -#define SIBA_ACCESSOR(var, ivar, type) \ - __BUS_ACCESSOR(siba, var, SIBA, ivar, type) +enum siba_clock { + SIBA_CLOCK_DYNAMIC, + SIBA_CLOCK_SLOW, + SIBA_CLOCK_FAST, +}; -SIBA_ACCESSOR(vendor, VENDOR, uint16_t) -SIBA_ACCESSOR(device, DEVICE, uint16_t) -SIBA_ACCESSOR(revid, REVID, uint8_t) -SIBA_ACCESSOR(core_index, CORE_INDEX, uint8_t) +enum siba_clksrc { + SIBA_CC_CLKSRC_PCI, + SIBA_CC_CLKSRC_CRYSTAL, + SIBA_CC_CLKSRC_LOWPW, +}; -#undef SIBA_ACCESSOR +struct siba_cc_pmu0_plltab { + uint16_t freq; /* in kHz.*/ + uint8_t xf; /* crystal frequency */ + uint8_t wb_int; + uint32_t wb_frac; +}; + +struct siba_cc_pmu1_plltab { + uint16_t freq; + uint8_t xf; + uint8_t p1div; + uint8_t p2div; + uint8_t ndiv_int; + uint32_t ndiv_frac; +}; + +struct siba_cc_pmu_res_updown { + uint8_t res; + uint16_t updown; +}; + +#define SIBA_CC_PMU_DEP_SET 1 +#define SIBA_CC_PMU_DEP_ADD 2 +#define SIBA_CC_PMU_DEP_REMOVE 3 + +struct siba_cc_pmu_res_depend { + uint8_t res; + uint8_t task; + uint32_t depend; +}; + +struct siba_sprom { + uint8_t rev; /* revision */ + uint8_t mac_80211bg[6]; /* address for 802.11b/g */ + uint8_t mac_eth[6]; /* address for Ethernet */ + uint8_t mac_80211a[6]; /* address for 802.11a */ + uint8_t mii_eth0; /* MII address for eth0 */ + uint8_t mii_eth1; /* MII address for eth1 */ + uint8_t mdio_eth0; /* MDIO for eth0 */ + uint8_t mdio_eth1; /* MDIO for eth1 */ + uint8_t brev; /* board revision */ + uint8_t ccode; /* Country Code */ + uint8_t ant_a; /* A-PHY antenna */ + uint8_t ant_bg; /* B/G-PHY antenna */ + uint16_t pa0b0; + uint16_t pa0b1; + uint16_t pa0b2; + uint16_t pa1b0; + uint16_t pa1b1; + uint16_t pa1b2; + uint8_t gpio0; + uint8_t gpio1; + uint8_t gpio2; + uint8_t gpio3; + uint16_t maxpwr_a; /* A-PHY Max Power */ + uint16_t maxpwr_bg; /* BG-PHY Max Power */ + uint8_t tssi_a; /* Idle TSSI */ + uint8_t tssi_bg; /* Idle TSSI */ + uint16_t bf_lo; /* boardflags */ + uint16_t bf_hi; /* boardflags */ + struct { + struct { + int8_t a0, a1, a2, a3; + } ghz24; + struct { + int8_t a0, a1, a2, a3; + } ghz5; + } again; /* antenna gain */ +}; + +struct siba_cc_pmu { + uint8_t rev; /* PMU rev */ + uint32_t freq; /* crystal freq in kHz */ +}; + +struct siba_cc { + struct siba_dev_softc *scc_dev; + uint32_t scc_caps; + struct siba_cc_pmu scc_pmu; + uint16_t scc_powerup_delay; +}; + +struct siba_pci { + struct siba_dev_softc *spc_dev; + uint8_t spc_inited; + uint8_t spc_hostmode; +}; + +struct siba_bus_ops { + uint16_t (*read_2)(struct siba_dev_softc *, + uint16_t); + uint32_t (*read_4)(struct siba_dev_softc *, + uint16_t); + void (*write_2)(struct siba_dev_softc *, + uint16_t, uint16_t); + void (*write_4)(struct siba_dev_softc *, + uint16_t, uint32_t); + void (*read_multi_1)(struct siba_dev_softc *, + void *, size_t, uint16_t); + void (*read_multi_2)(struct siba_dev_softc *, + void *, size_t, uint16_t); + void (*read_multi_4)(struct siba_dev_softc *, + void *, size_t, uint16_t); + void (*write_multi_1)(struct siba_dev_softc *, + const void *, size_t, uint16_t); + void (*write_multi_2)(struct siba_dev_softc *, + const void *, size_t, uint16_t); + void (*write_multi_4)(struct siba_dev_softc *, + const void *, size_t, uint16_t); +}; + +struct siba_dev_softc { + struct siba_softc *sd_bus; + struct siba_devid sd_id; + const struct siba_bus_ops *sd_ops; + + uint8_t sd_coreidx; +}; + +struct siba_devinfo { + struct resource_list sdi_rl; + /*devhandle_t sdi_devhandle; XXX*/ + /*struct rman sdi_intr_rman;*/ + + /* Accessors are needed for ivars below. */ + uint16_t sdi_vid; + uint16_t sdi_devid; + uint8_t sdi_rev; + uint8_t sdi_idx; /* core index on bus */ + uint8_t sdi_irq; /* TODO */ +}; + +struct siba_softc { + /* + * common variables which used for siba(4) bus and siba_bwn bridge. + */ + device_t siba_dev; /* Device ID */ + struct resource *siba_mem_res; + bus_space_tag_t siba_mem_bt; + bus_space_handle_t siba_mem_bh; + bus_addr_t siba_maddr; + bus_size_t siba_msize; + uint8_t siba_ncores; + + /* + * the following variables are only used for siba_bwn bridge. + */ + + enum siba_type siba_type; + int siba_invalid; + + struct siba_dev_softc *siba_curdev; /* only for PCI */ + struct siba_dev_softc siba_devs[SIBA_MAX_CORES]; + int siba_ndevs; + + uint16_t siba_pci_vid; + uint16_t siba_pci_did; + uint16_t siba_pci_subvid; + uint16_t siba_pci_subdid; + int siba_mem_rid; + + uint16_t siba_chipid; /* for CORE 0 */ + uint16_t siba_chiprev; + uint8_t siba_chippkg; + + struct siba_cc siba_cc; /* ChipCommon */ + struct siba_pci siba_pci; /* PCI-core */ + const struct siba_bus_ops *siba_ops; + + /* board informations */ + uint16_t siba_board_vendor; + uint16_t siba_board_type; + uint16_t siba_board_rev; + struct siba_sprom siba_sprom; /* SPROM */ + uint16_t siba_spromsize; /* in word size */ +}; + +void siba_powerup(struct siba_softc *, int); +uint16_t siba_read_2(struct siba_dev_softc *, uint16_t); +void siba_write_2(struct siba_dev_softc *, uint16_t, uint16_t); +uint32_t siba_read_4(struct siba_dev_softc *, uint16_t); +void siba_write_4(struct siba_dev_softc *, uint16_t, uint32_t); +void siba_dev_up(struct siba_dev_softc *, uint32_t); +void siba_dev_down(struct siba_dev_softc *, uint32_t); +int siba_powerdown(struct siba_softc *); +int siba_dev_isup(struct siba_dev_softc *); +void siba_pcicore_intr(struct siba_pci *, struct siba_dev_softc *); +uint32_t siba_dma_translation(struct siba_dev_softc *); +void *siba_dma_alloc_consistent(struct siba_dev_softc *, size_t, + bus_addr_t *); +void siba_read_multi_1(struct siba_dev_softc *, void *, size_t, + uint16_t); +void siba_read_multi_2(struct siba_dev_softc *, void *, size_t, + uint16_t); +void siba_read_multi_4(struct siba_dev_softc *, void *, size_t, + uint16_t); +void siba_write_multi_1(struct siba_dev_softc *, const void *, + size_t, uint16_t); +void siba_write_multi_2(struct siba_dev_softc *, const void *, + size_t, uint16_t); +void siba_write_multi_4(struct siba_dev_softc *, const void *, + size_t, uint16_t); +void siba_barrier(struct siba_dev_softc *, int); #endif /* _SIBA_SIBAVAR_H_ */ diff --git a/sys/modules/siba_bwn/Makefile b/sys/modules/siba_bwn/Makefile new file mode 100644 index 0000000..433d37f --- /dev/null +++ b/sys/modules/siba_bwn/Makefile @@ -0,0 +1,9 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../dev/siba + +KMOD= siba_bwn +SRCS= siba_core.c siba_bwn.c sibareg.h sibavar.h +SRCS+= device_if.h bus_if.h pci_if.h + +.include -- cgit v1.1