Commit 3355650c authored by Arend van Spriel's avatar Arend van Spriel Committed by John W. Linville

brcmfmac: rework firmware download code

The firmware download code has been restructured so the reset vector
does not need to be stored in a structure, but keep it on the stack
to be passed to exit download function.
Reviewed-by: default avatarFranky Lin <frankyl@broadcom.com>
Reviewed-by: default avatarHante Meuleman <meuleman@broadcom.com>
Reviewed-by: default avatarPieter-Paul Giesberts <pieterpg@broadcom.com>
Reviewed-by: default avatarDaniel (Deognyoun) Kim <dekim@broadcom.com>
Signed-off-by: default avatarArend van Spriel <arend@broadcom.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 53036261
...@@ -3192,30 +3192,6 @@ brcmf_sdio_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen) ...@@ -3192,30 +3192,6 @@ brcmf_sdio_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen)
return rxlen ? (int)rxlen : -ETIMEDOUT; return rxlen ? (int)rxlen : -ETIMEDOUT;
} }
static bool brcmf_sdio_download_state(struct brcmf_sdio *bus, bool enter)
{
struct chip_info *ci = bus->ci;
/* To enter download state, disable ARM and reset SOCRAM.
* To exit download state, simply reset ARM (default is RAM boot).
*/
if (enter) {
bus->alp_only = true;
brcmf_sdio_chip_enter_download(bus->sdiodev, ci);
} else {
if (!brcmf_sdio_chip_exit_download(bus->sdiodev, ci))
return false;
/* Allow HT Clock now that the ARM is running. */
bus->alp_only = false;
bus->sdiodev->bus_if->state = BRCMF_BUS_LOAD;
}
return true;
}
#ifdef DEBUG #ifdef DEBUG
static bool static bool
brcmf_sdio_verifymemory(struct brcmf_sdio_dev *sdiodev, u32 ram_addr, brcmf_sdio_verifymemory(struct brcmf_sdio_dev *sdiodev, u32 ram_addr,
...@@ -3270,9 +3246,9 @@ brcmf_sdio_verifymemory(struct brcmf_sdio_dev *sdiodev, u32 ram_addr, ...@@ -3270,9 +3246,9 @@ brcmf_sdio_verifymemory(struct brcmf_sdio_dev *sdiodev, u32 ram_addr,
} }
#endif /* DEBUG */ #endif /* DEBUG */
static int brcmf_sdio_download_code_file(struct brcmf_sdio *bus) static int brcmf_sdio_download_code_file(struct brcmf_sdio *bus,
const struct firmware *fw)
{ {
const struct firmware *fw;
int err; int err;
int offset; int offset;
int address; int address;
...@@ -3280,14 +3256,6 @@ static int brcmf_sdio_download_code_file(struct brcmf_sdio *bus) ...@@ -3280,14 +3256,6 @@ static int brcmf_sdio_download_code_file(struct brcmf_sdio *bus)
brcmf_dbg(TRACE, "Enter\n"); brcmf_dbg(TRACE, "Enter\n");
fw = brcmf_sdio_get_fw(bus, BRCMF_FIRMWARE_BIN);
if (fw == NULL)
return -ENOENT;
if (brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_ARM_CR4) !=
BRCMF_MAX_CORENUM)
memcpy(&bus->ci->rst_vec, fw->data, sizeof(bus->ci->rst_vec));
err = 0; err = 0;
offset = 0; offset = 0;
address = bus->ci->rambase; address = bus->ci->rambase;
...@@ -3299,7 +3267,7 @@ static int brcmf_sdio_download_code_file(struct brcmf_sdio *bus) ...@@ -3299,7 +3267,7 @@ static int brcmf_sdio_download_code_file(struct brcmf_sdio *bus)
if (err) { if (err) {
brcmf_err("error %d on writing %d membytes at 0x%08x\n", brcmf_err("error %d on writing %d membytes at 0x%08x\n",
err, len, address); err, len, address);
goto failure; return err;
} }
offset += len; offset += len;
address += len; address += len;
...@@ -3309,15 +3277,12 @@ static int brcmf_sdio_download_code_file(struct brcmf_sdio *bus) ...@@ -3309,15 +3277,12 @@ static int brcmf_sdio_download_code_file(struct brcmf_sdio *bus)
(u8 *)fw->data, fw->size)) (u8 *)fw->data, fw->size))
err = -EIO; err = -EIO;
failure:
release_firmware(fw);
return err; return err;
} }
static int brcmf_sdio_download_nvram(struct brcmf_sdio *bus) static int brcmf_sdio_download_nvram(struct brcmf_sdio *bus,
const struct firmware *nv)
{ {
const struct firmware *nv;
void *vars; void *vars;
u32 varsz; u32 varsz;
int address; int address;
...@@ -3325,12 +3290,7 @@ static int brcmf_sdio_download_nvram(struct brcmf_sdio *bus) ...@@ -3325,12 +3290,7 @@ static int brcmf_sdio_download_nvram(struct brcmf_sdio *bus)
brcmf_dbg(TRACE, "Enter\n"); brcmf_dbg(TRACE, "Enter\n");
nv = brcmf_sdio_get_fw(bus, BRCMF_FIRMWARE_NVRAM);
if (nv == NULL)
return -ENOENT;
vars = brcmf_nvram_strip(nv, &varsz); vars = brcmf_nvram_strip(nv, &varsz);
release_firmware(nv);
if (vars == NULL) if (vars == NULL)
return -EINVAL; return -EINVAL;
...@@ -3351,33 +3311,52 @@ static int brcmf_sdio_download_nvram(struct brcmf_sdio *bus) ...@@ -3351,33 +3311,52 @@ static int brcmf_sdio_download_nvram(struct brcmf_sdio *bus)
static int brcmf_sdio_download_firmware(struct brcmf_sdio *bus) static int brcmf_sdio_download_firmware(struct brcmf_sdio *bus)
{ {
int bcmerror = -EFAULT; int bcmerror = -EFAULT;
const struct firmware *fw;
u32 rstvec;
sdio_claim_host(bus->sdiodev->func[1]); sdio_claim_host(bus->sdiodev->func[1]);
brcmf_sdio_clkctl(bus, CLK_AVAIL, false); brcmf_sdio_clkctl(bus, CLK_AVAIL, false);
/* Keep arm in reset */ /* Keep arm in reset */
if (!brcmf_sdio_download_state(bus, true)) { brcmf_sdio_chip_enter_download(bus->sdiodev, bus->ci);
brcmf_err("error placing ARM core in reset\n");
fw = brcmf_sdio_get_fw(bus, BRCMF_FIRMWARE_BIN);
if (fw == NULL) {
bcmerror = -ENOENT;
goto err; goto err;
} }
if (brcmf_sdio_download_code_file(bus)) { rstvec = get_unaligned_le32(fw->data);
brcmf_dbg(SDIO, "firmware rstvec: %x\n", rstvec);
bcmerror = brcmf_sdio_download_code_file(bus, fw);
release_firmware(fw);
if (bcmerror) {
brcmf_err("dongle image file download failed\n"); brcmf_err("dongle image file download failed\n");
goto err; goto err;
} }
if (brcmf_sdio_download_nvram(bus)) { fw = brcmf_sdio_get_fw(bus, BRCMF_FIRMWARE_NVRAM);
if (fw == NULL) {
bcmerror = -ENOENT;
goto err;
}
bcmerror = brcmf_sdio_download_nvram(bus, fw);
release_firmware(fw);
if (bcmerror) {
brcmf_err("dongle nvram file download failed\n"); brcmf_err("dongle nvram file download failed\n");
goto err; goto err;
} }
/* Take arm out of reset */ /* Take arm out of reset */
if (!brcmf_sdio_download_state(bus, false)) { if (!brcmf_sdio_chip_exit_download(bus->sdiodev, bus->ci, rstvec)) {
brcmf_err("error getting out of ARM core reset\n"); brcmf_err("error getting out of ARM core reset\n");
goto err; goto err;
} }
/* Allow HT Clock now that the ARM is running. */
bus->sdiodev->bus_if->state = BRCMF_BUS_LOAD;
bcmerror = 0; bcmerror = 0;
err: err:
...@@ -3566,9 +3545,11 @@ static int brcmf_sdio_bus_init(struct device *dev) ...@@ -3566,9 +3545,11 @@ static int brcmf_sdio_bus_init(struct device *dev)
/* try to download image and nvram to the dongle */ /* try to download image and nvram to the dongle */
if (bus_if->state == BRCMF_BUS_DOWN) { if (bus_if->state == BRCMF_BUS_DOWN) {
bus->alp_only = true;
err = brcmf_sdio_download_firmware(bus); err = brcmf_sdio_download_firmware(bus);
if (err) if (err)
return err; return err;
bus->alp_only = false;
} }
if (!bus->sdiodev->bus_if->drvr) if (!bus->sdiodev->bus_if->drvr)
...@@ -3778,8 +3759,6 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus) ...@@ -3778,8 +3759,6 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus)
u32 reg_val; u32 reg_val;
u32 drivestrength; u32 drivestrength;
bus->alp_only = true;
sdio_claim_host(bus->sdiodev->func[1]); sdio_claim_host(bus->sdiodev->func[1]);
pr_debug("F1 signature read @0x18000000=0x%4x\n", pr_debug("F1 signature read @0x18000000=0x%4x\n",
...@@ -4088,7 +4067,7 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus) ...@@ -4088,7 +4067,7 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus)
* essentially resets all necessary cores * essentially resets all necessary cores
*/ */
msleep(20); msleep(20);
brcmf_sdio_download_state(bus, true); brcmf_sdio_chip_enter_download(bus->sdiodev, bus->ci);
brcmf_sdio_clkctl(bus, CLK_NONE, false); brcmf_sdio_clkctl(bus, CLK_NONE, false);
sdio_release_host(bus->sdiodev->func[1]); sdio_release_host(bus->sdiodev->func[1]);
brcmf_sdio_chip_detach(&bus->ci); brcmf_sdio_chip_detach(&bus->ci);
......
...@@ -923,7 +923,8 @@ brcmf_sdio_chip_cr4_enterdl(struct brcmf_sdio_dev *sdiodev, ...@@ -923,7 +923,8 @@ brcmf_sdio_chip_cr4_enterdl(struct brcmf_sdio_dev *sdiodev,
} }
static bool static bool
brcmf_sdio_chip_cr4_exitdl(struct brcmf_sdio_dev *sdiodev, struct chip_info *ci) brcmf_sdio_chip_cr4_exitdl(struct brcmf_sdio_dev *sdiodev, struct chip_info *ci,
u32 rstvec)
{ {
u8 core_idx; u8 core_idx;
u32 reg_addr; u32 reg_addr;
...@@ -935,8 +936,8 @@ brcmf_sdio_chip_cr4_exitdl(struct brcmf_sdio_dev *sdiodev, struct chip_info *ci) ...@@ -935,8 +936,8 @@ brcmf_sdio_chip_cr4_exitdl(struct brcmf_sdio_dev *sdiodev, struct chip_info *ci)
brcmf_sdiod_regwl(sdiodev, reg_addr, 0xFFFFFFFF, NULL); brcmf_sdiod_regwl(sdiodev, reg_addr, 0xFFFFFFFF, NULL);
/* Write reset vector to address 0 */ /* Write reset vector to address 0 */
brcmf_sdiod_ramrw(sdiodev, true, 0, (void *)&ci->rst_vec, brcmf_sdiod_ramrw(sdiodev, true, 0, (void *)&rstvec,
sizeof(ci->rst_vec)); sizeof(rstvec));
/* restore ARM */ /* restore ARM */
ci->resetcore(sdiodev, ci, BCMA_CORE_ARM_CR4, ARMCR4_BCMA_IOCTL_CPUHALT, ci->resetcore(sdiodev, ci, BCMA_CORE_ARM_CR4, ARMCR4_BCMA_IOCTL_CPUHALT,
...@@ -960,7 +961,7 @@ void brcmf_sdio_chip_enter_download(struct brcmf_sdio_dev *sdiodev, ...@@ -960,7 +961,7 @@ void brcmf_sdio_chip_enter_download(struct brcmf_sdio_dev *sdiodev,
} }
bool brcmf_sdio_chip_exit_download(struct brcmf_sdio_dev *sdiodev, bool brcmf_sdio_chip_exit_download(struct brcmf_sdio_dev *sdiodev,
struct chip_info *ci) struct chip_info *ci, u32 rstvec)
{ {
u8 arm_core_idx; u8 arm_core_idx;
...@@ -968,5 +969,5 @@ bool brcmf_sdio_chip_exit_download(struct brcmf_sdio_dev *sdiodev, ...@@ -968,5 +969,5 @@ bool brcmf_sdio_chip_exit_download(struct brcmf_sdio_dev *sdiodev,
if (BRCMF_MAX_CORENUM != arm_core_idx) if (BRCMF_MAX_CORENUM != arm_core_idx)
return brcmf_sdio_chip_cm3_exitdl(sdiodev, ci); return brcmf_sdio_chip_cm3_exitdl(sdiodev, ci);
return brcmf_sdio_chip_cr4_exitdl(sdiodev, ci); return brcmf_sdio_chip_cr4_exitdl(sdiodev, ci, rstvec);
} }
...@@ -226,6 +226,6 @@ u8 brcmf_sdio_chip_getinfidx(struct chip_info *ci, u16 coreid); ...@@ -226,6 +226,6 @@ u8 brcmf_sdio_chip_getinfidx(struct chip_info *ci, u16 coreid);
void brcmf_sdio_chip_enter_download(struct brcmf_sdio_dev *sdiodev, void brcmf_sdio_chip_enter_download(struct brcmf_sdio_dev *sdiodev,
struct chip_info *ci); struct chip_info *ci);
bool brcmf_sdio_chip_exit_download(struct brcmf_sdio_dev *sdiodev, bool brcmf_sdio_chip_exit_download(struct brcmf_sdio_dev *sdiodev,
struct chip_info *ci); struct chip_info *ci, u32 rstvec);
#endif /* _BRCMFMAC_SDIO_CHIP_H_ */ #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