Commit 069eddd9 authored by Franky Lin's avatar Franky Lin Committed by John W. Linville

brcmfmac: move chip download state code to sdio_chip.c

enter/exit download state routine is going to diverge with new ARM core
introduced. Move corresponding code to sdio_chip.c for new ARM core support.
Reviewed-by: default avatarArend van Spriel <arend@broadcom.com>
Reviewed-by: default avatarPieter-Paul Giesberts <pieterpg@broadcom.com>
Signed-off-by: default avatarFranky Lin <frankyl@broadcom.com>
Signed-off-by: default avatarArend van Spriel <arend@broadcom.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent ba540b01
......@@ -336,95 +336,6 @@ static uint prio2prec(u32 prio)
(prio^2) : prio;
}
/* core registers */
struct sdpcmd_regs {
u32 corecontrol; /* 0x00, rev8 */
u32 corestatus; /* rev8 */
u32 PAD[1];
u32 biststatus; /* rev8 */
/* PCMCIA access */
u16 pcmciamesportaladdr; /* 0x010, rev8 */
u16 PAD[1];
u16 pcmciamesportalmask; /* rev8 */
u16 PAD[1];
u16 pcmciawrframebc; /* rev8 */
u16 PAD[1];
u16 pcmciaunderflowtimer; /* rev8 */
u16 PAD[1];
/* interrupt */
u32 intstatus; /* 0x020, rev8 */
u32 hostintmask; /* rev8 */
u32 intmask; /* rev8 */
u32 sbintstatus; /* rev8 */
u32 sbintmask; /* rev8 */
u32 funcintmask; /* rev4 */
u32 PAD[2];
u32 tosbmailbox; /* 0x040, rev8 */
u32 tohostmailbox; /* rev8 */
u32 tosbmailboxdata; /* rev8 */
u32 tohostmailboxdata; /* rev8 */
/* synchronized access to registers in SDIO clock domain */
u32 sdioaccess; /* 0x050, rev8 */
u32 PAD[3];
/* PCMCIA frame control */
u8 pcmciaframectrl; /* 0x060, rev8 */
u8 PAD[3];
u8 pcmciawatermark; /* rev8 */
u8 PAD[155];
/* interrupt batching control */
u32 intrcvlazy; /* 0x100, rev8 */
u32 PAD[3];
/* counters */
u32 cmd52rd; /* 0x110, rev8 */
u32 cmd52wr; /* rev8 */
u32 cmd53rd; /* rev8 */
u32 cmd53wr; /* rev8 */
u32 abort; /* rev8 */
u32 datacrcerror; /* rev8 */
u32 rdoutofsync; /* rev8 */
u32 wroutofsync; /* rev8 */
u32 writebusy; /* rev8 */
u32 readwait; /* rev8 */
u32 readterm; /* rev8 */
u32 writeterm; /* rev8 */
u32 PAD[40];
u32 clockctlstatus; /* rev8 */
u32 PAD[7];
u32 PAD[128]; /* DMA engines */
/* SDIO/PCMCIA CIS region */
char cis[512]; /* 0x400-0x5ff, rev6 */
/* PCMCIA function control registers */
char pcmciafcr[256]; /* 0x600-6ff, rev6 */
u16 PAD[55];
/* PCMCIA backplane access */
u16 backplanecsr; /* 0x76E, rev6 */
u16 backplaneaddr0; /* rev6 */
u16 backplaneaddr1; /* rev6 */
u16 backplaneaddr2; /* rev6 */
u16 backplaneaddr3; /* rev6 */
u16 backplanedata0; /* rev6 */
u16 backplanedata1; /* rev6 */
u16 backplanedata2; /* rev6 */
u16 backplanedata3; /* rev6 */
u16 PAD[31];
/* sprom "size" & "blank" info */
u16 spromstatus; /* 0x7BE, rev2 */
u32 PAD[464];
u16 PAD[0x80];
};
#ifdef DEBUG
/* Device console log buffer state */
struct brcmf_console {
......@@ -3082,84 +2993,8 @@ brcmf_sdbrcm_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen)
return rxlen ? (int)rxlen : -ETIMEDOUT;
}
static int brcmf_sdbrcm_write_vars(struct brcmf_sdio *bus)
{
int bcmerror = 0;
u32 varaddr;
u32 varsizew;
__le32 varsizew_le;
#ifdef DEBUG
char *nvram_ularray;
#endif /* DEBUG */
/* Even if there are no vars are to be written, we still
need to set the ramsize. */
varaddr = (bus->ramsize - 4) - bus->varsz;
if (bus->vars) {
/* Write the vars list */
bcmerror = brcmf_sdio_ramrw(bus->sdiodev, true, varaddr,
bus->vars, bus->varsz);
#ifdef DEBUG
/* Verify NVRAM bytes */
brcmf_dbg(INFO, "Compare NVRAM dl & ul; varsize=%d\n",
bus->varsz);
nvram_ularray = kmalloc(bus->varsz, GFP_ATOMIC);
if (!nvram_ularray)
return -ENOMEM;
/* Upload image to verify downloaded contents. */
memset(nvram_ularray, 0xaa, bus->varsz);
/* Read the vars list to temp buffer for comparison */
bcmerror = brcmf_sdio_ramrw(bus->sdiodev, false, varaddr,
nvram_ularray, bus->varsz);
if (bcmerror) {
brcmf_err("error %d on reading %d nvram bytes at 0x%08x\n",
bcmerror, bus->varsz, varaddr);
}
/* Compare the org NVRAM with the one read from RAM */
if (memcmp(bus->vars, nvram_ularray, bus->varsz))
brcmf_err("Downloaded NVRAM image is corrupted\n");
else
brcmf_err("Download/Upload/Compare of NVRAM ok\n");
kfree(nvram_ularray);
#endif /* DEBUG */
}
/* adjust to the user specified RAM */
brcmf_dbg(INFO, "Physical memory size: %d\n", bus->ramsize);
brcmf_dbg(INFO, "Vars are at %d, orig varsize is %d\n",
varaddr, bus->varsz);
/*
* Determine the length token:
* Varsize, converted to words, in lower 16-bits, checksum
* in upper 16-bits.
*/
if (bcmerror) {
varsizew = 0;
varsizew_le = cpu_to_le32(0);
} else {
varsizew = bus->varsz / 4;
varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF);
varsizew_le = cpu_to_le32(varsizew);
}
brcmf_dbg(INFO, "New varsize is %d, length token=0x%08x\n",
bus->varsz, varsizew);
/* Write the length token to the last word */
bcmerror = brcmf_sdio_ramrw(bus->sdiodev, true, (bus->ramsize - 4),
(u8 *)&varsizew_le, 4);
return bcmerror;
}
static int brcmf_sdbrcm_download_state(struct brcmf_sdio *bus, bool enter)
static bool brcmf_sdbrcm_download_state(struct brcmf_sdio *bus, bool enter)
{
int bcmerror = 0;
struct chip_info *ci = bus->ci;
/* To enter download state, disable ARM and reset SOCRAM.
......@@ -3168,41 +3003,19 @@ static int brcmf_sdbrcm_download_state(struct brcmf_sdio *bus, bool enter)
if (enter) {
bus->alp_only = true;
ci->coredisable(bus->sdiodev, ci, BCMA_CORE_ARM_CM3);
ci->resetcore(bus->sdiodev, ci, BCMA_CORE_INTERNAL_MEM);
/* Clear the top bit of memory */
if (bus->ramsize) {
u32 zeros = 0;
brcmf_sdio_ramrw(bus->sdiodev, true, bus->ramsize - 4,
(u8 *)&zeros, 4);
}
brcmf_sdio_chip_enter_download(bus->sdiodev, ci);
} else {
if (!ci->iscoreup(bus->sdiodev, ci, BCMA_CORE_INTERNAL_MEM)) {
brcmf_err("SOCRAM core is down after reset?\n");
bcmerror = -EBADE;
goto fail;
}
bcmerror = brcmf_sdbrcm_write_vars(bus);
if (bcmerror) {
brcmf_err("no vars written to RAM\n");
bcmerror = 0;
}
w_sdreg32(bus, 0xFFFFFFFF,
offsetof(struct sdpcmd_regs, intstatus));
ci->resetcore(bus->sdiodev, ci, BCMA_CORE_ARM_CM3);
if (!brcmf_sdio_chip_exit_download(bus->sdiodev, ci, bus->vars,
bus->varsz))
return false;
/* Allow HT Clock now that the ARM is running. */
bus->alp_only = false;
bus->sdiodev->bus_if->state = BRCMF_BUS_LOAD;
}
fail:
return bcmerror;
return true;
}
static int brcmf_sdbrcm_get_image(char *buf, int len, struct brcmf_sdio *bus)
......@@ -3359,7 +3172,7 @@ static int _brcmf_sdbrcm_download_firmware(struct brcmf_sdio *bus)
int bcmerror = -1;
/* Keep arm in reset */
if (brcmf_sdbrcm_download_state(bus, true)) {
if (!brcmf_sdbrcm_download_state(bus, true)) {
brcmf_err("error placing ARM core in reset\n");
goto err;
}
......@@ -3375,7 +3188,7 @@ static int _brcmf_sdbrcm_download_firmware(struct brcmf_sdio *bus)
}
/* Take arm out of reset */
if (brcmf_sdbrcm_download_state(bus, false)) {
if (!brcmf_sdbrcm_download_state(bus, false)) {
brcmf_err("error getting out of ARM core reset\n");
goto err;
}
......
......@@ -356,8 +356,7 @@ static int brcmf_sdio_chip_recognition(struct brcmf_sdio_dev *sdiodev,
{
u32 regdata;
/*
* Get CC core rev
/* 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.
......@@ -650,3 +649,140 @@ brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
drivestrength, cc_data_temp);
}
}
#ifdef DEBUG
static bool
brcmf_sdio_chip_verifynvram(struct brcmf_sdio_dev *sdiodev, u32 nvram_addr,
char *nvram_dat, uint nvram_sz)
{
char *nvram_ularray;
int err;
bool ret = true;
/* read back and verify */
brcmf_dbg(INFO, "Compare NVRAM dl & ul; size=%d\n", nvram_sz);
nvram_ularray = kmalloc(nvram_sz, GFP_KERNEL);
/* do not proceed while no memory but */
if (!nvram_ularray)
return true;
/* Upload image to verify downloaded contents. */
memset(nvram_ularray, 0xaa, nvram_sz);
/* Read the vars list to temp buffer for comparison */
err = brcmf_sdio_ramrw(sdiodev, false, nvram_addr, nvram_ularray,
nvram_sz);
if (err) {
brcmf_err("error %d on reading %d nvram bytes at 0x%08x\n",
err, nvram_sz, nvram_addr);
} else if (memcmp(nvram_dat, nvram_ularray, nvram_sz)) {
brcmf_err("Downloaded NVRAM image is corrupted\n");
ret = false;
}
kfree(nvram_ularray);
return ret;
}
#else /* DEBUG */
static inline bool
brcmf_sdio_chip_verifynvram(struct brcmf_sdio_dev *sdiodev, u32 nvram_addr,
char *nvram_dat, uint nvram_sz)
{
return true;
}
#endif /* DEBUG */
static bool brcmf_sdio_chip_writenvram(struct brcmf_sdio_dev *sdiodev,
struct chip_info *ci,
char *nvram_dat, uint nvram_sz)
{
int err;
u32 nvram_addr;
u32 token;
__le32 token_le;
nvram_addr = (ci->ramsize - 4) - nvram_sz;
/* Write the vars list */
err = brcmf_sdio_ramrw(sdiodev, true, nvram_addr, nvram_dat, nvram_sz);
if (err) {
brcmf_err("error %d on writing %d nvram bytes at 0x%08x\n",
err, nvram_sz, nvram_addr);
return false;
}
if (!brcmf_sdio_chip_verifynvram(sdiodev, nvram_addr,
nvram_dat, nvram_sz))
return false;
/* generate token:
* nvram size, converted to words, in lower 16-bits, checksum
* in upper 16-bits.
*/
token = nvram_sz / 4;
token = (~token << 16) | (token & 0x0000FFFF);
token_le = cpu_to_le32(token);
brcmf_dbg(INFO, "RAM size: %d\n", ci->ramsize);
brcmf_dbg(INFO, "nvram is placed at %d, size %d, token=0x%08x\n",
nvram_addr, nvram_sz, token);
/* Write the length token to the last word */
if (brcmf_sdio_ramrw(sdiodev, true, (ci->ramsize - 4),
(u8 *)&token_le, 4))
return false;
return true;
}
static void
brcmf_sdio_chip_cm3_enterdl(struct brcmf_sdio_dev *sdiodev,
struct chip_info *ci)
{
u32 zeros = 0;
ci->coredisable(sdiodev, ci, BCMA_CORE_ARM_CM3);
ci->resetcore(sdiodev, ci, BCMA_CORE_INTERNAL_MEM);
/* clear length token */
brcmf_sdio_ramrw(sdiodev, true, ci->ramsize - 4, (u8 *)&zeros, 4);
}
static bool
brcmf_sdio_chip_cm3_exitdl(struct brcmf_sdio_dev *sdiodev, struct chip_info *ci,
char *nvram_dat, uint nvram_sz)
{
u8 core_idx;
u32 reg_addr;
if (!ci->iscoreup(sdiodev, ci, BCMA_CORE_INTERNAL_MEM)) {
brcmf_err("SOCRAM core is down after reset?\n");
return false;
}
if (!brcmf_sdio_chip_writenvram(sdiodev, ci, nvram_dat, nvram_sz))
return false;
/* clear all interrupts */
core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_SDIO_DEV);
reg_addr = ci->c_inf[core_idx].base;
reg_addr += offsetof(struct sdpcmd_regs, intstatus);
brcmf_sdio_regwl(sdiodev, reg_addr, 0xFFFFFFFF, NULL);
ci->resetcore(sdiodev, ci, BCMA_CORE_ARM_CM3);
return true;
}
void brcmf_sdio_chip_enter_download(struct brcmf_sdio_dev *sdiodev,
struct chip_info *ci)
{
brcmf_sdio_chip_cm3_enterdl(sdiodev, ci);
}
bool brcmf_sdio_chip_exit_download(struct brcmf_sdio_dev *sdiodev,
struct chip_info *ci, char *nvram_dat,
uint nvram_sz)
{
return brcmf_sdio_chip_cm3_exitdl(sdiodev, ci, nvram_dat, nvram_sz);
}
......@@ -124,6 +124,95 @@ struct sbconfig {
u32 sbidhigh; /* identification */
};
/* sdio core registers */
struct sdpcmd_regs {
u32 corecontrol; /* 0x00, rev8 */
u32 corestatus; /* rev8 */
u32 PAD[1];
u32 biststatus; /* rev8 */
/* PCMCIA access */
u16 pcmciamesportaladdr; /* 0x010, rev8 */
u16 PAD[1];
u16 pcmciamesportalmask; /* rev8 */
u16 PAD[1];
u16 pcmciawrframebc; /* rev8 */
u16 PAD[1];
u16 pcmciaunderflowtimer; /* rev8 */
u16 PAD[1];
/* interrupt */
u32 intstatus; /* 0x020, rev8 */
u32 hostintmask; /* rev8 */
u32 intmask; /* rev8 */
u32 sbintstatus; /* rev8 */
u32 sbintmask; /* rev8 */
u32 funcintmask; /* rev4 */
u32 PAD[2];
u32 tosbmailbox; /* 0x040, rev8 */
u32 tohostmailbox; /* rev8 */
u32 tosbmailboxdata; /* rev8 */
u32 tohostmailboxdata; /* rev8 */
/* synchronized access to registers in SDIO clock domain */
u32 sdioaccess; /* 0x050, rev8 */
u32 PAD[3];
/* PCMCIA frame control */
u8 pcmciaframectrl; /* 0x060, rev8 */
u8 PAD[3];
u8 pcmciawatermark; /* rev8 */
u8 PAD[155];
/* interrupt batching control */
u32 intrcvlazy; /* 0x100, rev8 */
u32 PAD[3];
/* counters */
u32 cmd52rd; /* 0x110, rev8 */
u32 cmd52wr; /* rev8 */
u32 cmd53rd; /* rev8 */
u32 cmd53wr; /* rev8 */
u32 abort; /* rev8 */
u32 datacrcerror; /* rev8 */
u32 rdoutofsync; /* rev8 */
u32 wroutofsync; /* rev8 */
u32 writebusy; /* rev8 */
u32 readwait; /* rev8 */
u32 readterm; /* rev8 */
u32 writeterm; /* rev8 */
u32 PAD[40];
u32 clockctlstatus; /* rev8 */
u32 PAD[7];
u32 PAD[128]; /* DMA engines */
/* SDIO/PCMCIA CIS region */
char cis[512]; /* 0x400-0x5ff, rev6 */
/* PCMCIA function control registers */
char pcmciafcr[256]; /* 0x600-6ff, rev6 */
u16 PAD[55];
/* PCMCIA backplane access */
u16 backplanecsr; /* 0x76E, rev6 */
u16 backplaneaddr0; /* rev6 */
u16 backplaneaddr1; /* rev6 */
u16 backplaneaddr2; /* rev6 */
u16 backplaneaddr3; /* rev6 */
u16 backplanedata0; /* rev6 */
u16 backplanedata1; /* rev6 */
u16 backplanedata2; /* rev6 */
u16 backplanedata3; /* rev6 */
u16 PAD[31];
/* sprom "size" & "blank" info */
u16 spromstatus; /* 0x7BE, rev2 */
u32 PAD[464];
u16 PAD[0x80];
};
extern int brcmf_sdio_chip_attach(struct brcmf_sdio_dev *sdiodev,
struct chip_info **ci_ptr, u32 regs);
extern void brcmf_sdio_chip_detach(struct chip_info **ci_ptr);
......@@ -131,6 +220,10 @@ extern void brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
struct chip_info *ci,
u32 drivestrength);
extern u8 brcmf_sdio_chip_getinfidx(struct chip_info *ci, u16 coreid);
extern void brcmf_sdio_chip_enter_download(struct brcmf_sdio_dev *sdiodev,
struct chip_info *ci);
extern bool brcmf_sdio_chip_exit_download(struct brcmf_sdio_dev *sdiodev,
struct chip_info *ci, char *nvram_dat,
uint nvram_sz);
#endif /* _BRCMFMAC_SDIO_CHIP_H_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment