freebsd-nq/sys/dev/siba/siba_core.c

2579 lines
69 KiB
C
Raw Normal View History

/*-
* Copyright (c) 2009-2010 Weongyo Jeong <weongyo@freebsd.org>
* 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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
/*
* the Sonics Silicon Backplane driver.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/module.h>
#include <sys/kernel.h>
#include <sys/endian.h>
#include <sys/errno.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <machine/bus.h>
#include <machine/resource.h>
#include <sys/bus.h>
#include <sys/rman.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/if_media.h>
#include <net/if_arp.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcireg.h>
#include <dev/siba/siba_ids.h>
#include <dev/siba/sibareg.h>
#include <dev/siba/sibavar.h>
#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 *);
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.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_cap(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++;
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 = 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))
#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_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_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));
}
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;
struct siba_softc *siba;
if (sd == NULL)
return;
siba = sd->sd_bus;
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;
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);
}