static bool _dma32_addrext(osl_t *osh, dma32regs_t *dma32regs) { uint32 w; OR_REG(osh, &dma32regs->control, XC_AE); w = R_REG(osh, &dma32regs->control); AND_REG(osh, &dma32regs->control, ~XC_AE); return ((w & XC_AE) == XC_AE); }
static void chipduplexupd(struct bcm4xxx *ch) { uint32 txcontrol; txcontrol = R_REG(ch->osh, &ch->regs->txcontrol); if (ch->etc->duplex && !(txcontrol & EXC_FD)) OR_REG(ch->osh, &ch->regs->txcontrol, EXC_FD); else if (!ch->etc->duplex && (txcontrol & EXC_FD)) AND_REG(ch->osh, &ch->regs->txcontrol, ~EXC_FD); }
static void chipenablepme(struct bcm4xxx *ch) { bcmenetregs_t *regs; regs = ch->regs; /* enable chip wakeup pattern matching */ OR_REG(ch->osh, ®s->devcontrol, DC_PM); /* enable sonics bus PME */ si_core_cflags(ch->sih, SICF_PME_EN, SICF_PME_EN); }
/* initialize PMU */ void si_pmu_init(struct si_pub *sih) { chipcregs_t *cc; uint origidx; /* Remember original core before switch to chipc */ origidx = ai_coreidx(sih); cc = ai_setcoreidx(sih, SI_CC_IDX); if (sih->pmurev == 1) AND_REG(&cc->pmucontrol, ~PCTL_NOILP_ON_WAIT); else if (sih->pmurev >= 2) OR_REG(&cc->pmucontrol, PCTL_NOILP_ON_WAIT); /* Return to original core */ ai_setcoreidx(sih, origidx); }
int sflash_write(si_t *sih, chipcregs_t *cc, uint offset, uint length, const uchar *buffer) { struct sflash *sfl; uint off = offset, len = length; const uint8 *buf = buffer; uint8 data; int ret = 0, ntry = 0; bool is4712b0; uint32 page, byte, mask; osl_t *osh; ASSERT(sih); osh = si_osh(sih); if (!len) return 0; sfl = &sflash; if ((off + len) > sfl->size) return -22; switch (sfl->type) { case SFLASH_ST: is4712b0 = (CHIPID(sih->chip) == BCM4712_CHIP_ID) && (CHIPREV(sih->chiprev) == 3); /* Enable writes */ retry: sflash_cmd(osh, cc, SFLASH_ST_WREN); off = offset; len = length; buf = buffer; ntry++; if (is4712b0) { mask = 1 << 14; W_REG(osh, &cc->flashaddress, off); data = GET_BYTE(buf); buf++; W_REG(osh, &cc->flashdata, data); /* Set chip select */ OR_REG(osh, &cc->gpioout, mask); /* Issue a page program with the first byte */ sflash_cmd(osh, cc, SFLASH_ST_PP); ret = 1; off++; len--; while (len > 0) { if ((off & 255) == 0) { /* Page boundary, drop cs and return */ AND_REG(osh, &cc->gpioout, ~mask); OSL_DELAY(1); if (!sflash_poll(sih, cc, off)) { /* Flash rejected command */ if (ntry <= ST_RETRIES) goto retry; else return -11; } return ret; } else { /* Write single byte */ data = GET_BYTE(buf); buf++; sflash_cmd(osh, cc, data); } ret++; off++; len--; } /* All done, drop cs */ AND_REG(osh, &cc->gpioout, ~mask); OSL_DELAY(1); if (!sflash_poll(sih, cc, off)) { /* Flash rejected command */ if (ntry <= ST_RETRIES) goto retry; else return -12; } } else if (sih->ccrev >= 20) { W_REG(osh, &cc->flashaddress, off); data = GET_BYTE(buf); buf++; W_REG(osh, &cc->flashdata, data); /* Issue a page program with CSA bit set */ sflash_cmd(osh, cc, SFLASH_ST_CSA | SFLASH_ST_PP); ret = 1; off++; len--; while (len > 0) { if ((off & 255) == 0) { /* Page boundary, poll droping cs and return */ W_REG(NULL, &cc->flashcontrol, 0); OSL_DELAY(1); if (sflash_poll(sih, cc, off) == 0) { /* Flash rejected command */ SFL_MSG(("sflash: pp rejected, ntry: %d," " off: %d/%d, len: %d/%d, ret:" "%d\n", ntry, off, offset, len, length, ret)); if (ntry <= ST_RETRIES) goto retry; else return -11; } return ret; } else { /* Write single byte */ data = GET_BYTE(buf); buf++; sflash_cmd(osh, cc, SFLASH_ST_CSA | data); } ret++; off++; len--; } /* All done, drop cs & poll */ W_REG(NULL, &cc->flashcontrol, 0); OSL_DELAY(1); if (sflash_poll(sih, cc, off) == 0) { /* Flash rejected command */ SFL_MSG(("sflash: pp rejected, ntry: %d, off: %d/%d," " len: %d/%d, ret: %d\n", ntry, off, offset, len, length, ret)); if (ntry <= ST_RETRIES) goto retry; else return -12; } } else { ret = 1; W_REG(osh, &cc->flashaddress, off); data = GET_BYTE(buf); buf++; W_REG(osh, &cc->flashdata, data); /* Page program */ sflash_cmd(osh, cc, SFLASH_ST_PP); } break; case SFLASH_AT: mask = sfl->blocksize - 1; page = (off & ~mask) << 1; byte = off & mask; /* Read main memory page into buffer 1 */ if (byte || (len < sfl->blocksize)) { W_REG(osh, &cc->flashaddress, page); sflash_cmd(osh, cc, SFLASH_AT_BUF1_LOAD); /* 250 us for AT45DB321B */ SPINWAIT(sflash_poll(sih, cc, off), 1000); ASSERT(!sflash_poll(sih, cc, off)); } /* Write into buffer 1 */ for (ret = 0; (ret < (int)len) && (byte < sfl->blocksize); ret++) { W_REG(osh, &cc->flashaddress, byte++); W_REG(osh, &cc->flashdata, *buf++); sflash_cmd(osh, cc, SFLASH_AT_BUF1_WRITE); } /* Write buffer 1 into main memory page */ W_REG(osh, &cc->flashaddress, page); sflash_cmd(osh, cc, SFLASH_AT_BUF1_PROGRAM); break; } return ret; }
static bool si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, uint32 savewin, uint *origidx, void *regs) { bool pci, pcie; uint i; uint pciidx, pcieidx, pcirev, pcierev; cc = si_setcoreidx(&sii->pub, SI_CC_IDX); ASSERT((uintptr)cc); /* get chipcommon rev */ sii->pub.ccrev = (int)si_corerev(&sii->pub); /* get chipcommon chipstatus */ if (sii->pub.ccrev >= 11) sii->pub.chipst = R_REG(sii->osh, &cc->chipstatus); /* get chipcommon capabilites */ sii->pub.cccaps = R_REG(sii->osh, &cc->capabilities); /* get pmu rev and caps */ if (sii->pub.cccaps & CC_CAP_PMU) { sii->pub.pmucaps = R_REG(sii->osh, &cc->pmucapabilities); sii->pub.pmurev = sii->pub.pmucaps & PCAP_REV_MASK; } SI_MSG(("Chipc: rev %d, caps 0x%x, chipst 0x%x pmurev %d, pmucaps 0x%x\n", sii->pub.ccrev, sii->pub.cccaps, sii->pub.chipst, sii->pub.pmurev, sii->pub.pmucaps)); /* figure out bus/orignal core idx */ sii->pub.buscoretype = NODEV_CORE_ID; sii->pub.buscorerev = NOREV; sii->pub.buscoreidx = BADIDX; pci = pcie = FALSE; pcirev = pcierev = NOREV; pciidx = pcieidx = BADIDX; for (i = 0; i < sii->numcores; i++) { uint cid, crev; si_setcoreidx(&sii->pub, i); cid = si_coreid(&sii->pub); crev = si_corerev(&sii->pub); /* Display cores found */ SI_MSG(("CORE[%d]: id 0x%x rev %d base 0x%x regs 0x%p\n", i, cid, crev, sii->common_info->coresba[i], sii->common_info->regs[i])); if (BUSTYPE(bustype) == PCI_BUS) { if (cid == PCI_CORE_ID) { pciidx = i; pcirev = crev; pci = TRUE; } else if (cid == PCIE_CORE_ID) { pcieidx = i; pcierev = crev; pcie = TRUE; } } else if ((BUSTYPE(bustype) == PCMCIA_BUS) && (cid == PCMCIA_CORE_ID)) { sii->pub.buscorerev = crev; sii->pub.buscoretype = cid; sii->pub.buscoreidx = i; } else if (((BUSTYPE(bustype) == SDIO_BUS) || (BUSTYPE(bustype) == SPI_BUS)) && ((cid == PCMCIA_CORE_ID) || (cid == SDIOD_CORE_ID))) { sii->pub.buscorerev = crev; sii->pub.buscoretype = cid; sii->pub.buscoreidx = i; } /* find the core idx before entering this func. */ if ((savewin && (savewin == sii->common_info->coresba[i])) || (regs == sii->common_info->regs[i])) *origidx = i; } SI_MSG(("Buscore id/type/rev %d/0x%x/%d\n", sii->pub.buscoreidx, sii->pub.buscoretype, sii->pub.buscorerev)); if (BUSTYPE(sii->pub.bustype) == SI_BUS && (CHIPID(sii->pub.chip) == BCM4712_CHIP_ID) && (sii->pub.chippkg != BCM4712LARGE_PKG_ID) && (sii->pub.chiprev <= 3)) OR_REG(sii->osh, &cc->slow_clk_ctl, SCC_SS_XTAL); /* Make sure any on-chip ARM is off (in case strapping is wrong), or downloaded code was * already running. */ if ((BUSTYPE(bustype) == SDIO_BUS) || (BUSTYPE(bustype) == SPI_BUS)) { if (si_setcore(&sii->pub, ARM7S_CORE_ID, 0) || si_setcore(&sii->pub, ARMCM3_CORE_ID, 0)) si_core_disable(&sii->pub, 0); } /* return to the original core */ si_setcoreidx(&sii->pub, *origidx); return TRUE; }
/* Write len bytes starting at offset into buf. Returns number of bytes * written. Caller should poll for completion. */ int sflash_write(chipcregs_t *cc, uint offset, uint len, const uchar *buf) { struct sflash *sfl; int ret = 0; bool is4712b0; uint32 page, byte, mask; if (!len) return 0; if ((offset + len) > sflash.size) return -22; sfl = &sflash; switch (sfl->type) { case SFLASH_ST: mask = R_REG(NULL, &cc->chipid); is4712b0 = (((mask & CID_ID_MASK) == BCM4712_CHIP_ID) && ((mask & CID_REV_MASK) == (3 << CID_REV_SHIFT))); /* Enable writes */ sflash_cmd(cc, SFLASH_ST_WREN); if (is4712b0) { mask = 1 << 14; W_REG(NULL, &cc->flashaddress, offset); W_REG(NULL, &cc->flashdata, *buf++); /* Set chip select */ OR_REG(NULL, &cc->gpioout, mask); /* Issue a page program with the first byte */ sflash_cmd(cc, SFLASH_ST_PP); ret = 1; offset++; len--; while (len > 0) { if ((offset & 255) == 0) { /* Page boundary, drop cs and return */ AND_REG(NULL, &cc->gpioout, ~mask); if (!sflash_poll(cc, offset)) { /* Flash rejected command */ return -11; } return ret; } else { /* Write single byte */ sflash_cmd(cc, *buf++); } ret++; offset++; len--; } /* All done, drop cs if needed */ if ((offset & 255) != 1) { /* Drop cs */ AND_REG(NULL, &cc->gpioout, ~mask); if (!sflash_poll(cc, offset)) { /* Flash rejected command */ return -12; } } } else { ret = 1; W_REG(NULL, &cc->flashaddress, offset); W_REG(NULL, &cc->flashdata, *buf); /* Page program */ sflash_cmd(cc, SFLASH_ST_PP); } break; case SFLASH_AT: mask = sfl->blocksize - 1; page = (offset & ~mask) << 1; byte = offset & mask; /* Read main memory page into buffer 1 */ if (byte || (len < sfl->blocksize)) { W_REG(NULL, &cc->flashaddress, page); sflash_cmd(cc, SFLASH_AT_BUF1_LOAD); /* 250 us for AT45DB321B */ SPINWAIT(sflash_poll(cc, offset), 1000); ASSERT(!sflash_poll(cc, offset)); } /* Write into buffer 1 */ for (ret = 0; (ret < (int)len) && (byte < sfl->blocksize); ret++) { W_REG(NULL, &cc->flashaddress, byte++); W_REG(NULL, &cc->flashdata, *buf++); sflash_cmd(cc, SFLASH_AT_BUF1_WRITE); } /* Write buffer 1 into main memory page */ W_REG(NULL, &cc->flashaddress, page); sflash_cmd(cc, SFLASH_AT_BUF1_PROGRAM); break; } return ret; }
/* * Setup the gige core. * Resetting the core will lose all settings. */ void hndgige_init(si_t *sih, uint32 unit, bool *rgmii) { volatile pci_config_regs *pci; sbgige_pcishim_t *ocp; sbconfig_t *sb; osl_t *osh; uint32 statelow; uint32 statehigh; uint32 base; uint32 idx; void *regs; /* Sanity checks */ ASSERT(sih); ASSERT(rgmii); idx = si_coreidx(sih); /* point to the gige core registers */ regs = si_setcore(sih, GIGETH_CORE_ID, unit); ASSERT(regs); osh = si_osh(sih); pci = &((sbgige_t *)regs)->pcicfg; ocp = &((sbgige_t *)regs)->pcishim; sb = &((sbgige_t *)regs)->sbconfig; /* Enable the core clock and memory access */ if (!si_iscoreup(sih)) si_core_reset(sih, 0, 0); /* * Setup the 64K memory-mapped region base address through BAR0. * Leave the other BAR values alone. */ base = si_addrspace(sih, 1); W_REG(osh, &pci->base[0], base); W_REG(osh, &pci->base[1], 0); /* * Enable the PCI memory access anyway. Any PCI config commands * issued before the core is enabled will go to the emulation * only and will not go to the real PCI config registers. */ OR_REG(osh, &pci->command, 2); /* * Enable the posted write flush scheme as follows: * * - Enable flush on any core register read * - Enable timeout on the flush * - Disable the interrupt mask when flushing * * This differs from the default setting only in that interrupts are * not masked. Since posted writes are not flushed on interrupt, the * driver must explicitly request a flush in its interrupt handling * by reading a core register. */ W_REG(osh, &ocp->FlushStatusControl, 0x68); /* * Determine whether the GbE is in GMII or RGMII mode. This is * indicated in bit 16 of the SBTMStateHigh register, which is * part of the core-specific flags field. * * For GMII, bypass the Rx/Tx DLLs, i.e. add no delay to RXC/GTXC * within the core. For RGMII, do not bypass the DLLs, resulting * in added delay for RXC/GTXC. The SBTMStateLow register contains * the controls for doing this in the core-specific flags field: * * bit 24 - Enable DLL controls * bit 20 - Bypass Rx DLL * bit 19 - Bypass Tx DLL */ statelow = R_REG(osh, &sb->sbtmstatelow); /* DLL controls */ statehigh = R_REG(osh, &sb->sbtmstatehigh); /* GMII/RGMII mode */ if ((statehigh & (1 << 16)) != 0) /* RGMII */ { statelow &= ~(1 << 20); /* no Rx bypass (delay) */ statelow &= ~(1 << 19); /* no Tx bypass (delay) */ *rgmii = TRUE; } else /* GMII */ { statelow |= (1 << 20); /* Rx bypass (no delay) */ statelow |= (1 << 19); /* Tx bypass (no delay) */ *rgmii = FALSE; } statelow |= (1 << 24); /* enable DLL controls */ W_REG(osh, &sb->sbtmstatelow, statelow); si_setcoreidx(sih, idx); }
/* * Initializes UART access. The callback function will be called once * per found UART. */ void BCMATTACHFN(si_serial_init)(si_t *sih, si_serial_init_fn add) { osl_t *osh; void *regs; chipcregs_t *cc; uint32 rev, cap, pll, baud_base, div; uint irq; int i, n; osh = si_osh(sih); cc = (chipcregs_t *)si_setcoreidx(sih, SI_CC_IDX); ASSERT(cc); /* Determine core revision and capabilities */ rev = sih->ccrev; cap = sih->cccaps; pll = cap & CC_CAP_PLL_MASK; /* Determine IRQ */ irq = si_irq(sih); if (CCPLL_ENAB(sih) && pll == PLL_TYPE1) { /* PLL clock */ baud_base = si_clock_rate(pll, R_REG(osh, &cc->clockcontrol_n), R_REG(osh, &cc->clockcontrol_m2)); div = 1; } else { /* Fixed ALP clock */ if (rev >= 11 && rev != 15) { baud_base = si_alp_clock(sih); div = 1; /* Turn off UART clock before switching clock source */ if (rev >= 21) AND_REG(osh, &cc->corecontrol, ~CC_UARTCLKEN); /* Set the override bit so we don't divide it */ OR_REG(osh, &cc->corecontrol, CC_UARTCLKO); if (rev >= 21) OR_REG(osh, &cc->corecontrol, CC_UARTCLKEN); } else if (rev >= 3) { /* Internal backplane clock */ baud_base = si_clock(sih); div = 2; /* Minimum divisor */ W_REG(osh, &cc->clkdiv, ((R_REG(osh, &cc->clkdiv) & ~CLKD_UART) | div)); } else { /* Fixed internal backplane clock */ baud_base = 88000000; div = 48; } /* Clock source depends on strapping if UartClkOverride is unset */ if ((R_REG(osh, &cc->corecontrol) & CC_UARTCLKO) == 0) { if ((cap & CC_CAP_UCLKSEL) == CC_CAP_UINTCLK) { /* Internal divided backplane clock */ baud_base /= div; } else { /* Assume external clock of 1.8432 MHz */ baud_base = 1843200; } } } /* Add internal UARTs */ n = cap & CC_CAP_UARTS_MASK; for (i = 0; i < n; i++) { regs = (void *)((ulong) &cc->uart0data + (i * 256)); if (add) add(regs, irq, baud_base, 0); } }
/* * Initializes UART access. The callback function will be called once * per found UART. */ void BCMINITFN(sb_serial_init) (sb_t * sbh, sb_serial_init_fn add) { osl_t *osh; void *regs; chipcregs_t *cc; uint32 rev, cap, pll, baud_base, div; uint irq; int i, n; osh = sb_osh(sbh); regs = sb_setcore(sbh, SB_EXTIF, 0); if (regs) { sb_extif_serial_init(sbh, regs, add); return; } cc = (chipcregs_t *) sb_setcore(sbh, SB_CC, 0); ASSERT(cc); /* Determine core revision and capabilities */ rev = sbh->ccrev; cap = sbh->cccaps; pll = cap & CC_CAP_PLL_MASK; /* Determine IRQ */ irq = sb_irq(sbh); if (pll == PLL_TYPE1) { /* PLL clock */ baud_base = sb_clock_rate(pll, R_REG(osh, &cc->clockcontrol_n), R_REG(osh, &cc->clockcontrol_m2)); div = 1; } else { /* 5354 chip common uart uses a constant clock * frequency of 25MHz */ if (sb_corerev(sbh) == 20) { /* Set the override bit so we don't divide it */ W_REG(osh, &cc->corecontrol, CC_UARTCLKO); baud_base = 25000000; } else if (rev >= 11 && rev != 15) { /* Fixed ALP clock */ baud_base = sb_alp_clock(sbh); div = 1; /* Turn off UART clock before switching clock source */ if (rev >= 21) AND_REG(osh, &cc->corecontrol, ~CC_UARTCLKEN); /* Set the override bit so we don't divide it */ OR_REG(osh, &cc->corecontrol, CC_UARTCLKO); if (rev >= 21) OR_REG(osh, &cc->corecontrol, CC_UARTCLKEN); } else if (rev >= 3) { /* Internal backplane clock */ baud_base = sb_clock(sbh); div = 2; /* Minimum divisor */ W_REG(osh, &cc->clkdiv, ((R_REG(osh, &cc->clkdiv) & ~CLKD_UART) | div)); } else { /* Fixed internal backplane clock */ baud_base = 88000000; div = 48; } /* Clock source depends on strapping if UartClkOverride is unset */ if ((rev > 0) && ((R_REG(osh, &cc->corecontrol) & CC_UARTCLKO) == 0)) { if ((cap & CC_CAP_UCLKSEL) == CC_CAP_UINTCLK) { /* Internal divided backplane clock */ baud_base /= div; } else { /* Assume external clock of 1.8432 MHz */ baud_base = 1843200; } } } /* Add internal UARTs */ n = cap & CC_CAP_UARTS_MASK; for (i = 0; i < n; i++) { /* Register offset changed after revision 0 */ if (rev) regs = (void *)((ulong) & cc->uart0data + (i * 256)); else regs = (void *)((ulong) & cc->uart0data + (i * 8)); if (add) add(regs, irq, baud_base, 0); } }
/** * Balance between stable SDIO operation and power consumption is achieved using this function. * Note that each drive strength table is for a specific VDDIO of the SDIO pads, ideally this * function should read the VDDIO itself to select the correct table. For now it has been solved * with the 'BCM_SDIO_VDDIO' preprocessor constant. * * 'drivestrength': desired pad drive strength in mA. Drive strength of 0 requests tri-state (if * hardware supports this), if no hw support drive strength is not programmed. */ void si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, uint32 drivestrength) { chipcregs_t *cc; uint origidx, intr_val = 0; sdiod_drive_str_t *str_tab = NULL; uint32 str_mask = 0; /* only alter desired bits in PMU chipcontrol 1 register */ uint32 str_shift = 0; uint32 str_ovr_pmuctl = PMU_CHIPCTL0; /* PMU chipcontrol register containing override bit */ uint32 str_ovr_pmuval = 0; /* position of bit within this register */ if (!(sih->cccaps & CC_CAP_PMU)) { return; } /* Remember original core before switch to chipc */ cc = (chipcregs_t *) si_switch_core(sih, CC_CORE_ID, &origidx, &intr_val); switch (SDIOD_DRVSTR_KEY(sih->chip, sih->pmurev)) { case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 1): str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab1; str_mask = 0x30000000; str_shift = 28; break; case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 2): case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 3): case SDIOD_DRVSTR_KEY(BCM4315_CHIP_ID, 4): str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab2; str_mask = 0x00003800; str_shift = 11; break; case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 8): case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 11): if (sih->pmurev == 8) { str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab3; } else if (sih->pmurev == 11) { str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab4_1v8; } str_mask = 0x00003800; str_shift = 11; break; case SDIOD_DRVSTR_KEY(BCM4330_CHIP_ID, 12): str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab4_1v8; str_mask = 0x00003800; str_shift = 11; break; case SDIOD_DRVSTR_KEY(BCM43362_CHIP_ID, 13): str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab5_1v8; str_mask = 0x00003800; str_shift = 11; break; case SDIOD_DRVSTR_KEY(BCM4334_CHIP_ID, 17): str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab6_1v8; str_mask = 0x00001800; str_shift = 11; break; case SDIOD_DRVSTR_KEY(BCM43143_CHIP_ID, 17): #if !defined(BCM_SDIO_VDDIO) || BCM_SDIO_VDDIO == 33 if (drivestrength >= ARRAYLAST(sdiod_drive_strength_tab7_3v3)->strength) { str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab7_3v3; } #else if (drivestrength >= ARRAYLAST(sdiod_drive_strength_tab7_1v8)->strength) { str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab7_1v8; } #endif /* BCM_SDIO_VDDIO */ str_mask = 0x00000007; str_ovr_pmuval = PMU43143_CC0_SDIO_DRSTR_OVR; break; default: PMU_MSG(("No SDIO Drive strength init done for chip %s rev %d pmurev %d\n", bcm_chipname(sih->chip, chn, 8), sih->chiprev, sih->pmurev)); break; } if (str_tab != NULL && cc != NULL) { uint32 cc_data_temp; int i; /* Pick the lowest available drive strength equal or greater than the * requested strength. Drive strength of 0 requests tri-state. */ for (i = 0; drivestrength < str_tab[i].strength; i++) ; if (i > 0 && drivestrength > str_tab[i].strength) i--; W_REG(osh, &cc->chipcontrol_addr, PMU_CHIPCTL1); cc_data_temp = R_REG(osh, &cc->chipcontrol_data); cc_data_temp &= ~str_mask; cc_data_temp |= str_tab[i].sel << str_shift; W_REG(osh, &cc->chipcontrol_data, cc_data_temp); if (str_ovr_pmuval) { /* enables the selected drive strength */ W_REG(osh, &cc->chipcontrol_addr, str_ovr_pmuctl); OR_REG(osh, &cc->chipcontrol_data, str_ovr_pmuval); } PMU_MSG(("SDIO: %dmA drive strength requested; set to %dmA\n", drivestrength, str_tab[i].strength)); } /* Return to original core */ si_restore_core(sih, origidx, intr_val); } /* si_sdiod_drive_strength_init */
void si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, uint32 drivestrength) { chipcregs_t *cc; uint origidx, intr_val = 0; sdiod_drive_str_t *str_tab = NULL; uint32 str_mask = 0; uint32 str_shift = 0; uint32 str_ovr_pmuctl = PMU_CHIPCTL0; uint32 str_ovr_pmuval = 0; if (!(sih->cccaps & CC_CAP_PMU)) { return; } cc = (chipcregs_t *) si_switch_core(sih, CC_CORE_ID, &origidx, &intr_val); switch (SDIOD_DRVSTR_KEY(sih->chip, sih->pmurev)) { case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 1): str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab1; str_mask = 0x30000000; str_shift = 28; break; case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 2): case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 3): case SDIOD_DRVSTR_KEY(BCM4315_CHIP_ID, 4): str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab2; str_mask = 0x00003800; str_shift = 11; break; case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 8): case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 11): if (sih->pmurev == 8) { str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab3; } else if (sih->pmurev == 11) { str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab4_1v8; } str_mask = 0x00003800; str_shift = 11; break; case SDIOD_DRVSTR_KEY(BCM4330_CHIP_ID, 12): str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab4_1v8; str_mask = 0x00003800; str_shift = 11; break; case SDIOD_DRVSTR_KEY(BCM43362_CHIP_ID, 13): str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab5_1v8; str_mask = 0x00003800; str_shift = 11; break; case SDIOD_DRVSTR_KEY(BCM4334_CHIP_ID, 17): str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab6_1v8; str_mask = 0x00001800; str_shift = 11; break; case SDIOD_DRVSTR_KEY(BCM43143_CHIP_ID, 17): #if !defined(BCM_SDIO_VDDIO) || BCM_SDIO_VDDIO == 33 if (drivestrength >= ARRAYLAST(sdiod_drive_strength_tab7_3v3)->strength) { str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab7_3v3; } #else if (drivestrength >= ARRAYLAST(sdiod_drive_strength_tab7_1v8)->strength) { str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab7_1v8; } #endif str_mask = 0x00000007; str_ovr_pmuval = PMU43143_CC0_SDIO_DRSTR_OVR; break; default: PMU_MSG(("No SDIO Drive strength init done for chip %s rev %d pmurev %d\n", bcm_chipname(sih->chip, chn, 8), sih->chiprev, sih->pmurev)); break; } if (str_tab != NULL && cc != NULL) { uint32 cc_data_temp; int i; for (i = 0; drivestrength < str_tab[i].strength; i++) ; if (i > 0 && drivestrength > str_tab[i].strength) i--; if( cc!= NULL ) { W_REG(osh, &cc->chipcontrol_addr, PMU_CHIPCTL1); cc_data_temp = R_REG(osh, &cc->chipcontrol_data); cc_data_temp &= ~str_mask; cc_data_temp |= str_tab[i].sel << str_shift; W_REG(osh, &cc->chipcontrol_data, cc_data_temp); if (str_ovr_pmuval) { W_REG(osh, &cc->chipcontrol_addr, str_ovr_pmuctl); OR_REG(osh, &cc->chipcontrol_data, str_ovr_pmuval); } PMU_MSG(("SDIO: %dmA drive strength requested; set to %dmA\n", drivestrength, str_tab[i].strength)); } } si_restore_core(sih, origidx, intr_val); }
/* * Initializes UART access. The callback function will be called once * per found UART. */ void BCMINITFN(si_serial_init)(si_t *sih, si_serial_init_fn add, uint32 baudrate) { osl_t *osh; void *regs; chipcregs_t *cc; uint32 rev, cap, pll, baud_base, div; uint irq; int i, n; osh = si_osh(sih); cc = (chipcregs_t *)si_setcoreidx(sih, SI_CC_IDX); ASSERT(cc); /* Determine core revision and capabilities */ rev = sih->ccrev; cap = sih->cccaps; pll = cap & CC_CAP_PLL_MASK; /* Determine IRQ */ irq = si_irq(sih); if (CCPLL_ENAB(sih) && pll == PLL_TYPE1) { /* PLL clock */ baud_base = si_clock_rate(pll, R_REG(osh, &cc->clockcontrol_n), R_REG(osh, &cc->clockcontrol_m2)); div = 1; } else { /* Fixed ALP clock */ /* XXX rev. 15 in 4785 breaks the rule! */ if (rev >= 11 && rev != 15) { baud_base = si_alp_clock(sih); div = 1; /* * If baudrate parameter is given with a non-zero value, * UART clock will be divided for the given baud rate before * feeding into UART module. * Note: UART driver could also adjust UART module's divider for * clock fine tunning. */ if (baudrate) { /* Turn off UART clock before switching clock source */ if (rev >= 21) AND_REG(osh, &cc->corecontrol, ~CC_UARTCLKEN); /* Don't set the override bit so we divide it */ AND_REG(osh, &cc->corecontrol, ~CC_UARTCLKO); div = baud_base / (baudrate * 16); div = (div + 1) & ~0x1; AND_REG(osh, &cc->clkdiv, ~CLKD_UART); OR_REG(osh, &cc->clkdiv, div); /* Turn back UART clock on */ if (rev >= 21) OR_REG(osh, &cc->corecontrol, CC_UARTCLKEN); } else { /* Turn off UART clock before switching clock source */ if (rev >= 21) AND_REG(osh, &cc->corecontrol, ~CC_UARTCLKEN); OR_REG(osh, &cc->corecontrol, CC_UARTCLKO); /* Turn back UART clock on */ if (rev >= 21) OR_REG(osh, &cc->corecontrol, CC_UARTCLKEN); } if (CONSOLE_TTY == 1) { /* Use UART1, enable "UART1 use GPIO" bit */ OR_REG(osh, &cc->corecontrol, 0x80); } } else if (rev >= 3) { /* Internal backplane clock */ baud_base = si_clock(sih); div = 2; /* Minimum divisor */ W_REG(osh, &cc->clkdiv, ((R_REG(osh, &cc->clkdiv) & ~CLKD_UART) | div)); } else { /* Fixed internal backplane clock */ baud_base = 88000000; div = 48; } /* Clock source depends on strapping if UartClkOverride is unset */ if ((rev > 0) && ((R_REG(osh, &cc->corecontrol) & CC_UARTCLKO) == 0)) { if ((cap & CC_CAP_UCLKSEL) == CC_CAP_UINTCLK) { /* Internal divided backplane clock */ baud_base /= div; } else { /* Assume external clock of 1.8432 MHz */ baud_base = 1843200; } } } /* Add internal UARTs */ n = cap & CC_CAP_UARTS_MASK; for (i = 0; i < n; i++) { /* Register offset changed after revision 0 */ if (rev) regs = (void *)((ulong) &cc->uart0data + (i * 256)); else regs = (void *)((ulong) &cc->uart0data + (i * 8)); if (add) add(regs, irq, baud_base, 0); } }
void dma_fifoloopbackenable(dma_info_t *di) { DMA_TRACE(("%s: dma_fifoloopbackenable\n", di->name)); OR_REG(&di->regs->xmtcontrol, XC_LE); }
void dma_txsuspend(dma_info_t *di) { DMA_TRACE(("%s: dma_txsuspend\n", di->name)); OR_REG(&di->regs->xmtcontrol, XC_SE); }
/* * Initialize all the chip registers. If dma mode, init tx and rx dma engines * but leave the devcontrol tx and rx (fifos) disabled. */ static void chipinit(struct bcm4xxx *ch, uint options) { etc_info_t *etc; bcmenetregs_t *regs; uint idx; uint i; regs = ch->regs; etc = ch->etc; idx = 0; ET_TRACE(("et%d: chipinit\n", etc->unit)); /* enable crc32 generation */ OR_REG(ch->osh, ®s->emaccontrol, EMC_CG); /* enable one rx interrupt per received frame */ W_REG(ch->osh, ®s->intrecvlazy, (1 << IRL_FC_SHIFT)); /* enable 802.3x tx flow control (honor received PAUSE frames) */ W_REG(ch->osh, ®s->rxconfig, ERC_FE | ERC_UF); /* initialize CAM */ if (etc->promisc || (R_REG(ch->osh, ®s->rxconfig) & ERC_CA)) OR_REG(ch->osh, ®s->rxconfig, ERC_PE); else { /* our local address */ chipwrcam(ch, &etc->cur_etheraddr, idx++); /* allmulti or a list of discrete multicast addresses */ if (etc->allmulti) OR_REG(ch->osh, ®s->rxconfig, ERC_AM); else if (etc->nmulticast) { for (i = 0; i < etc->nmulticast; i++) chipwrcam(ch, &etc->multicast[i], idx++); } /* enable cam */ OR_REG(ch->osh, ®s->camcontrol, CC_CE); } /* optionally enable mac-level loopback */ if (etc->loopbk) OR_REG(ch->osh, ®s->rxconfig, ERC_LE); /* set max frame lengths - account for possible vlan tag */ W_REG(ch->osh, ®s->rxmaxlength, ETHER_MAX_LEN + 32); W_REG(ch->osh, ®s->txmaxlength, ETHER_MAX_LEN + 32); /* set tx watermark */ W_REG(ch->osh, ®s->txwatermark, 56); /* * Optionally, disable phy autonegotiation and force our speed/duplex * or constrain our advertised capabilities. */ if (etc->forcespeed != ET_AUTO) chipphyforce(ch, etc->phyaddr); else if (etc->advertise && etc->needautoneg) chipphyadvertise(ch, etc->phyaddr); if (options & ET_INIT_FULL) { /* initialize the tx and rx dma channels */ dma_txinit(ch->di); dma_rxinit(ch->di); /* post dma receive buffers */ dma_rxfill(ch->di); /* lastly, enable interrupts */ if (options & ET_INIT_INTRON) et_intrson(etc->et); } else dma_rxenable(ch->di); /* turn on the emac */ OR_REG(ch->osh, ®s->enetcontrol, EC_EE); }