Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 249162
b: refs/heads/master
c: cb63e4c
h: refs/heads/master
v: v3
  • Loading branch information
Franky Lin authored and Greg Kroah-Hartman committed Apr 25, 2011
1 parent 666510a commit 51db3b1
Show file tree
Hide file tree
Showing 2 changed files with 254 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: ddd0b091dbb0cd6891f13c6157679076467aa146
refs/heads/master: cb63e4c967541402b79a92a31c841744ca17d1aa
253 changes: 253 additions & 0 deletions trunk/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
#include <dhdioctl.h>
#include <sdiovar.h>
#include <siutils_priv.h>
#include <bcmchip.h>

#ifndef DHDSDIO_MEM_DUMP_FNAME
#define DHDSDIO_MEM_DUMP_FNAME "mem_dump"
Expand Down Expand Up @@ -166,12 +167,28 @@ typedef struct dhd_console {
} dhd_console_t;
#endif /* DHD_DEBUG */

/* misc chip info needed by some of the routines */
struct chip_info {
u32 chip;
u32 chiprev;
u32 cccorebase;
u32 ccrev;
u32 cccaps;
u32 buscorebase;
u32 buscorerev;
u32 buscoretype;
u32 ramcorebase;
u32 armcorebase;
u32 pmurev;
};

/* Private data for SDIO bus interaction */
typedef struct dhd_bus {
dhd_pub_t *dhd;

bcmsdh_info_t *sdh; /* Handle for BCMSDH calls */
si_t *sih; /* Handle for SI calls */
struct chip_info *ci; /* Chip info struct */
char *vars; /* Variables (from CIS and/or other) */
uint varsz; /* Size of variables buffer */
u32 sbaddr; /* Current SB window pointer (-1, invalid) */
Expand Down Expand Up @@ -465,6 +482,7 @@ static int dhdsdio_download_nvram(struct dhd_bus *bus);
#ifdef BCMEMBEDIMAGE
static int dhdsdio_download_code_array(struct dhd_bus *bus);
#endif
static int dhdsdio_chip_attach(struct dhd_bus *bus, void *regs);

static void dhd_dongle_setmemsize(struct dhd_bus *bus, int mem_size)
{
Expand Down Expand Up @@ -5289,6 +5307,10 @@ dhdsdio_probe_attach(struct dhd_bus *bus, void *sdh, void *regsva, u16 devid)
DHD_ERROR(("%s: si_attach failed!\n", __func__));
goto fail;
}
if (dhdsdio_chip_attach(bus, regsva)) {
DHD_ERROR(("%s: dhdsdio_chip_attach failed!\n", __func__));
goto fail;
}

bcmsdh_chipinfo(sdh, bus->sih->chip, bus->sih->chiprev);

Expand Down Expand Up @@ -6071,3 +6093,234 @@ int dhd_bus_devreset(dhd_pub_t *dhdp, u8 flag)
}
return bcmerror;
}

static int
dhdsdio_chip_recognition(bcmsdh_info_t *sdh, struct chip_info *ci, void *regs)
{
u32 regdata;

/*
* Get CC core rev
* Chipid is assume to be at offset 0 from regs arg
* For different chiptypes or old sdio hosts w/o chipcommon,
* other ways of recognition should be added here.
*/
ci->cccorebase = (u32)regs;
regdata = bcmsdh_reg_read(sdh, CORE_CC_REG(ci->cccorebase, chipid), 4);
ci->chip = regdata & CID_ID_MASK;
ci->chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT;

DHD_INFO(("%s: chipid=0x%x chiprev=%d\n",
__func__, ci->chip, ci->chiprev));

/* Address of cores for new chips should be added here */
switch (ci->chip) {
case BCM4329_CHIP_ID:
ci->buscorebase = BCM4329_CORE_BUS_BASE;
ci->ramcorebase = BCM4329_CORE_SOCRAM_BASE;
ci->armcorebase = BCM4329_CORE_ARM_BASE;
break;
default:
DHD_ERROR(("%s: chipid 0x%x is not supported\n",
__func__, ci->chip));
return -ENODEV;
}

regdata = bcmsdh_reg_read(sdh,
CORE_SB(ci->cccorebase, sbidhigh), 4);
ci->ccrev = SBCOREREV(regdata);

regdata = bcmsdh_reg_read(sdh,
CORE_CC_REG(ci->cccorebase, pmucapabilities), 4);
ci->pmurev = regdata & PCAP_REV_MASK;

regdata = bcmsdh_reg_read(sdh, CORE_SB(ci->buscorebase, sbidhigh), 4);
ci->buscorerev = SBCOREREV(regdata);
ci->buscoretype = (regdata & SBIDH_CC_MASK) >> SBIDH_CC_SHIFT;

DHD_INFO(("%s: ccrev=%d, pmurev=%d, buscore rev/type=%d/0x%x\n",
__func__, ci->ccrev, ci->pmurev,
ci->buscorerev, ci->buscoretype));

/* get chipcommon capabilites */
ci->cccaps = bcmsdh_reg_read(sdh,
CORE_CC_REG(ci->cccorebase, capabilities), 4);

return 0;
}

static void
dhdsdio_chip_disablecore(bcmsdh_info_t *sdh, u32 corebase)
{
u32 regdata;

regdata = bcmsdh_reg_read(sdh,
CORE_SB(corebase, sbtmstatelow), 4);
if (regdata & SBTML_RESET)
return;

regdata = bcmsdh_reg_read(sdh,
CORE_SB(corebase, sbtmstatelow), 4);
if ((regdata & (SICF_CLOCK_EN << SBTML_SICF_SHIFT)) != 0) {
/*
* set target reject and spin until busy is clear
* (preserve core-specific bits)
*/
regdata = bcmsdh_reg_read(sdh,
CORE_SB(corebase, sbtmstatelow), 4);
bcmsdh_reg_write(sdh, CORE_SB(corebase, sbtmstatelow), 4,
regdata | SBTML_REJ);

regdata = bcmsdh_reg_read(sdh,
CORE_SB(corebase, sbtmstatelow), 4);
udelay(1);
SPINWAIT((bcmsdh_reg_read(sdh,
CORE_SB(corebase, sbtmstatehigh), 4) &
SBTMH_BUSY), 100000);

regdata = bcmsdh_reg_read(sdh,
CORE_SB(corebase, sbtmstatehigh), 4);
if (regdata & SBTMH_BUSY)
DHD_ERROR(("%s: ARM core still busy\n", __func__));

regdata = bcmsdh_reg_read(sdh,
CORE_SB(corebase, sbidlow), 4);
if (regdata & SBIDL_INIT) {
regdata = bcmsdh_reg_read(sdh,
CORE_SB(corebase, sbimstate), 4) |
SBIM_RJ;
bcmsdh_reg_write(sdh,
CORE_SB(corebase, sbimstate), 4,
regdata);
regdata = bcmsdh_reg_read(sdh,
CORE_SB(corebase, sbimstate), 4);
udelay(1);
SPINWAIT((bcmsdh_reg_read(sdh,
CORE_SB(corebase, sbimstate), 4) &
SBIM_BY), 100000);
}

/* set reset and reject while enabling the clocks */
bcmsdh_reg_write(sdh,
CORE_SB(corebase, sbtmstatelow), 4,
(((SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) |
SBTML_REJ | SBTML_RESET));
regdata = bcmsdh_reg_read(sdh,
CORE_SB(corebase, sbtmstatelow), 4);
udelay(10);

/* clear the initiator reject bit */
regdata = bcmsdh_reg_read(sdh,
CORE_SB(corebase, sbidlow), 4);
if (regdata & SBIDL_INIT) {
regdata = bcmsdh_reg_read(sdh,
CORE_SB(corebase, sbimstate), 4) &
~SBIM_RJ;
bcmsdh_reg_write(sdh,
CORE_SB(corebase, sbimstate), 4,
regdata);
}
}

/* leave reset and reject asserted */
bcmsdh_reg_write(sdh, CORE_SB(corebase, sbtmstatelow), 4,
(SBTML_REJ | SBTML_RESET));
udelay(1);
}

static int
dhdsdio_chip_attach(struct dhd_bus *bus, void *regs)
{
struct chip_info *ci;
int err;
u8 clkval, clkset;

DHD_TRACE(("%s: Enter\n", __func__));

/* alloc chip_info_t */
ci = kmalloc(sizeof(struct chip_info), GFP_ATOMIC);
if (NULL == ci) {
DHD_ERROR(("%s: malloc failed!\n", __func__));
return -ENOMEM;
}

memset((unsigned char *)ci, 0, sizeof(struct chip_info));

/* bus/core/clk setup for register access */
/* Try forcing SDIO core to do ALPAvail request only */
clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ;
bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
clkset, &err);
if (err) {
DHD_ERROR(("%s: error writing for HT off\n", __func__));
goto fail;
}

/* If register supported, wait for ALPAvail and then force ALP */
/* This may take up to 15 milliseconds */
clkval = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR, NULL);
if ((clkval & ~SBSDIO_AVBITS) == clkset) {
SPINWAIT(((clkval =
bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR,
NULL)),
!SBSDIO_ALPAV(clkval)),
PMU_MAX_TRANSITION_DLY);
if (!SBSDIO_ALPAV(clkval)) {
DHD_ERROR(("%s: timeout on ALPAV wait, clkval 0x%02x\n",
__func__, clkval));
err = -EBUSY;
goto fail;
}
clkset = SBSDIO_FORCE_HW_CLKREQ_OFF |
SBSDIO_FORCE_ALP;
bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR,
clkset, &err);
udelay(65);
} else {
DHD_ERROR(("%s: ChipClkCSR access: wrote 0x%02x read 0x%02x\n",
__func__, clkset, clkval));
err = -EACCES;
goto fail;
}

/* Also, disable the extra SDIO pull-ups */
bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SDIOPULLUP, 0,
NULL);

err = dhdsdio_chip_recognition(bus->sdh, ci, regs);
if (err)
goto fail;

/*
* Make sure any on-chip ARM is off (in case strapping is wrong),
* or downloaded code was already running.
*/
dhdsdio_chip_disablecore(bus->sdh, ci->armcorebase);

bcmsdh_reg_write(bus->sdh,
CORE_CC_REG(ci->cccorebase, gpiopullup), 4, 0);
bcmsdh_reg_write(bus->sdh,
CORE_CC_REG(ci->cccorebase, gpiopulldown), 4, 0);

/* Disable F2 to clear any intermediate frame state on the dongle */
bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN,
SDIO_FUNC_ENABLE_1, NULL);

/* WAR: cmd52 backplane read so core HW will drop ALPReq */
clkval = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
0, NULL);

/* Done with backplane-dependent accesses, can drop clock... */
bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0,
NULL);

bus->ci = ci;
return 0;
fail:
bus->ci = NULL;
kfree(ci);
return err;
}

0 comments on commit 51db3b1

Please sign in to comment.