From 7e33483e3b9db81819d981894e6e882aeff862ef Mon Sep 17 00:00:00 2001 From: Chung-Hsien Hsu Date: Sun, 5 Jul 2020 20:13:45 -0500 Subject: [PATCH 095/296] brcmfmac: add support for CYW55560 SDIO chipset CYW55560 is a 2x2 dual-band 802.11a/b/g/n/ac/ax chipset with 20/40/80MHz channel support. It's a WLAN+BT combo device with WLAN secure boot support. Signed-off-by: Chung-Hsien Hsu --- .../broadcom/brcm80211/brcmfmac/bcmsdh.c | 6 + .../broadcom/brcm80211/brcmfmac/chip.c | 1 + .../broadcom/brcm80211/brcmfmac/sdio.c | 145 +++++++++++++++--- .../broadcom/brcm80211/brcmfmac/sdio.h | 4 + include/linux/mmc/sdio_ids.h | 1 + 5 files changed, 139 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c index a82cb8082548..913853c016d6 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c @@ -48,6 +48,8 @@ #define SDIO_435X_FUNC2_BLOCKSIZE 256 #define SDIO_4329_FUNC2_BLOCKSIZE 128 #define SDIO_89459_FUNC2_BLOCKSIZE 256 +#define SDIO_CYW55560_FUNC2_BLOCKSIZE 256 + /* Maximum milliseconds to wait for F2 to come up */ #define SDIO_WAIT_F2RDY 3000 @@ -925,6 +927,9 @@ int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev) case SDIO_DEVICE_ID_CYPRESS_54594: f2_blksz = SDIO_89459_FUNC2_BLOCKSIZE; break; + case SDIO_DEVICE_ID_CYPRESS_55560: + f2_blksz = SDIO_CYW55560_FUNC2_BLOCKSIZE; + break; default: break; } @@ -1008,6 +1013,7 @@ static const struct sdio_device_id brcmf_sdmmc_ids[] = { CYW_SDIO_DEVICE(SDIO_DEVICE_ID_CYPRESS_54590, CYW), CYW_SDIO_DEVICE(SDIO_DEVICE_ID_CYPRESS_54591, CYW), CYW_SDIO_DEVICE(SDIO_DEVICE_ID_CYPRESS_54594, CYW), + CYW_SDIO_DEVICE(SDIO_DEVICE_ID_CYPRESS_55560, CYW), { /* end: all zeroes */ } }; MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c index 652f272c2447..299298307901 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c @@ -1663,6 +1663,7 @@ bool brcmf_chip_sr_capable(struct brcmf_chip *pub) return reg != 0; case BRCM_CC_4355_CHIP_ID: case CY_CC_4373_CHIP_ID: + case CY_CC_55560_CHIP_ID: /* explicitly check SR engine enable bit */ addr = CORE_CC_REG(base, sr_control0); reg = chip->ops->read32(chip->ctx, addr); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index ee8e35e3fbfe..704ddd58f185 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -70,6 +70,10 @@ #define CY_89459_MES_WATERMARK 0x40 #define CY_89459_MESBUSYCTRL (CY_89459_MES_WATERMARK | \ SBSDIO_MESBUSYCTRL_ENAB) +#define CYW55560_F2_WATERMARK 0x40 +#define CYW55560_MES_WATERMARK 0x40 +#define CYW55560_F1_MESBUSYCTRL (CYW55560_MES_WATERMARK | \ + SBSDIO_MESBUSYCTRL_ENAB) #ifdef DEBUG @@ -647,6 +651,7 @@ CY_FW_DEF(4373, "cyfmac4373-sdio"); CY_FW_DEF(43012, "cyfmac43012-sdio"); BRCMF_FW_CLM_DEF(43752, "brcmfmac43752-sdio"); CY_FW_DEF(89459, "cyfmac54591-sdio"); +CY_FW_TRXSE_DEF(55560, "cyfmac55560-sdio"); /* firmware config files */ MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-sdio.*.txt"); @@ -681,7 +686,8 @@ static const struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = { BRCMF_FW_ENTRY(CY_CC_43012_CHIP_ID, 0xFFFFFFFF, 43012), BRCMF_FW_ENTRY(CY_CC_43439_CHIP_ID, 0xFFFFFFFF, 43439), BRCMF_FW_ENTRY(CY_CC_43752_CHIP_ID, 0xFFFFFFFF, 43752), - BRCMF_FW_ENTRY(CY_CC_89459_CHIP_ID, 0xFFFFFFFF, 89459) + BRCMF_FW_ENTRY(CY_CC_89459_CHIP_ID, 0xFFFFFFFF, 89459), + BRCMF_FW_ENTRY(CY_CC_55560_CHIP_ID, 0xFFFFFFFF, 55560) }; #define TXCTL_CREDITS 2 @@ -742,7 +748,8 @@ brcmf_sdio_kso_control(struct brcmf_sdio *bus, bool on) * fail. Thereby just bailing out immediately after clearing KSO * bit, to avoid polling of KSO bit. */ - if (!on && bus->ci->chip == CY_CC_43012_CHIP_ID) + if (!on && ((bus->ci->chip == CY_CC_43012_CHIP_ID) || + (bus->ci->chip == CY_CC_55560_CHIP_ID))) return err; if (on) { @@ -2544,7 +2551,8 @@ static bool brcmf_chip_is_ulp(struct brcmf_chip *ci) static bool brcmf_sdio_use_ht_avail(struct brcmf_chip *ci) { - if (ci->chip == CY_CC_4373_CHIP_ID) + if (ci->chip == CY_CC_4373_CHIP_ID || + ci->chip == CY_CC_55560_CHIP_ID) return true; else return false; @@ -3676,6 +3684,16 @@ static int brcmf_sdio_download_firmware(struct brcmf_sdio *bus, rstvec = get_unaligned_le32(fw->data); brcmf_dbg(SDIO, "firmware rstvec: %x\n", rstvec); + if (bus->ci->blhs) { + bcmerror = bus->ci->blhs->prep_fwdl(bus->ci); + if (bcmerror) { + brcmf_err("FW download preparation failed\n"); + release_firmware(fw); + brcmf_fw_nvram_free(nvram); + goto err; + } + } + bcmerror = brcmf_sdio_download_code_file(bus, fw); release_firmware(fw); if (bcmerror) { @@ -3684,6 +3702,22 @@ static int brcmf_sdio_download_firmware(struct brcmf_sdio *bus, goto err; } + if (bus->ci->blhs) { + bcmerror = bus->ci->blhs->post_fwdl(bus->ci); + if (bcmerror) { + brcmf_err("FW download failed, err=%d\n", bcmerror); + brcmf_fw_nvram_free(nvram); + goto err; + } + + bcmerror = bus->ci->blhs->chk_validation(bus->ci); + if (bcmerror) { + brcmf_err("FW valication failed, err=%d\n", bcmerror); + brcmf_fw_nvram_free(nvram); + goto err; + } + } + bcmerror = brcmf_sdio_download_nvram(bus, nvram, nvlen); brcmf_fw_nvram_free(nvram); if (bcmerror) { @@ -3691,11 +3725,14 @@ static int brcmf_sdio_download_firmware(struct brcmf_sdio *bus, goto err; } - /* Take arm out of reset */ - if (!brcmf_chip_set_active(bus->ci, rstvec)) { - brcmf_err("error getting out of ARM core reset\n"); - bcmerror = -EIO; - goto err; + if (bus->ci->blhs) { + bus->ci->blhs->post_nvramdl(bus->ci); + } else { + /* Take arm out of reset */ + if (!brcmf_chip_set_active(bus->ci, rstvec)) { + brcmf_err("error getting out of ARM core reset\n"); + goto err; + } } err: @@ -3709,6 +3746,7 @@ static bool brcmf_sdio_aos_no_decode(struct brcmf_sdio *bus) if (bus->ci->chip == CY_CC_43012_CHIP_ID || bus->ci->chip == CY_CC_43752_CHIP_ID || bus->ci->chip == CY_CC_4373_CHIP_ID || + bus->ci->chip == CY_CC_55560_CHIP_ID || bus->ci->chip == BRCM_CC_4339_CHIP_ID || bus->ci->chip == BRCM_CC_4345_CHIP_ID || bus->ci->chip == BRCM_CC_4354_CHIP_ID || @@ -4133,6 +4171,20 @@ brcmf_sdio_drivestrengthinit(struct brcmf_sdio_dev *sdiodev, } } +static u32 brcmf_sdio_buscore_blhs_read(void *ctx, u32 reg_offset) +{ + struct brcmf_sdio_dev *sdiodev = (struct brcmf_sdio_dev *)ctx; + + return (u32)brcmf_sdiod_readb(sdiodev, reg_offset, NULL); +} + +static void brcmf_sdio_buscore_blhs_write(void *ctx, u32 reg_offset, u32 value) +{ + struct brcmf_sdio_dev *sdiodev = (struct brcmf_sdio_dev *)ctx; + + brcmf_sdiod_writeb(sdiodev, reg_offset, (u8)value, NULL); +} + static int brcmf_sdio_buscoreprep(void *ctx) { struct brcmf_sdio_dev *sdiodev = ctx; @@ -4229,11 +4281,39 @@ static void brcmf_sdio_buscore_write32(void *ctx, u32 addr, u32 val) brcmf_sdiod_writel(sdiodev, addr, val, NULL); } +static int brcmf_sdio_buscore_blhs_attach(void *ctx, struct brcmf_blhs **blhs, + u32 flag, uint timeout, uint interval) +{ + struct brcmf_sdio_dev *sdiodev = (struct brcmf_sdio_dev *)ctx; + struct brcmf_blhs *blhsh; + u8 cardcap; + + if (sdiodev->func1->vendor != SDIO_VENDOR_ID_CYPRESS) + return 0; + + cardcap = brcmf_sdiod_func0_rb(sdiodev, SDIO_CCCR_BRCM_CARDCAP, NULL); + if (cardcap & SDIO_CCCR_BRCM_CARDCAP_SECURE_MODE) { + blhsh = kzalloc(sizeof(*blhsh), GFP_KERNEL); + if (!blhsh) + return -ENOMEM; + + blhsh->d2h = BRCMF_SDIO_REG_DAR_D2H_MSG_0; + blhsh->h2d = BRCMF_SDIO_REG_DAR_H2D_MSG_0; + blhsh->read = brcmf_sdio_buscore_blhs_read; + blhsh->write = brcmf_sdio_buscore_blhs_write; + + *blhs = blhsh; + } + + return 0; +} + static const struct brcmf_buscore_ops brcmf_sdio_buscore_ops = { .prepare = brcmf_sdio_buscoreprep, .activate = brcmf_sdio_buscore_activate, .read32 = brcmf_sdio_buscore_read32, .write32 = brcmf_sdio_buscore_write32, + .blhs_attach = brcmf_sdio_buscore_blhs_attach, }; static bool @@ -4345,17 +4425,21 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus) if (err) goto fail; - /* set PMUControl so a backplane reset does PMU state reload */ - reg_addr = CORE_CC_REG(brcmf_chip_get_pmu(bus->ci)->base, pmucontrol); - reg_val = brcmf_sdiod_readl(sdiodev, reg_addr, &err); - if (err) - goto fail; + if (!bus->ci->blhs) { + /* set PMUControl so a backplane reset does PMU state reload */ + reg_addr = CORE_CC_REG(brcmf_chip_get_pmu(bus->ci)->base, + pmucontrol); + reg_val = brcmf_sdiod_readl(sdiodev, reg_addr, &err); + if (err) + goto fail; - reg_val |= (BCMA_CC_PMU_CTL_RES_RELOAD << BCMA_CC_PMU_CTL_RES_SHIFT); + reg_val |= (BCMA_CC_PMU_CTL_RES_RELOAD << + BCMA_CC_PMU_CTL_RES_SHIFT); - brcmf_sdiod_writel(sdiodev, reg_addr, reg_val, &err); - if (err) - goto fail; + brcmf_sdiod_writel(sdiodev, reg_addr, reg_val, &err); + if (err) + goto fail; + } sdio_release_host(sdiodev->func1); @@ -4648,6 +4732,19 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err, brcmf_sdiod_writeb(sdiod, SBSDIO_FUNC1_MESBUSYCTRL, CY_89459_MESBUSYCTRL, &err); break; + case SDIO_DEVICE_ID_CYPRESS_55560: + brcmf_dbg(INFO, "set F2 watermark to 0x%x*4 bytes\n", + CYW55560_F2_WATERMARK); + brcmf_sdiod_writeb(sdiod, SBSDIO_WATERMARK, + CYW55560_F2_WATERMARK, &err); + devctl = brcmf_sdiod_readb(sdiod, SBSDIO_DEVICE_CTL, + &err); + devctl |= SBSDIO_DEVCTL_F2WM_ENAB; + brcmf_sdiod_writeb(sdiod, SBSDIO_DEVICE_CTL, devctl, + &err); + brcmf_sdiod_writeb(sdiod, SBSDIO_FUNC1_MESBUSYCTRL, + CYW55560_F1_MESBUSYCTRL, &err); + break; default: brcmf_sdiod_writeb(sdiod, SBSDIO_WATERMARK, DEFAULT_F2_WATERMARK, &err); @@ -4755,6 +4852,9 @@ brcmf_sdio_prepare_fw_request(struct brcmf_sdio *bus) { ".clm_blob", bus->sdiodev->clm_name }, }; + if (bus->ci->blhs) + fwnames[BRCMF_SDIO_FW_CODE].extension = ".trxse"; + fwreq = brcmf_fw_alloc_request(bus->ci->chip, bus->ci->chiprev, brcmf_sdio_fwnames, ARRAY_SIZE(brcmf_sdio_fwnames), @@ -4762,7 +4862,10 @@ brcmf_sdio_prepare_fw_request(struct brcmf_sdio *bus) if (!fwreq) return NULL; - fwreq->items[BRCMF_SDIO_FW_CODE].type = BRCMF_FW_TYPE_BINARY; + if (bus->ci->blhs) + fwreq->items[BRCMF_SDIO_FW_CODE].type = BRCMF_FW_TYPE_TRXSE; + else + fwreq->items[BRCMF_SDIO_FW_CODE].type = BRCMF_FW_TYPE_BINARY; fwreq->items[BRCMF_SDIO_FW_NVRAM].type = BRCMF_FW_TYPE_NVRAM; fwreq->items[BRCMF_SDIO_FW_CLM].type = BRCMF_FW_TYPE_BINARY; fwreq->items[BRCMF_SDIO_FW_CLM].flags = BRCMF_FW_REQF_OPTIONAL; @@ -4920,10 +5023,16 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus) } else { brcmf_chip_set_passive(bus->ci); } + + if (bus->ci->blhs) + bus->ci->blhs->init(bus->ci); /* Reset the PMU, backplane and all the * cores by using the PMUWatchdogCounter. */ brcmf_chip_reset_watchdog(bus->ci); + if (bus->ci->blhs) + bus->ci->blhs->post_wdreset(bus->ci); + brcmf_sdio_clkctl(bus, CLK_NONE, false); sdio_release_host(bus->sdiodev->func1); } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h index aadf251d5440..fa4838617805 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h @@ -28,12 +28,16 @@ #define REG_F0_REG_MASK 0x7FF #define REG_F1_MISC_MASK 0x1FFFF +#define BRCMF_SDIO_REG_DAR_H2D_MSG_0 0x10030 +#define BRCMF_SDIO_REG_DAR_D2H_MSG_0 0x10038 + /* function 0 vendor specific CCCR registers */ #define SDIO_CCCR_BRCM_CARDCAP 0xf0 #define SDIO_CCCR_BRCM_CARDCAP_CMD14_SUPPORT BIT(1) #define SDIO_CCCR_BRCM_CARDCAP_CMD14_EXT BIT(2) #define SDIO_CCCR_BRCM_CARDCAP_CMD_NODEC BIT(3) +#define SDIO_CCCR_BRCM_CARDCAP_SECURE_MODE BIT(7) /* Interrupt enable bits for each function */ #define SDIO_CCCR_IEN_FUNC0 BIT(0) diff --git a/include/linux/mmc/sdio_ids.h b/include/linux/mmc/sdio_ids.h index 8a9b481ff99d..190551d7876b 100644 --- a/include/linux/mmc/sdio_ids.h +++ b/include/linux/mmc/sdio_ids.h @@ -84,6 +84,7 @@ #define SDIO_DEVICE_ID_CYPRESS_54591 0xbd3b #define SDIO_DEVICE_ID_CYPRESS_54594 0xbd3c #define SDIO_DEVICE_ID_CYPRESS_43439 0xbd3d +#define SDIO_DEVICE_ID_CYPRESS_55560 0xbd31 #define SDIO_VENDOR_ID_MARVELL 0x02df #define SDIO_DEVICE_ID_MARVELL_LIBERTAS 0x9103 -- 2.25.1