/*- * 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, MERCHANTABILITY * 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: head/sys/dev/siba/siba_core.c 299541 2016-05-12 16:14:16Z adrian $"); /* * the Sonics Silicon Backplane driver. */ #include "opt_siba.h" #include #include #include #include #include #include #include #include #if !defined(__DragonFly__) #include #include #endif #include #include #include #include #include #include #if defined(__DragonFly__) #include #include #else #include #include #endif #if defined(__DragonFly__) #include "siba_ids.h" #include "sibareg.h" #include "sibavar.h" #else #include #include #include #endif 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 }; #ifdef SIBA_DEBUG #define DPRINTF(siba, m, ...) do { \ if (siba->siba_debug & (m)) \ device_printf(siba->siba_dev, __VA_ARGS__); \ } while (0) #else #define DPRINTF(siba, m, ...) do { (void) siba; } while (0) #endif 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 *); static uint32_t siba_read_4_sub(struct siba_dev_softc *, uint16_t); static void siba_write_4_sub(struct siba_dev_softc *, uint16_t, uint32_t); static void siba_powerup_sub(struct siba_softc *, int); static int siba_powerdown_sub(struct siba_softc *); static int siba_dev_isup_sub(struct siba_dev_softc *); static void siba_dev_up_sub(struct siba_dev_softc *, uint32_t); static void siba_dev_down_sub(struct siba_dev_softc *, uint32_t); 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_sub(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); } error = siba_pci_sprom(siba, &siba->siba_sprom); if (error) { siba_powerdown_sub(siba); return (error); } siba_pcicore_init(&siba->siba_pci); siba_powerdown_sub(siba); return (bus_generic_attach(siba->siba_dev)); } int siba_core_detach(struct siba_softc *siba) { /* detach & delete all children */ device_delete_children(siba->siba_dev); 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; device_t child; 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.sd_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++; #if defined(__DragonFly__) error = pci_find_extcap(siba->siba_dev, PCIY_EXPRESS, &base); #else error = pci_find_cap(siba->siba_dev, PCIY_EXPRESS, &base); #endif 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++; child = device_add_child(siba->siba_dev, NULL, -1); if (child == NULL) { device_printf(siba->siba_dev, "child attach failed\n"); continue; } device_set_ivars(child, sd); } 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(device_t dev, int dynamic) { struct siba_dev_softc *sd = device_get_ivars(dev); struct siba_softc *siba = sd->sd_bus; siba_powerup_sub(siba, dynamic); } static void siba_powerup_sub(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(device_t dev, uint16_t offset) { struct siba_dev_softc *sd = device_get_ivars(dev); return (sd->sd_ops->read_2(sd, offset)); } uint32_t siba_read_4(device_t dev, uint16_t offset) { struct siba_dev_softc *sd = device_get_ivars(dev); return (siba_read_4_sub(sd, offset)); } static uint32_t siba_read_4_sub(struct siba_dev_softc *sd, uint16_t offset) { return (sd->sd_ops->read_4(sd, offset)); } void siba_write_2(device_t dev, uint16_t offset, uint16_t value) { struct siba_dev_softc *sd = device_get_ivars(dev); sd->sd_ops->write_2(sd, offset, value); } void siba_write_4(device_t dev, uint16_t offset, uint32_t value) { struct siba_dev_softc *sd = device_get_ivars(dev); return (siba_write_4_sub(sd, offset, value)); } static void siba_write_4_sub(struct siba_dev_softc *sd, uint16_t offset, uint32_t value) { sd->sd_ops->write_4(sd, offset, value); } void siba_read_multi_1(device_t dev, void *buffer, size_t count, uint16_t offset) { struct siba_dev_softc *sd = device_get_ivars(dev); sd->sd_ops->read_multi_1(sd, buffer, count, offset); } void siba_read_multi_2(device_t dev, void *buffer, size_t count, uint16_t offset) { struct siba_dev_softc *sd = device_get_ivars(dev); sd->sd_ops->read_multi_2(sd, buffer, count, offset); } void siba_read_multi_4(device_t dev, void *buffer, size_t count, uint16_t offset) { struct siba_dev_softc *sd = device_get_ivars(dev); sd->sd_ops->read_multi_4(sd, buffer, count, offset); } void siba_write_multi_1(device_t dev, const void *buffer, size_t count, uint16_t offset) { struct siba_dev_softc *sd = device_get_ivars(dev); sd->sd_ops->write_multi_1(sd, buffer, count, offset); } void siba_write_multi_2(device_t dev, const void *buffer, size_t count, uint16_t offset) { struct siba_dev_softc *sd = device_get_ivars(dev); sd->sd_ops->write_multi_2(sd, buffer, count, offset); } void siba_write_multi_4(device_t dev, const void *buffer, size_t count, uint16_t offset) { struct siba_dev_softc *sd = device_get_ivars(dev); 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 = nitems(siba_cc_pmu_4325_updown); depend = siba_cc_pmu_4325_depend; depend_size = nitems(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 = nitems(siba_cc_pmu_4328_updown); depend = siba_cc_pmu_4328_depend; depend_size = nitems(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 = howmany((SIBA_CC_READ32(scc, SIBA_CC_PLLONDELAY) + 2) * 1000000, 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 < nitems(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 < nitems(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 = kmalloc(SIBA_SPROMSIZE_R123 * sizeof(uint16_t), M_DEVBUF, M_INTWAIT | 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) { kfree(buf, M_DEVBUF); buf = kmalloc(SIBA_SPROMSIZE_R4 * sizeof(uint16_t), M_DEVBUF, M_INTWAIT | 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; kfree(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)) #define SIBA_SHIFTOUT_4(_var, _offset, _mask, _shift) \ out->_var = ((((uint32_t)in[SIBA_OFFSET((_offset)+2)] << 16 | \ in[SIBA_OFFSET(_offset)]) & (_mask)) >> (_shift)) 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_r458(struct siba_sprom *out, const uint16_t *in) { SIBA_SHIFTOUT(txpid2g[0], SIBA_SPROM4_TXPID2G01, SIBA_SPROM4_TXPID2G0); SIBA_SHIFTOUT(txpid2g[1], SIBA_SPROM4_TXPID2G01, SIBA_SPROM4_TXPID2G1); SIBA_SHIFTOUT(txpid2g[2], SIBA_SPROM4_TXPID2G23, SIBA_SPROM4_TXPID2G2); SIBA_SHIFTOUT(txpid2g[3], SIBA_SPROM4_TXPID2G23, SIBA_SPROM4_TXPID2G3); SIBA_SHIFTOUT(txpid5gl[0], SIBA_SPROM4_TXPID5GL01, SIBA_SPROM4_TXPID5GL0); SIBA_SHIFTOUT(txpid5gl[1], SIBA_SPROM4_TXPID5GL01, SIBA_SPROM4_TXPID5GL1); SIBA_SHIFTOUT(txpid5gl[2], SIBA_SPROM4_TXPID5GL23, SIBA_SPROM4_TXPID5GL2); SIBA_SHIFTOUT(txpid5gl[3], SIBA_SPROM4_TXPID5GL23, SIBA_SPROM4_TXPID5GL3); SIBA_SHIFTOUT(txpid5g[0], SIBA_SPROM4_TXPID5G01, SIBA_SPROM4_TXPID5G0); SIBA_SHIFTOUT(txpid5g[1], SIBA_SPROM4_TXPID5G01, SIBA_SPROM4_TXPID5G1); SIBA_SHIFTOUT(txpid5g[2], SIBA_SPROM4_TXPID5G23, SIBA_SPROM4_TXPID5G2); SIBA_SHIFTOUT(txpid5g[3], SIBA_SPROM4_TXPID5G23, SIBA_SPROM4_TXPID5G3); SIBA_SHIFTOUT(txpid5gh[0], SIBA_SPROM4_TXPID5GH01, SIBA_SPROM4_TXPID5GH0); SIBA_SHIFTOUT(txpid5gh[1], SIBA_SPROM4_TXPID5GH01, SIBA_SPROM4_TXPID5GH1); SIBA_SHIFTOUT(txpid5gh[2], SIBA_SPROM4_TXPID5GH23, SIBA_SPROM4_TXPID5GH2); SIBA_SHIFTOUT(txpid5gh[3], SIBA_SPROM4_TXPID5GH23, SIBA_SPROM4_TXPID5GH3); } static void siba_sprom_r45(struct siba_sprom *out, const uint16_t *in) { int i; uint16_t v; uint16_t mac_80211bg_offset; const uint16_t pwr_info_offset[] = { SIBA_SPROM4_PWR_INFO_CORE0, SIBA_SPROM4_PWR_INFO_CORE1, SIBA_SPROM4_PWR_INFO_CORE2, SIBA_SPROM4_PWR_INFO_CORE3 }; 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)); /* Extract core power info */ for (i = 0; i < nitems(pwr_info_offset); i++) { uint16_t o = pwr_info_offset[i]; SIBA_SHIFTOUT(core_pwr_info[i].itssi_2g, o + SIBA_SPROM4_2G_MAXP_ITSSI, SIBA_SPROM4_2G_ITSSI); SIBA_SHIFTOUT(core_pwr_info[i].maxpwr_2g, o + SIBA_SPROM4_2G_MAXP_ITSSI, SIBA_SPROM4_2G_MAXP); SIBA_SHIFTOUT(core_pwr_info[i].pa_2g[0], o + SIBA_SPROM4_2G_PA_0, ~0); SIBA_SHIFTOUT(core_pwr_info[i].pa_2g[1], o + SIBA_SPROM4_2G_PA_1, ~0); SIBA_SHIFTOUT(core_pwr_info[i].pa_2g[2], o + SIBA_SPROM4_2G_PA_2, ~0); SIBA_SHIFTOUT(core_pwr_info[i].pa_2g[3], o + SIBA_SPROM4_2G_PA_3, ~0); SIBA_SHIFTOUT(core_pwr_info[i].itssi_5g, o + SIBA_SPROM4_5G_MAXP_ITSSI, SIBA_SPROM4_5G_ITSSI); SIBA_SHIFTOUT(core_pwr_info[i].maxpwr_5g, o + SIBA_SPROM4_5G_MAXP_ITSSI, SIBA_SPROM4_5G_MAXP); SIBA_SHIFTOUT(core_pwr_info[i].maxpwr_5gh, o + SIBA_SPROM4_5GHL_MAXP, SIBA_SPROM4_5GH_MAXP); SIBA_SHIFTOUT(core_pwr_info[i].maxpwr_5gl, o + SIBA_SPROM4_5GHL_MAXP, SIBA_SPROM4_5GL_MAXP); SIBA_SHIFTOUT(core_pwr_info[i].pa_5gl[0], o + SIBA_SPROM4_5GL_PA_0, ~0); SIBA_SHIFTOUT(core_pwr_info[i].pa_5gl[1], o + SIBA_SPROM4_5GL_PA_1, ~0); SIBA_SHIFTOUT(core_pwr_info[i].pa_5gl[2], o + SIBA_SPROM4_5GL_PA_2, ~0); SIBA_SHIFTOUT(core_pwr_info[i].pa_5gl[3], o + SIBA_SPROM4_5GL_PA_3, ~0); SIBA_SHIFTOUT(core_pwr_info[i].pa_5g[0], o + SIBA_SPROM4_5G_PA_0, ~0); SIBA_SHIFTOUT(core_pwr_info[i].pa_5g[1], o + SIBA_SPROM4_5G_PA_1, ~0); SIBA_SHIFTOUT(core_pwr_info[i].pa_5g[2], o + SIBA_SPROM4_5G_PA_2, ~0); SIBA_SHIFTOUT(core_pwr_info[i].pa_5g[3], o + SIBA_SPROM4_5G_PA_3, ~0); SIBA_SHIFTOUT(core_pwr_info[i].pa_5gh[0], o + SIBA_SPROM4_5GH_PA_0, ~0); SIBA_SHIFTOUT(core_pwr_info[i].pa_5gh[1], o + SIBA_SPROM4_5GH_PA_1, ~0); SIBA_SHIFTOUT(core_pwr_info[i].pa_5gh[2], o + SIBA_SPROM4_5GH_PA_2, ~0); SIBA_SHIFTOUT(core_pwr_info[i].pa_5gh[3], o + SIBA_SPROM4_5GH_PA_3, ~0); } siba_sprom_r458(out, in); } static void siba_sprom_r8(struct siba_sprom *out, const uint16_t *in) { int i; uint16_t v; uint16_t pwr_info_offset[] = { SIBA_SROM8_PWR_INFO_CORE0, SIBA_SROM8_PWR_INFO_CORE1, SIBA_SROM8_PWR_INFO_CORE2, SIBA_SROM8_PWR_INFO_CORE3 }; for (i = 0; i < 3; i++) { v = in[SIBA_OFFSET(SIBA_SPROM8_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(bf2_lo, SIBA_SPROM8_BFL2LO, 0xffff); SIBA_SHIFTOUT(bf2_hi, SIBA_SPROM8_BFL2HI, 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(maxpwr_ah, SIBA_SPROM8_MAXP_AHL, SIBA_SPROM8_MAXP_AH_MASK); SIBA_SHIFTOUT(maxpwr_al, SIBA_SPROM8_MAXP_AHL, SIBA_SPROM8_MAXP_AL_MASK); 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); SIBA_SHIFTOUT(tri2g, SIBA_SPROM8_TRI25G, SIBA_SPROM8_TRI2G); SIBA_SHIFTOUT(tri5g, SIBA_SPROM8_TRI25G, SIBA_SPROM8_TRI5G); SIBA_SHIFTOUT(tri5gl, SIBA_SPROM8_TRI5GHL, SIBA_SPROM8_TRI5GL); SIBA_SHIFTOUT(tri5gh, SIBA_SPROM8_TRI5GHL, SIBA_SPROM8_TRI5GH); SIBA_SHIFTOUT(rxpo2g, SIBA_SPROM8_RXPO, SIBA_SPROM8_RXPO2G); SIBA_SHIFTOUT(rxpo5g, SIBA_SPROM8_RXPO, SIBA_SPROM8_RXPO5G); SIBA_SHIFTOUT(rssismf2g, SIBA_SPROM8_RSSIPARM2G, SIBA_SPROM8_RSSISMF2G); SIBA_SHIFTOUT(rssismc2g, SIBA_SPROM8_RSSIPARM2G, SIBA_SPROM8_RSSISMC2G); SIBA_SHIFTOUT(rssisav2g, SIBA_SPROM8_RSSIPARM2G, SIBA_SPROM8_RSSISAV2G); SIBA_SHIFTOUT(bxa2g, SIBA_SPROM8_RSSIPARM2G, SIBA_SPROM8_BXA2G); SIBA_SHIFTOUT(rssismf5g, SIBA_SPROM8_RSSIPARM5G, SIBA_SPROM8_RSSISMF5G); SIBA_SHIFTOUT(rssismc5g, SIBA_SPROM8_RSSIPARM5G, SIBA_SPROM8_RSSISMC5G); SIBA_SHIFTOUT(rssisav5g, SIBA_SPROM8_RSSIPARM5G, SIBA_SPROM8_RSSISAV5G); SIBA_SHIFTOUT(bxa5g, SIBA_SPROM8_RSSIPARM5G, SIBA_SPROM8_BXA5G); SIBA_SHIFTOUT(pa0b0, SIBA_SPROM8_PA0B0, 0xffff); SIBA_SHIFTOUT(pa0b1, SIBA_SPROM8_PA0B1, 0xffff); SIBA_SHIFTOUT(pa0b2, SIBA_SPROM8_PA0B2, 0xffff); SIBA_SHIFTOUT(pa1b0, SIBA_SPROM8_PA1B0, 0xffff); SIBA_SHIFTOUT(pa1b1, SIBA_SPROM8_PA1B1, 0xffff); SIBA_SHIFTOUT(pa1b2, SIBA_SPROM8_PA1B2, 0xffff); SIBA_SHIFTOUT(pa1lob0, SIBA_SPROM8_PA1LOB0, 0xffff); SIBA_SHIFTOUT(pa1lob1, SIBA_SPROM8_PA1LOB1, 0xffff); SIBA_SHIFTOUT(pa1lob2, SIBA_SPROM8_PA1LOB2, 0xffff); SIBA_SHIFTOUT(pa1hib0, SIBA_SPROM8_PA1HIB0, 0xffff); SIBA_SHIFTOUT(pa1hib1, SIBA_SPROM8_PA1HIB1, 0xffff); SIBA_SHIFTOUT(pa1hib2, SIBA_SPROM8_PA1HIB2, 0xffff); SIBA_SHIFTOUT(cck2gpo, SIBA_SPROM8_CCK2GPO, 0xffff); SIBA_SHIFTOUT_4(ofdm2gpo, SIBA_SPROM8_OFDM2GPO, 0xffffffff, 0); SIBA_SHIFTOUT_4(ofdm5glpo, SIBA_SPROM8_OFDM5GLPO, 0xffffffff, 0); SIBA_SHIFTOUT_4(ofdm5gpo, SIBA_SPROM8_OFDM5GPO, 0xffffffff, 0); SIBA_SHIFTOUT_4(ofdm5ghpo, SIBA_SPROM8_OFDM5GHPO, 0xffffffff, 0); /* 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)); /* FEM */ SIBA_SHIFTOUT(fem.ghz2.tssipos, SIBA_SPROM8_FEM2G, SSB_SROM8_FEM_TSSIPOS); SIBA_SHIFTOUT(fem.ghz2.extpa_gain, SIBA_SPROM8_FEM2G, SSB_SROM8_FEM_EXTPA_GAIN); SIBA_SHIFTOUT(fem.ghz2.pdet_range, SIBA_SPROM8_FEM2G, SSB_SROM8_FEM_PDET_RANGE); SIBA_SHIFTOUT(fem.ghz2.tr_iso, SIBA_SPROM8_FEM2G, SSB_SROM8_FEM_TR_ISO); SIBA_SHIFTOUT(fem.ghz2.antswlut, SIBA_SPROM8_FEM2G, SSB_SROM8_FEM_ANTSWLUT); SIBA_SHIFTOUT(fem.ghz5.tssipos, SIBA_SPROM8_FEM5G, SSB_SROM8_FEM_TSSIPOS); SIBA_SHIFTOUT(fem.ghz5.extpa_gain, SIBA_SPROM8_FEM5G, SSB_SROM8_FEM_EXTPA_GAIN); SIBA_SHIFTOUT(fem.ghz5.pdet_range, SIBA_SPROM8_FEM5G, SSB_SROM8_FEM_PDET_RANGE); SIBA_SHIFTOUT(fem.ghz5.tr_iso, SIBA_SPROM8_FEM5G, SSB_SROM8_FEM_TR_ISO); SIBA_SHIFTOUT(fem.ghz5.antswlut, SIBA_SPROM8_FEM5G, SSB_SROM8_FEM_ANTSWLUT); /* Extract cores power info info */ for (i = 0; i < nitems(pwr_info_offset); i++) { uint16_t o = pwr_info_offset[i]; SIBA_SHIFTOUT(core_pwr_info[i].itssi_2g, o + SIBA_SROM8_2G_MAXP_ITSSI, SIBA_SPROM8_2G_ITSSI); SIBA_SHIFTOUT(core_pwr_info[i].maxpwr_2g, o + SIBA_SROM8_2G_MAXP_ITSSI, SIBA_SPROM8_2G_MAXP); SIBA_SHIFTOUT(core_pwr_info[i].pa_2g[0], o + SIBA_SROM8_2G_PA_0, ~0); SIBA_SHIFTOUT(core_pwr_info[i].pa_2g[1], o + SIBA_SROM8_2G_PA_1, ~0); SIBA_SHIFTOUT(core_pwr_info[i].pa_2g[2], o + SIBA_SROM8_2G_PA_2, ~0); SIBA_SHIFTOUT(core_pwr_info[i].itssi_5g, o + SIBA_SROM8_5G_MAXP_ITSSI, SIBA_SPROM8_5G_ITSSI); SIBA_SHIFTOUT(core_pwr_info[i].maxpwr_5g, o + SIBA_SROM8_5G_MAXP_ITSSI, SIBA_SPROM8_5G_MAXP); SIBA_SHIFTOUT(core_pwr_info[i].maxpwr_5gh, o + SIBA_SPROM8_5GHL_MAXP, SIBA_SPROM8_5GH_MAXP); SIBA_SHIFTOUT(core_pwr_info[i].maxpwr_5gl, o + SIBA_SPROM8_5GHL_MAXP, SIBA_SPROM8_5GL_MAXP); SIBA_SHIFTOUT(core_pwr_info[i].pa_5gl[0], o + SIBA_SROM8_5GL_PA_0, ~0); SIBA_SHIFTOUT(core_pwr_info[i].pa_5gl[1], o + SIBA_SROM8_5GL_PA_1, ~0); SIBA_SHIFTOUT(core_pwr_info[i].pa_5gl[2], o + SIBA_SROM8_5GL_PA_2, ~0); SIBA_SHIFTOUT(core_pwr_info[i].pa_5g[0], o + SIBA_SROM8_5G_PA_0, ~0); SIBA_SHIFTOUT(core_pwr_info[i].pa_5g[1], o + SIBA_SROM8_5G_PA_1, ~0); SIBA_SHIFTOUT(core_pwr_info[i].pa_5g[2], o + SIBA_SROM8_5G_PA_2, ~0); SIBA_SHIFTOUT(core_pwr_info[i].pa_5gh[0], o + SIBA_SROM8_5GH_PA_0, ~0); SIBA_SHIFTOUT(core_pwr_info[i].pa_5gh[1], o + SIBA_SROM8_5GH_PA_1, ~0); SIBA_SHIFTOUT(core_pwr_info[i].pa_5gh[2], o + SIBA_SROM8_5GH_PA_2, ~0); } SIBA_SHIFTOUT(cddpo, SIBA_SPROM8_CDDPO, ~0); SIBA_SHIFTOUT(stbcpo, SIBA_SPROM8_STBCPO, ~0); siba_sprom_r458(out, in); } 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(device_t dev) { struct siba_dev_softc *sd = device_get_ivars(dev); struct siba_softc *siba = sd->sd_bus; return (siba_powerdown_sub(siba)); } static int siba_powerdown_sub(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; if (sd == NULL) return; if (!siba_dev_isup_sub(sd)) siba_dev_up_sub(sd, 0); KASSERT(spc->spc_hostmode == 0, ("%s:%d: hostmode", __func__, __LINE__)); /* disable PCI interrupt */ siba_write_4_sub(spc->spc_dev, SIBA_INTR_MASK, 0); } int siba_dev_isup(device_t dev) { struct siba_dev_softc *sd = device_get_ivars(dev); return (siba_dev_isup_sub(sd)); } static int siba_dev_isup_sub(struct siba_dev_softc *sd) { uint32_t reject, val; reject = siba_tmslow_reject_bitmask(sd); val = siba_read_4_sub(sd, SIBA_TGSLOW); val &= SIBA_TGSLOW_CLOCK | SIBA_TGSLOW_RESET | reject; return (val == SIBA_TGSLOW_CLOCK); } void siba_dev_up(device_t dev, uint32_t flags) { struct siba_dev_softc *sd = device_get_ivars(dev); siba_dev_up_sub(sd, flags); } static void siba_dev_up_sub(struct siba_dev_softc *sd, uint32_t flags) { uint32_t val; siba_dev_down_sub(sd, flags); siba_write_4_sub(sd, SIBA_TGSLOW, SIBA_TGSLOW_RESET | SIBA_TGSLOW_CLOCK | SIBA_TGSLOW_FGC | flags); siba_read_4_sub(sd, SIBA_TGSLOW); DELAY(1); if (siba_read_4_sub(sd, SIBA_TGSHIGH) & SIBA_TGSHIGH_SERR) siba_write_4_sub(sd, SIBA_TGSHIGH, 0); val = siba_read_4_sub(sd, SIBA_IAS); if (val & (SIBA_IAS_INBAND_ERR | SIBA_IAS_TIMEOUT)) { val &= ~(SIBA_IAS_INBAND_ERR | SIBA_IAS_TIMEOUT); siba_write_4_sub(sd, SIBA_IAS, val); } siba_write_4_sub(sd, SIBA_TGSLOW, SIBA_TGSLOW_CLOCK | SIBA_TGSLOW_FGC | flags); siba_read_4_sub(sd, SIBA_TGSLOW); DELAY(1); siba_write_4_sub(sd, SIBA_TGSLOW, SIBA_TGSLOW_CLOCK | flags); siba_read_4_sub(sd, SIBA_TGSLOW); DELAY(1); } static uint32_t siba_tmslow_reject_bitmask(struct siba_dev_softc *sd) { uint32_t rev = siba_read_4_sub(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(device_t dev, uint32_t flags) { struct siba_dev_softc *sd = device_get_ivars(dev); siba_dev_down_sub(sd, flags); } static void siba_dev_down_sub(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_sub(sd, SIBA_TGSLOW) & SIBA_TGSLOW_RESET) return; reject = siba_tmslow_reject_bitmask(sd); siba_write_4_sub(sd, SIBA_TGSLOW, reject | SIBA_TGSLOW_CLOCK); for (i = 0; i < 1000; i++) { val = siba_read_4_sub(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_sub(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_sub(sd, SIBA_TGSLOW, SIBA_TGSLOW_FGC | SIBA_TGSLOW_CLOCK | reject | SIBA_TGSLOW_RESET | flags); siba_read_4_sub(sd, SIBA_TGSLOW); DELAY(1); siba_write_4_sub(sd, SIBA_TGSLOW, reject | SIBA_TGSLOW_RESET | flags); siba_read_4_sub(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_sub(psd, SIBA_IMCFGLO); tmp &= ~SIBA_IMCFGLO_SERTO; tmp = (tmp | 2) & ~SIBA_IMCFGLO_REQTO; tmp |= 3 << 4 /* SIBA_IMCFGLO_REQTO_SHIFT */; siba_write_4_sub(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_sub(sd, SIBA_PCICORE_BCAST_ADDR, 0xfd8); siba_read_4_sub(sd, SIBA_PCICORE_BCAST_ADDR); siba_write_4_sub(sd, SIBA_PCICORE_BCAST_DATA, 0); siba_read_4_sub(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(device_t dev) { struct siba_dev_softc *sd = device_get_ivars(dev); struct siba_softc *siba = sd->sd_bus; struct siba_pci *spc = &siba->siba_pci; struct siba_dev_softc *psd = spc->spc_dev; uint32_t tmp; if (siba->siba_type != SIBA_TYPE_PCI || !psd) return; KASSERT(siba == psd->sd_bus, ("different pointers")); /* 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_sub(sd, SIBA_TPS); tmp &= SIBA_TPS_BPFLAG; siba_write_4_sub(psd, SIBA_INTR_MASK, siba_read_4_sub(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_sub(spc->spc_dev, offset)); } static void siba_pcicore_write_4(struct siba_pci *spc, uint16_t offset, uint32_t value) { siba_write_4_sub(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(device_t dev) { #ifdef INVARIANTS struct siba_dev_softc *sd = device_get_ivars(dev); struct siba_softc *siba = sd->sd_bus; KASSERT(siba->siba_type == SIBA_TYPE_PCI, ("unsupported bustype %d\n", siba->siba_type)); #endif return (SIBA_PCI_DMA); } void siba_barrier(device_t dev, int flags) { struct siba_dev_softc *sd = device_get_ivars(dev); struct siba_softc *siba = sd->sd_bus; SIBA_BARRIER(siba, flags); } 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_sub(siba, 0); /* XXX setup H/W for PCMCIA??? */ siba_cc_resume(&siba->siba_cc); siba_powerdown_sub(siba); return (0); } static void siba_cc_regctl_setmask(struct siba_cc *cc, uint32_t offset, uint32_t mask, uint32_t set) { SIBA_CC_READ32(cc, SIBA_CC_REGCTL_ADDR); SIBA_CC_WRITE32(cc, SIBA_CC_REGCTL_ADDR, offset); SIBA_CC_READ32(cc, SIBA_CC_REGCTL_ADDR); SIBA_CC_WRITE32(cc, SIBA_CC_REGCTL_DATA, (SIBA_CC_READ32(cc, SIBA_CC_REGCTL_DATA) & mask) | set); SIBA_CC_READ32(cc, SIBA_CC_REGCTL_DATA); } void siba_cc_pmu_set_ldovolt(device_t dev, int id, uint32_t volt) { struct siba_dev_softc *sd = device_get_ivars(dev); struct siba_softc *siba = sd->sd_bus; struct siba_cc *scc = &siba->siba_cc; uint32_t *p = NULL, info[5][3] = { { 2, 25, 0xf }, { 3, 1, 0xf }, { 3, 9, 0xf }, { 3, 17, 0x3f }, { 0, 21, 0x3f } }; if (siba->siba_chipid == 0x4312) { if (id != SIBA_LDO_PAREF) return; p = info[4]; siba_cc_regctl_setmask(scc, p[0], ~(p[2] << p[1]), (volt & p[2]) << p[1]); return; } if (siba->siba_chipid == 0x4328 || siba->siba_chipid == 0x5354) { switch (id) { case SIBA_LDO_PAREF: p = info[3]; break; case SIBA_LDO_VOLT1: p = info[0]; break; case SIBA_LDO_VOLT2: p = info[1]; break; case SIBA_LDO_VOLT3: p = info[2]; break; default: KASSERT(0 == 1, ("%s: unsupported voltage ID %#x", __func__, id)); return; } siba_cc_regctl_setmask(scc, p[0], ~(p[2] << p[1]), (volt & p[2]) << p[1]); } } void siba_cc_pmu_set_ldoparef(device_t dev, uint8_t on) { struct siba_dev_softc *sd = device_get_ivars(dev); struct siba_softc *siba = sd->sd_bus; struct siba_cc *scc = &siba->siba_cc; int ldo; ldo = ((siba->siba_chipid == 0x4312) ? SIBA_CC_PMU_4312_PA_REF : ((siba->siba_chipid == 0x4328) ? SIBA_CC_PMU_4328_PA_REF : ((siba->siba_chipid == 0x5354) ? SIBA_CC_PMU_5354_PA_REF : -1))); if (ldo == -1) return; if (on) SIBA_CC_SET32(scc, SIBA_CC_PMU_MINRES, 1 << ldo); else SIBA_CC_MASK32(scc, SIBA_CC_PMU_MINRES, ~(1 << ldo)); SIBA_CC_READ32(scc, SIBA_CC_PMU_MINRES); } int siba_read_sprom(device_t dev, device_t child, int which, uintptr_t *result) { struct siba_dev_softc *sd = device_get_ivars(child); struct siba_softc *siba = sd->sd_bus; switch (which) { case SIBA_SPROMVAR_REV: *result = siba->siba_sprom.rev; break; case SIBA_SPROMVAR_MAC_80211BG: *((uint8_t **) result) = siba->siba_sprom.mac_80211bg; break; case SIBA_SPROMVAR_MAC_ETH: *((uint8_t **) result) = siba->siba_sprom.mac_eth; break; case SIBA_SPROMVAR_MAC_80211A: *((uint8_t **) result) = siba->siba_sprom.mac_80211a; break; case SIBA_SPROMVAR_MII_ETH0: *result = siba->siba_sprom.mii_eth0; break; case SIBA_SPROMVAR_MII_ETH1: *result = siba->siba_sprom.mii_eth1; break; case SIBA_SPROMVAR_MDIO_ETH0: *result = siba->siba_sprom.mdio_eth0; break; case SIBA_SPROMVAR_MDIO_ETH1: *result = siba->siba_sprom.mdio_eth1; break; case SIBA_SPROMVAR_BREV: *result = siba->siba_sprom.brev; break; case SIBA_SPROMVAR_CCODE: *result = siba->siba_sprom.ccode; break; case SIBA_SPROMVAR_ANT_A: *result = siba->siba_sprom.ant_a; break; case SIBA_SPROMVAR_ANT_BG: *result = siba->siba_sprom.ant_bg; break; case SIBA_SPROMVAR_PA0B0: *result = siba->siba_sprom.pa0b0; break; case SIBA_SPROMVAR_PA0B1: *result = siba->siba_sprom.pa0b1; break; case SIBA_SPROMVAR_PA0B2: *result = siba->siba_sprom.pa0b2; break; case SIBA_SPROMVAR_PA1B0: *result = siba->siba_sprom.pa1b0; break; case SIBA_SPROMVAR_PA1B1: *result = siba->siba_sprom.pa1b1; break; case SIBA_SPROMVAR_PA1B2: *result = siba->siba_sprom.pa1b2; break; case SIBA_SPROMVAR_PA1LOB0: *result = siba->siba_sprom.pa1lob0; break; case SIBA_SPROMVAR_PA1LOB1: *result = siba->siba_sprom.pa1lob1; break; case SIBA_SPROMVAR_PA1LOB2: *result = siba->siba_sprom.pa1lob2; break; case SIBA_SPROMVAR_PA1HIB0: *result = siba->siba_sprom.pa1hib0; break; case SIBA_SPROMVAR_PA1HIB1: *result = siba->siba_sprom.pa1hib1; break; case SIBA_SPROMVAR_PA1HIB2: *result = siba->siba_sprom.pa1hib2; break; case SIBA_SPROMVAR_GPIO0: *result = siba->siba_sprom.gpio0; break; case SIBA_SPROMVAR_GPIO1: *result = siba->siba_sprom.gpio1; break; case SIBA_SPROMVAR_GPIO2: *result = siba->siba_sprom.gpio2; break; case SIBA_SPROMVAR_GPIO3: *result = siba->siba_sprom.gpio3; break; case SIBA_SPROMVAR_MAXPWR_AL: *result = siba->siba_sprom.maxpwr_al; break; case SIBA_SPROMVAR_MAXPWR_A: *result = siba->siba_sprom.maxpwr_a; break; case SIBA_SPROMVAR_MAXPWR_AH: *result = siba->siba_sprom.maxpwr_ah; break; case SIBA_SPROMVAR_MAXPWR_BG: *result = siba->siba_sprom.maxpwr_bg; break; case SIBA_SPROMVAR_RXPO2G: *result = siba->siba_sprom.rxpo2g; break; case SIBA_SPROMVAR_RXPO5G: *result = siba->siba_sprom.rxpo5g; break; case SIBA_SPROMVAR_TSSI_A: *result = siba->siba_sprom.tssi_a; break; case SIBA_SPROMVAR_TSSI_BG: *result = siba->siba_sprom.tssi_bg; break; case SIBA_SPROMVAR_TRI2G: *result = siba->siba_sprom.tri2g; break; case SIBA_SPROMVAR_TRI5GL: *result = siba->siba_sprom.tri5gl; break; case SIBA_SPROMVAR_TRI5G: *result = siba->siba_sprom.tri5g; break; case SIBA_SPROMVAR_TRI5GH: *result = siba->siba_sprom.tri5gh; break; case SIBA_SPROMVAR_RSSISAV2G: *result = siba->siba_sprom.rssisav2g; break; case SIBA_SPROMVAR_RSSISMC2G: *result = siba->siba_sprom.rssismc2g; break; case SIBA_SPROMVAR_RSSISMF2G: *result = siba->siba_sprom.rssismf2g; break; case SIBA_SPROMVAR_BXA2G: *result = siba->siba_sprom.bxa2g; break; case SIBA_SPROMVAR_RSSISAV5G: *result = siba->siba_sprom.rssisav5g; break; case SIBA_SPROMVAR_RSSISMC5G: *result = siba->siba_sprom.rssismc5g; break; case SIBA_SPROMVAR_RSSISMF5G: *result = siba->siba_sprom.rssismf5g; break; case SIBA_SPROMVAR_BXA5G: *result = siba->siba_sprom.bxa5g; break; case SIBA_SPROMVAR_CCK2GPO: *result = siba->siba_sprom.cck2gpo; break; case SIBA_SPROMVAR_OFDM2GPO: *result = siba->siba_sprom.ofdm2gpo; break; case SIBA_SPROMVAR_OFDM5GLPO: *result = siba->siba_sprom.ofdm5glpo; break; case SIBA_SPROMVAR_OFDM5GPO: *result = siba->siba_sprom.ofdm5gpo; break; case SIBA_SPROMVAR_OFDM5GHPO: *result = siba->siba_sprom.ofdm5ghpo; break; case SIBA_SPROMVAR_BF_LO: *result = siba->siba_sprom.bf_lo; break; case SIBA_SPROMVAR_BF_HI: *result = siba->siba_sprom.bf_hi; break; case SIBA_SPROMVAR_BF2_LO: *result = siba->siba_sprom.bf2_lo; break; case SIBA_SPROMVAR_BF2_HI: *result = siba->siba_sprom.bf2_hi; break; case SIBA_SPROMVAR_FEM_2GHZ_TSSIPOS: *result = siba->siba_sprom.fem.ghz2.tssipos; break; case SIBA_SPROMVAR_FEM_2GHZ_EXTPAGAIN: *result = siba->siba_sprom.fem.ghz2.extpa_gain; break; case SIBA_SPROMVAR_FEM_2GHZ_PDET_RANGE: *result = siba->siba_sprom.fem.ghz2.pdet_range; break; case SIBA_SPROMVAR_FEM_2GHZ_TR_ISO: *result = siba->siba_sprom.fem.ghz2.tr_iso; break; case SIBA_SPROMVAR_FEM_2GHZ_ANTSWLUT: *result = siba->siba_sprom.fem.ghz2.antswlut; break; case SIBA_SPROMVAR_FEM_5GHZ_TSSIPOS: *result = siba->siba_sprom.fem.ghz5.tssipos; break; case SIBA_SPROMVAR_FEM_5GHZ_EXTPAGAIN: *result = siba->siba_sprom.fem.ghz5.extpa_gain; break; case SIBA_SPROMVAR_FEM_5GHZ_PDET_RANGE: *result = siba->siba_sprom.fem.ghz5.pdet_range; break; case SIBA_SPROMVAR_FEM_5GHZ_TR_ISO: *result = siba->siba_sprom.fem.ghz5.tr_iso; break; case SIBA_SPROMVAR_FEM_5GHZ_ANTSWLUT: *result = siba->siba_sprom.fem.ghz5.antswlut; break; case SIBA_SPROMVAR_TXPID_2G_0: *result = siba->siba_sprom.txpid2g[0]; break; case SIBA_SPROMVAR_TXPID_2G_1: *result = siba->siba_sprom.txpid2g[1]; break; case SIBA_SPROMVAR_TXPID_2G_2: *result = siba->siba_sprom.txpid2g[2]; break; case SIBA_SPROMVAR_TXPID_2G_3: *result = siba->siba_sprom.txpid2g[3]; break; case SIBA_SPROMVAR_TXPID_5GL_0: *result = siba->siba_sprom.txpid5gl[0]; break; case SIBA_SPROMVAR_TXPID_5GL_1: *result = siba->siba_sprom.txpid5gl[1]; break; case SIBA_SPROMVAR_TXPID_5GL_2: *result = siba->siba_sprom.txpid5gl[2]; break; case SIBA_SPROMVAR_TXPID_5GL_3: *result = siba->siba_sprom.txpid5gl[3]; break; case SIBA_SPROMVAR_TXPID_5G_0: *result = siba->siba_sprom.txpid5g[0]; break; case SIBA_SPROMVAR_TXPID_5G_1: *result = siba->siba_sprom.txpid5g[1]; break; case SIBA_SPROMVAR_TXPID_5G_2: *result = siba->siba_sprom.txpid5g[2]; break; case SIBA_SPROMVAR_TXPID_5G_3: *result = siba->siba_sprom.txpid5g[3]; break; case SIBA_SPROMVAR_TXPID_5GH_0: *result = siba->siba_sprom.txpid5gh[0]; break; case SIBA_SPROMVAR_TXPID_5GH_1: *result = siba->siba_sprom.txpid5gh[1]; break; case SIBA_SPROMVAR_TXPID_5GH_2: *result = siba->siba_sprom.txpid5gh[2]; break; case SIBA_SPROMVAR_TXPID_5GH_3: *result = siba->siba_sprom.txpid5gh[3]; break; case SIBA_SPROMVAR_STBCPO: *result = siba->siba_sprom.stbcpo; break; case SIBA_SPROMVAR_CDDPO: *result = siba->siba_sprom.cddpo; break; default: return (ENOENT); } return (0); } int siba_write_sprom(device_t dev, device_t child, int which, uintptr_t value) { struct siba_dev_softc *sd = device_get_ivars(child); struct siba_softc *siba = sd->sd_bus; switch (which) { case SIBA_SPROMVAR_REV: siba->siba_sprom.rev = value; break; case SIBA_SPROMVAR_MII_ETH0: siba->siba_sprom.mii_eth0 = value; break; case SIBA_SPROMVAR_MII_ETH1: siba->siba_sprom.mii_eth1 = value; break; case SIBA_SPROMVAR_MDIO_ETH0: siba->siba_sprom.mdio_eth0 = value; break; case SIBA_SPROMVAR_MDIO_ETH1: siba->siba_sprom.mdio_eth1 = value; break; case SIBA_SPROMVAR_BREV: siba->siba_sprom.brev = value; break; case SIBA_SPROMVAR_CCODE: siba->siba_sprom.ccode = value; break; case SIBA_SPROMVAR_ANT_A: siba->siba_sprom.ant_a = value; break; case SIBA_SPROMVAR_ANT_BG: siba->siba_sprom.ant_bg = value; break; case SIBA_SPROMVAR_PA0B0: siba->siba_sprom.pa0b0 = value; break; case SIBA_SPROMVAR_PA0B1: siba->siba_sprom.pa0b1 = value; break; case SIBA_SPROMVAR_PA0B2: siba->siba_sprom.pa0b2 = value; break; case SIBA_SPROMVAR_PA1B0: siba->siba_sprom.pa1b0 = value; break; case SIBA_SPROMVAR_PA1B1: siba->siba_sprom.pa1b1 = value; break; case SIBA_SPROMVAR_PA1B2: siba->siba_sprom.pa1b2 = value; break; case SIBA_SPROMVAR_PA1LOB0: siba->siba_sprom.pa1lob0 = value; break; case SIBA_SPROMVAR_PA1LOB1: siba->siba_sprom.pa1lob1 = value; break; case SIBA_SPROMVAR_PA1LOB2: siba->siba_sprom.pa1lob2 = value; break; case SIBA_SPROMVAR_PA1HIB0: siba->siba_sprom.pa1hib0 = value; break; case SIBA_SPROMVAR_PA1HIB1: siba->siba_sprom.pa1hib1 = value; break; case SIBA_SPROMVAR_PA1HIB2: siba->siba_sprom.pa1hib2 = value; break; case SIBA_SPROMVAR_GPIO0: siba->siba_sprom.gpio0 = value; break; case SIBA_SPROMVAR_GPIO1: siba->siba_sprom.gpio1 = value; break; case SIBA_SPROMVAR_GPIO2: siba->siba_sprom.gpio2 = value; break; case SIBA_SPROMVAR_GPIO3: siba->siba_sprom.gpio3 = value; break; case SIBA_SPROMVAR_MAXPWR_AL: siba->siba_sprom.maxpwr_al = value; break; case SIBA_SPROMVAR_MAXPWR_A: siba->siba_sprom.maxpwr_a = value; break; case SIBA_SPROMVAR_MAXPWR_AH: siba->siba_sprom.maxpwr_ah = value; break; case SIBA_SPROMVAR_MAXPWR_BG: siba->siba_sprom.maxpwr_bg = value; break; case SIBA_SPROMVAR_RXPO2G: siba->siba_sprom.rxpo2g = value; break; case SIBA_SPROMVAR_RXPO5G: siba->siba_sprom.rxpo5g = value; break; case SIBA_SPROMVAR_TSSI_A: siba->siba_sprom.tssi_a = value; break; case SIBA_SPROMVAR_TSSI_BG: siba->siba_sprom.tssi_bg = value; break; case SIBA_SPROMVAR_TRI2G: siba->siba_sprom.tri2g = value; break; case SIBA_SPROMVAR_TRI5GL: siba->siba_sprom.tri5gl = value; break; case SIBA_SPROMVAR_TRI5G: siba->siba_sprom.tri5g = value; break; case SIBA_SPROMVAR_TRI5GH: siba->siba_sprom.tri5gh = value; break; case SIBA_SPROMVAR_RSSISAV2G: siba->siba_sprom.rssisav2g = value; break; case SIBA_SPROMVAR_RSSISMC2G: siba->siba_sprom.rssismc2g = value; break; case SIBA_SPROMVAR_RSSISMF2G: siba->siba_sprom.rssismf2g = value; break; case SIBA_SPROMVAR_BXA2G: siba->siba_sprom.bxa2g = value; break; case SIBA_SPROMVAR_RSSISAV5G: siba->siba_sprom.rssisav5g = value; break; case SIBA_SPROMVAR_RSSISMC5G: siba->siba_sprom.rssismc5g = value; break; case SIBA_SPROMVAR_RSSISMF5G: siba->siba_sprom.rssismf5g = value; break; case SIBA_SPROMVAR_BXA5G: siba->siba_sprom.bxa5g = value; break; case SIBA_SPROMVAR_CCK2GPO: siba->siba_sprom.cck2gpo = value; break; case SIBA_SPROMVAR_OFDM2GPO: siba->siba_sprom.ofdm2gpo = value; break; case SIBA_SPROMVAR_OFDM5GLPO: siba->siba_sprom.ofdm5glpo = value; break; case SIBA_SPROMVAR_OFDM5GPO: siba->siba_sprom.ofdm5gpo = value; break; case SIBA_SPROMVAR_OFDM5GHPO: siba->siba_sprom.ofdm5ghpo = value; break; case SIBA_SPROMVAR_BF_LO: siba->siba_sprom.bf_lo = value; break; case SIBA_SPROMVAR_BF_HI: siba->siba_sprom.bf_hi = value; break; case SIBA_SPROMVAR_BF2_LO: siba->siba_sprom.bf2_lo = value; break; case SIBA_SPROMVAR_BF2_HI: siba->siba_sprom.bf2_hi = value; break; default: return (ENOENT); } return (0); } #define SIBA_GPIOCTL 0x06c uint32_t siba_gpio_get(device_t dev) { struct siba_dev_softc *sd = device_get_ivars(dev); struct siba_softc *siba = sd->sd_bus; struct siba_dev_softc *gpiodev, *pcidev = NULL; pcidev = siba->siba_pci.spc_dev; gpiodev = siba->siba_cc.scc_dev ? siba->siba_cc.scc_dev : pcidev; if (!gpiodev) return (-1); return (siba_read_4_sub(gpiodev, SIBA_GPIOCTL)); } void siba_gpio_set(device_t dev, uint32_t value) { struct siba_dev_softc *sd = device_get_ivars(dev); struct siba_softc *siba = sd->sd_bus; struct siba_dev_softc *gpiodev, *pcidev = NULL; pcidev = siba->siba_pci.spc_dev; gpiodev = siba->siba_cc.scc_dev ? siba->siba_cc.scc_dev : pcidev; if (!gpiodev) return; siba_write_4_sub(gpiodev, SIBA_GPIOCTL, value); } void siba_fix_imcfglobug(device_t dev) { struct siba_dev_softc *sd = device_get_ivars(dev); struct siba_softc *siba = sd->sd_bus; uint32_t tmp; if (siba->siba_pci.spc_dev == NULL) return; if (siba->siba_pci.spc_dev->sd_id.sd_device != SIBA_DEVID_PCI || siba->siba_pci.spc_dev->sd_id.sd_rev > 5) return; tmp = siba_read_4_sub(sd, SIBA_IMCFGLO) & ~(SIBA_IMCFGLO_REQTO | SIBA_IMCFGLO_SERTO); switch (siba->siba_type) { case SIBA_TYPE_PCI: case SIBA_TYPE_PCMCIA: tmp |= 0x32; break; case SIBA_TYPE_SSB: tmp |= 0x53; break; } siba_write_4_sub(sd, SIBA_IMCFGLO, tmp); } int siba_sprom_get_core_power_info(device_t dev, int core, struct siba_sprom_core_pwr_info *c) { struct siba_dev_softc *sd = device_get_ivars(dev); struct siba_softc *siba = sd->sd_bus; if (core < 0 || core > 3) { return (EINVAL); } memcpy(c, &siba->siba_sprom.core_pwr_info[core], sizeof(*c)); return (0); } int siba_sprom_get_mcs2gpo(device_t dev, uint16_t *c) { struct siba_dev_softc *sd = device_get_ivars(dev); struct siba_softc *siba = sd->sd_bus; memcpy(c, &siba->siba_sprom.mcs2gpo, sizeof(uint16_t) * 8); return (0); } int siba_sprom_get_mcs5glpo(device_t dev, uint16_t *c) { struct siba_dev_softc *sd = device_get_ivars(dev); struct siba_softc *siba = sd->sd_bus; memcpy(c, &siba->siba_sprom.mcs5glpo, sizeof(uint16_t) * 8); return (0); } int siba_sprom_get_mcs5gpo(device_t dev, uint16_t *c) { struct siba_dev_softc *sd = device_get_ivars(dev); struct siba_softc *siba = sd->sd_bus; memcpy(c, &siba->siba_sprom.mcs5gpo, sizeof(uint16_t) * 8); return (0); } int siba_sprom_get_mcs5ghpo(device_t dev, uint16_t *c) { struct siba_dev_softc *sd = device_get_ivars(dev); struct siba_softc *siba = sd->sd_bus; memcpy(c, &siba->siba_sprom.mcs5ghpo, sizeof(uint16_t) * 8); return (0); } void siba_pmu_spuravoid_pllupdate(device_t dev, int spur_avoid) { struct siba_dev_softc *sd = device_get_ivars(dev); struct siba_softc *siba = sd->sd_bus; struct siba_cc *scc; scc = &siba->siba_cc; if (scc->scc_dev == NULL) { device_printf(dev, "%s: called; no pmu\n", __func__); return; } switch (siba_get_chipid(dev)) { case 0x4322: siba_cc_pll_write(scc, SIBA_CC_PMU1_PLL0, 0x11100070); siba_cc_pll_write(scc, SIBA_CC_PMU1_PLL1, 0x1014140a); siba_cc_pll_write(scc, SIBA_CC_PMU1_PLL5, 0x88888854); if (spur_avoid == 1) siba_cc_pll_write(scc, SIBA_CC_PMU1_PLL2, 0x05201828); else siba_cc_pll_write(scc, SIBA_CC_PMU1_PLL2, 0x05001828); break; case 43222: if (spur_avoid == 1) { siba_cc_pll_write(scc, SIBA_CC_PMU1_PLL0, 0x11500008); siba_cc_pll_write(scc, SIBA_CC_PMU1_PLL1, 0x0C000C06); siba_cc_pll_write(scc, SIBA_CC_PMU1_PLL2, 0x0F600a08); siba_cc_pll_write(scc, SIBA_CC_PMU1_PLL3, 0x00000000); siba_cc_pll_write(scc, SIBA_CC_PMU1_PLL4, 0x2001E920); siba_cc_pll_write(scc, SIBA_CC_PMU1_PLL5, 0x88888815); } else { siba_cc_pll_write(scc, SIBA_CC_PMU1_PLL0, 0x11100008); siba_cc_pll_write(scc, SIBA_CC_PMU1_PLL1, 0x0c000c06); siba_cc_pll_write(scc, SIBA_CC_PMU1_PLL2, 0x03000a08); siba_cc_pll_write(scc, SIBA_CC_PMU1_PLL3, 0x00000000); siba_cc_pll_write(scc, SIBA_CC_PMU1_PLL4, 0x200005c0); siba_cc_pll_write(scc, SIBA_CC_PMU1_PLL5, 0x88888855); } break; default: device_printf(dev, "%s: unknown spur avoidance settings for chip 0x%04x\n", __func__, siba_get_chipid(dev)); return; } /* Both chips above use the same update */ SIBA_CC_SET32(scc, SIBA_CC_PMUCTL, SIBA_CC_PMUCTL_PLL_UPD); } void siba_cc_set32(device_t dev, uint32_t reg, uint32_t val) { struct siba_dev_softc *sd = device_get_ivars(dev); struct siba_softc *siba = sd->sd_bus; struct siba_cc *scc; scc = &siba->siba_cc; if (scc->scc_dev == NULL) { device_printf(dev, "%s: called; no pmu\n", __func__); return; } SIBA_CC_SET32(scc, reg, val); } void siba_cc_mask32(device_t dev, uint32_t reg, uint32_t mask) { struct siba_dev_softc *sd = device_get_ivars(dev); struct siba_softc *siba = sd->sd_bus; struct siba_cc *scc; scc = &siba->siba_cc; if (scc->scc_dev == NULL) { device_printf(dev, "%s: called; no pmu\n", __func__); return; } SIBA_CC_MASK32(scc, reg, mask); } uint32_t siba_cc_read32(device_t dev, uint32_t reg) { struct siba_dev_softc *sd = device_get_ivars(dev); struct siba_softc *siba = sd->sd_bus; struct siba_cc *scc; scc = &siba->siba_cc; if (scc->scc_dev == NULL) { device_printf(dev, "%s: called; no pmu\n", __func__); return 0xffffffff; } return SIBA_CC_READ32(scc, reg); } void siba_cc_write32(device_t dev, uint32_t reg, uint32_t val) { struct siba_dev_softc *sd = device_get_ivars(dev); struct siba_softc *siba = sd->sd_bus; struct siba_cc *scc; scc = &siba->siba_cc; if (scc->scc_dev == NULL) { device_printf(dev, "%s: called; no pmu\n", __func__); return; } SIBA_CC_WRITE32(scc, reg, val); }