Message ID | 20240909203133.74777-2-marex@denx.de |
---|---|
State | New |
Headers | show |
Series | [v2,1/2] wifi: brcmfmac: add support for TRX firmware download | expand |
On 9/9/2024 10:31 PM, Marek Vasut wrote: > From: Chung-Hsien Hsu <stanley.hsu@cypress.com> > > CYW55572 is a 2x2 dual-band 802.11a/b/g/n/ac/ax chipset with 20/40/80MHz > channel support. It is a WLAN+BT combo device with WLAN secure boot support. > The CYW55572 used to be labeled CYW55560. Reviewed-by: Arend van Spriel <arend.vanspriel@broadcom.com> > Signed-off-by: Chung-Hsien Hsu <stanley.hsu@cypress.com> Same remark here as in the first patch of this series. > Signed-off-by: Chung-Hsien Hsu <chung-hsien.hsu@infineon.com> > Signed-off-by: Carter Chen <carter.chen@infineon.com> > Signed-off-by: Owen Huang <Owen.Huang@infineon.com> > Signed-off-by: Marek Vasut <marex@denx.de> # Upport to current linux-next > --- > NOTE: This is squashed from downstream upports from > https://github.com/Infineon/ifx-wireless-drivers/ > branch RTM/v5.15.58-Indrik / tag release-v5.15.58-2024_0514 > - 8a41d39f6290 ("brcmfmac: add Cypress PCIe vendor ID") > - 12f74eba2569 ("brcmfmac: add support for CYW55560 PCIe chipset") > - ea4e4056a3f8 ("brcmfmac: update firmware loading name for CY5557x") > - ee322201fe11 ("brcmfmac: use SR core id to decide SR capability for CY55572") > - 0a47ed7f3678 ("brcmfmac: Fix invalid RAM address warning for PCIE platforms") This patch is a bit large and covering multiple concepts. At least the bootloader handshake implementation is worth a separate patch I would say. I skipped the related stuff for now. > --- > Cc: "Dr. David Alan Gilbert" <linux@treblig.org> > Cc: "Gustavo A. R. Silva" <gustavoars@kernel.org> > Cc: "Rafał Miłecki" <zajec5@gmail.com> > Cc: Arend van Spriel <arend.vanspriel@broadcom.com> > Cc: Bjorn Helgaas <bhelgaas@google.com> > Cc: Carter Chen <carter.chen@infineon.com> > Cc: Chung-Hsien Hsu <stanley.hsu@cypress.com> > Cc: Double Lo <Double.Lo@infineon.com> > Cc: Duoming Zhou <duoming@zju.edu.cn> > Cc: Erick Archer <erick.archer@outlook.com> > Cc: Kalle Valo <kvalo@kernel.org> > Cc: Kees Cook <kees@kernel.org> > Cc: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> > Cc: Mathias Krause <minipli@grsecurity.net> > Cc: Matthias Brugger <mbrugger@suse.com> > Cc: Owen Huang <Owen.Huang@infineon.com> > Cc: Ulf Hansson <ulf.hansson@linaro.org> > Cc: brcm80211-dev-list.pdl@broadcom.com > Cc: brcm80211@lists.linux.dev > Cc: linux-wireless@vger.kernel.org > --- > V2: - Fix up build warnings related to use of u32 instead of __le32 > - Include SoB line from Chung-Hsien with both cypress and infineon address > --- > .../broadcom/brcm80211/brcmfmac/bcmsdh.c | 6 + > .../broadcom/brcm80211/brcmfmac/chip.c | 214 +++++++++++++++++- > .../broadcom/brcm80211/brcmfmac/chip.h | 34 +++ > .../broadcom/brcm80211/brcmfmac/firmware.c | 15 +- > .../broadcom/brcm80211/brcmfmac/firmware.h | 8 +- > .../broadcom/brcm80211/brcmfmac/pcie.c | 192 +++++++++++++++- > .../broadcom/brcm80211/brcmfmac/sdio.c | 27 ++- > .../broadcom/brcm80211/include/brcm_hw_ids.h | 3 + > .../broadcom/brcm80211/include/brcmu_utils.h | 13 ++ > include/linux/bcma/bcma.h | 1 + > include/linux/mmc/sdio_ids.h | 1 + > 11 files changed, 497 insertions(+), 17 deletions(-) > > diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c > index d35262335eaf7..ae89d73eefb87 100644 > --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c > +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c > @@ -46,6 +46,8 @@ > #define SDIO_4373_FUNC2_BLOCKSIZE 256 > #define SDIO_435X_FUNC2_BLOCKSIZE 256 > #define SDIO_4329_FUNC2_BLOCKSIZE 128 > +#define SDIO_CYW55572_FUNC2_BLOCKSIZE 256 > + > /* Maximum milliseconds to wait for F2 to come up */ > #define SDIO_WAIT_F2RDY 3000 > > @@ -917,6 +919,9 @@ int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev) > case SDIO_DEVICE_ID_BROADCOM_4329: > f2_blksz = SDIO_4329_FUNC2_BLOCKSIZE; > break; > + case SDIO_DEVICE_ID_CYPRESS_55572: > + f2_blksz = SDIO_CYW55572_FUNC2_BLOCKSIZE; > + break; > default: > break; > } > @@ -996,6 +1001,7 @@ static const struct sdio_device_id brcmf_sdmmc_ids[] = { > BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_43752, CYW), > BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_89359, CYW), > CYW_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_43439, CYW), > + CYW_SDIO_DEVICE(SDIO_DEVICE_ID_CYPRESS_55572, 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 2ef92ef25517e..c5188a31c9efb 100644 > --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c > +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c > @@ -216,6 +216,32 @@ struct sbsocramregs { > #define ARMCR4_BSZ_MULT 8192 > #define ARMCR4_BLK_1K_MASK 0x200 > > +/* CYW55572 dedicated space and RAM base */ > +#define CYW55572_TCAM_SIZE 0x800 > +#define CYW55572_TRXHDR_SIZE 0x2b4 Please use sizeof(struct trxhdr_le) instead of hard value 0x2b4 (they are the same). > +#define CYW55572_RAM_BASE (0x370000 + \ > + CYW55572_TCAM_SIZE + CYW55572_TRXHDR_SIZE) > + > +#define BRCMF_BLHS_POLL_INTERVAL 10 /* msec */ > +#define BRCMF_BLHS_D2H_READY_TIMEOUT 100 /* msec */ > +#define BRCMF_BLHS_D2H_TRXHDR_PARSE_DONE_TIMEOUT 50 /* msec */ > +#define BRCMF_BLHS_D2H_VALDN_DONE_TIMEOUT 250 /* msec */ > + > +/* Bootloader handshake flags - dongle to host */ > +#define BRCMF_BLHS_D2H_START BIT(0) > +#define BRCMF_BLHS_D2H_READY BIT(1) > +#define BRCMF_BLHS_D2H_STEADY BIT(2) > +#define BRCMF_BLHS_D2H_TRXHDR_PARSE_DONE BIT(3) > +#define BRCMF_BLHS_D2H_VALDN_START BIT(4) > +#define BRCMF_BLHS_D2H_VALDN_RESULT BIT(5) > +#define BRCMF_BLHS_D2H_VALDN_DONE BIT(6) > + > +/* Bootloader handshake flags - host to dongle */ > +#define BRCMF_BLHS_H2D_DL_FW_START BIT(0) > +#define BRCMF_BLHS_H2D_DL_FW_DONE BIT(1) > +#define BRCMF_BLHS_H2D_DL_NVRAM_DONE BIT(2) > +#define BRCMF_BLHS_H2D_BL_RESET_ON_ERROR BIT(3) > + > struct brcmf_core_priv { > struct brcmf_core pub; > u32 wrapbase; > @@ -501,6 +527,21 @@ char *brcmf_chip_name(u32 id, u32 rev, char *buf, uint len) > return buf; > } > > +static bool brcmf_chip_find_coreid(struct brcmf_chip_priv *ci, u16 coreid) No need for this function. Simply use brcmf_chip_get_core(). > +{ > + struct brcmf_core_priv *core; > + > + list_for_each_entry(core, &ci->cores, list) { > + brcmf_dbg(TRACE, " core 0x%x:%-2d base 0x%08x wrap 0x%08x\n", > + core->pub.id, core->pub.rev, core->pub.base, > + core->wrapbase); > + if (core->pub.id == coreid) > + return true; > + } > + > + return false; > +} > + > static struct brcmf_core *brcmf_chip_add_core(struct brcmf_chip_priv *ci, > u16 coreid, u32 base, > u32 wrapbase) > @@ -745,6 +786,8 @@ static u32 brcmf_chip_tcm_rambase(struct brcmf_chip_priv *ci) > return 0x352000; > case BRCM_CC_4387_CHIP_ID: > return 0x740000; > + case CY_CC_55572_CHIP_ID: > + return CYW55572_RAM_BASE; > default: > brcmf_err("unknown chip: %s\n", ci->pub.name); > break; > @@ -763,6 +806,9 @@ int brcmf_chip_get_raminfo(struct brcmf_chip *pub) > if (mem) { > mem_core = container_of(mem, struct brcmf_core_priv, pub); > ci->pub.ramsize = brcmf_chip_tcm_ramsize(mem_core); > + if (ci->pub.chip == CY_CC_55572_CHIP_ID) > + ci->pub.ramsize -= (CYW55572_TCAM_SIZE + > + CYW55572_TRXHDR_SIZE); Please move this to the end of the function just before the debug print and use switch statement instead. > ci->pub.rambase = brcmf_chip_tcm_rambase(ci); > if (ci->pub.rambase == INVALID_RAMBASE) { > brcmf_err("RAM base not provided with ARM CR4 core\n"); > @@ -942,7 +988,8 @@ int brcmf_chip_dmp_erom_scan(struct brcmf_chip_priv *ci) > /* need core with ports */ > if (nmw + nsw == 0 && > id != BCMA_CORE_PMU && > - id != BCMA_CORE_GCI) > + id != BCMA_CORE_GCI && > + id != BCMA_CORE_SR) indentation wrong(?) > continue; > > /* try to obtain register address info */ > @@ -966,6 +1013,144 @@ u32 brcmf_chip_enum_base(u16 devid) > return SI_ENUM_BASE_DEFAULT; > } [...] as mentioned skipped blhs stuff for now. > static int brcmf_chip_recognition(struct brcmf_chip_priv *ci) > { > struct brcmf_core *core; > @@ -1123,6 +1308,7 @@ struct brcmf_chip *brcmf_chip_attach(void *ctx, u16 devid, > const struct brcmf_buscore_ops *ops) > { > struct brcmf_chip_priv *chip; > + struct brcmf_blhs *blhs; > int err = 0; > > if (WARN_ON(!ops->read32)) > @@ -1150,6 +1336,26 @@ struct brcmf_chip *brcmf_chip_attach(void *ctx, u16 devid, > if (err < 0) > goto fail; > > + blhs = NULL; > + if (chip->ops->blhs_attach) { > + err = chip->ops->blhs_attach(chip->ctx, &blhs, > + BRCMF_BLHS_D2H_READY, > + BRCMF_BLHS_D2H_READY_TIMEOUT, > + BRCMF_BLHS_POLL_INTERVAL); > + if (err < 0) > + goto fail; > + > + if (blhs) { > + blhs->init = brcmf_blhs_init; > + blhs->prep_fwdl = brcmf_blhs_prep_fw_download; > + blhs->post_fwdl = brcmf_blhs_post_fw_download; > + blhs->post_nvramdl = brcmf_blhs_post_nvram_download; > + blhs->chk_validation = brcmf_blhs_chk_validation; > + blhs->post_wdreset = brcmf_blhs_post_watchdog_reset; > + } > + } > + chip->pub.blhs = blhs; > + > err = brcmf_chip_recognition(chip); > if (err < 0) > goto fail; > @@ -1176,6 +1382,7 @@ void brcmf_chip_detach(struct brcmf_chip *pub) > list_del(&core->list); > kfree(core); > } > + kfree(pub->blhs); > kfree(chip); > } > > @@ -1309,7 +1516,8 @@ brcmf_chip_cr4_set_passive(struct brcmf_chip_priv *chip) > int i; > struct brcmf_core *core; > > - brcmf_chip_disable_arm(chip, BCMA_CORE_ARM_CR4); > + if (!chip->pub.blhs) > + brcmf_chip_disable_arm(chip, BCMA_CORE_ARM_CR4); > > /* Disable the cores only and let the firmware enable them. > * Releasing reset ourselves breaks BCM4387 in weird ways. > @@ -1456,6 +1664,8 @@ bool brcmf_chip_sr_capable(struct brcmf_chip *pub) > reg = chip->ops->read32(chip->ctx, addr); > return (reg & (PMU_RCTL_MACPHY_DISABLE_MASK | > PMU_RCTL_LOGIC_DISABLE_MASK)) == 0; > + case CY_CC_55572_CHIP_ID: > + return brcmf_chip_find_coreid(chip, BCMA_CORE_SR); Simply use !!brcmf_chip_get_core(chip, BCMA_CORE_SR) here although I am surprised the presence is sufficient here. I would suggest reading control0 register (offset 0x4): sr = brcmf_chip_get_core(chip, BCMA_CORE_SR); if (sr) { reg = chip->ops->read32(chip->ctx, sr->base + 0x4); return (reg & CC_SR_CTL0_ENABLE_MASK) != 0; } return false; > default: > addr = CORE_CC_REG(pmu->base, pmucapabilities_ext); > reg = chip->ops->read32(chip->ctx, addr); > diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h > index d69f101f58344..0a00fb9d7632e 100644 > --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h > +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h > @@ -10,6 +10,8 @@ > #define CORE_CC_REG(base, field) \ > (base + offsetof(struct chipcregs, field)) > > +struct brcmf_blhs; > + Just put the struct brcmf_blhs here and drop the forward declaration. > /** > * struct brcmf_chip - chip level information. > * > @@ -24,6 +26,7 @@ > * @ramsize: amount of RAM on chip including retention. > * @srsize: amount of retention RAM on chip. > * @name: string representation of the chip identifier. > + * @blhs: bootlooder handshake handle. > */ > struct brcmf_chip { > u32 chip; > @@ -37,6 +40,7 @@ struct brcmf_chip { > u32 ramsize; > u32 srsize; > char name[12]; > + struct brcmf_blhs *blhs; > }; > > /** > @@ -61,6 +65,7 @@ struct brcmf_core { > * @setup: bus-specific core setup. > * @active: chip becomes active. > * The callback should use the provided @rstvec when non-zero. > + * @blhs_attach: attach bootloader handshake handle > */ > struct brcmf_buscore_ops { > u32 (*read32)(void *ctx, u32 addr); > @@ -69,6 +74,35 @@ struct brcmf_buscore_ops { > int (*reset)(void *ctx, struct brcmf_chip *chip); > int (*setup)(void *ctx, struct brcmf_chip *chip); > void (*activate)(void *ctx, struct brcmf_chip *chip, u32 rstvec); > + int (*blhs_attach)(void *ctx, struct brcmf_blhs **blhs, u32 flag, > + uint timeout, uint interval); > +}; > + > +/** > + * struct brcmf_blhs - bootloader handshake handle related information. > + * > + * @d2h: offset of dongle to host register for the handshake. > + * @h2d: offset of host to dongle register for the handshake. > + * @init: bootloader handshake initialization. > + * @prep_fwdl: handshake before firmware download. > + * @post_fwdl: handshake after firmware download. > + * @post_nvramdl: handshake after nvram download. > + * @chk_validation: handshake for firmware validation check. > + * @post_wdreset: handshake after watchdog reset. > + * @read: read value with register offset for the handshake. > + * @write: write value with register offset for the handshake. > + */ > +struct brcmf_blhs { > + u32 d2h; > + u32 h2d; > + void (*init)(struct brcmf_chip *pub); > + int (*prep_fwdl)(struct brcmf_chip *pub); > + int (*post_fwdl)(struct brcmf_chip *pub); > + void (*post_nvramdl)(struct brcmf_chip *pub); > + int (*chk_validation)(struct brcmf_chip *pub); > + int (*post_wdreset)(struct brcmf_chip *pub); > + u32 (*read)(void *ctx, u32 addr); > + void (*write)(void *ctx, u32 addr, u32 value); > }; > > int brcmf_chip_get_raminfo(struct brcmf_chip *pub); > diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c > index 83f8ed7d00f96..1d5be3ce51ccf 100644 > --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c > +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c > @@ -527,7 +527,8 @@ static void brcmf_fw_free_request(struct brcmf_fw_request *req) > int i; > > for (i = 0, item = &req->items[0]; i < req->n_items; i++, item++) { > - if (item->type == BRCMF_FW_TYPE_BINARY) > + if (item->type == BRCMF_FW_TYPE_BINARY || > + item->type == BRCMF_FW_TYPE_TRXSE) > release_firmware(item->binary); > else if (item->type == BRCMF_FW_TYPE_NVRAM) > brcmf_fw_nvram_free(item->nv_data.data); > @@ -599,6 +600,7 @@ static int brcmf_fw_complete_request(const struct firmware *fw, > ret = brcmf_fw_request_nvram_done(fw, fwctx); > break; > case BRCMF_FW_TYPE_BINARY: > + case BRCMF_FW_TYPE_TRXSE: > if (fw) > cur->binary = fw; > else > @@ -672,8 +674,19 @@ static int brcmf_fw_request_firmware(const struct firmware **fw, > static void brcmf_fw_request_done(const struct firmware *fw, void *ctx) > { > struct brcmf_fw *fwctx = ctx; > + struct brcmf_fw_item *cur = &fwctx->req->items[fwctx->curpos]; > + char alt_path[BRCMF_FW_NAME_LEN]; > int ret; > > + if (!fw && cur->type == BRCMF_FW_TYPE_TRXSE) { > + strscpy(alt_path, cur->path, BRCMF_FW_NAME_LEN); > + /* strip 'se' from .trxse at the end */ > + alt_path[strlen(alt_path) - 2] = 0; > + ret = request_firmware(&fw, alt_path, fwctx->dev); What is the reason for stripping the 'se'. Just keep it. > + if (!ret) > + cur->path = alt_path; > + } > + > ret = brcmf_fw_complete_request(fw, fwctx); > > while (ret == 0 && ++fwctx->curpos < fwctx->req->n_items) { > diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h > index 4002d326fd21b..ab709babd649a 100644 > --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h > +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h > @@ -41,6 +41,11 @@ static const char BRCM_ ## fw_name ## _FIRMWARE_BASENAME[] = \ > MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH fw_base ".bin"); \ > MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH fw_base ".clm_blob") > > +#define CY_FW_TRXSE_DEF(fw_name, fw_base) \ > +static const char BRCM_ ## fw_name ## _FIRMWARE_BASENAME[] = \ > + BRCMF_FW_DEFAULT_PATH fw_base; \ > +MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH fw_base ".trxse") > + > #define BRCMF_FW_ENTRY(chipid, mask, name) \ > { chipid, mask, BRCM_ ## name ## _FIRMWARE_BASENAME } > > @@ -48,7 +53,8 @@ void brcmf_fw_nvram_free(void *nvram); > > enum brcmf_fw_type { > BRCMF_FW_TYPE_BINARY, > - BRCMF_FW_TYPE_NVRAM > + BRCMF_FW_TYPE_NVRAM, > + BRCMF_FW_TYPE_TRXSE > }; > > struct brcmf_fw_item { > diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c > index 058a742d17eda..15b045ab477ca 100644 > --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c > +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c > @@ -71,6 +71,7 @@ BRCMF_FW_CLM_DEF(4377B3, "brcmfmac4377b3-pcie"); > BRCMF_FW_CLM_DEF(4378B1, "brcmfmac4378b1-pcie"); > BRCMF_FW_CLM_DEF(4378B3, "brcmfmac4378b3-pcie"); > BRCMF_FW_CLM_DEF(4387C2, "brcmfmac4387c2-pcie"); > +CY_FW_TRXSE_DEF(55572, "cyfmac55572-pcie"); > > /* firmware config files */ > MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-pcie.txt"); > @@ -109,6 +110,7 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { > BRCMF_FW_ENTRY(BRCM_CC_4378_CHIP_ID, 0x0000000F, 4378B1), /* revision ID 3 */ > BRCMF_FW_ENTRY(BRCM_CC_4378_CHIP_ID, 0xFFFFFFE0, 4378B3), /* revision ID 5 */ > BRCMF_FW_ENTRY(BRCM_CC_4387_CHIP_ID, 0xFFFFFFFF, 4387C2), /* revision ID 7 */ > + BRCMF_FW_ENTRY(CY_CC_55572_CHIP_ID, 0xFFFFFFFF, 55572), What chip revisions did you come across? We can keep the revmask as above for now, but I would like to know what is out there. > }; > > #define BRCMF_PCIE_FW_UP_TIMEOUT 5000 /* msec */ > @@ -121,7 +123,8 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { > #define BRCMF_PCIE_BAR0_WRAPPERBASE 0x70 > > #define BRCMF_PCIE_BAR0_WRAPBASE_DMP_OFFSET 0x1000 > -#define BRCMF_PCIE_BARO_PCIE_ENUM_OFFSET 0x2000 > +#define BRCMF_PCIE_BAR0_PCIE_ENUM_OFFSET 0x2000 > +#define BRCMF_CYW55572_PCIE_BAR0_PCIE_ENUM_OFFSET 0x3000 > > #define BRCMF_PCIE_ARMCR4REG_BANKIDX 0x40 > #define BRCMF_PCIE_ARMCR4REG_BANKPDA 0x4C > @@ -139,6 +142,8 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { > #define BRCMF_PCIE_PCIE2REG_CONFIGDATA 0x124 > #define BRCMF_PCIE_PCIE2REG_H2D_MAILBOX_0 0x140 > #define BRCMF_PCIE_PCIE2REG_H2D_MAILBOX_1 0x144 > +#define BRCMF_PCIE_PCIE2REG_DAR_D2H_MSG_0 0xA80 > +#define BRCMF_PCIE_PCIE2REG_DAR_H2D_MSG_0 0xA90 > > #define BRCMF_PCIE_64_PCIE2REG_INTMASK 0xC14 > #define BRCMF_PCIE_64_PCIE2REG_MAILBOXINT 0xC30 > @@ -271,18 +276,32 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { > #define BRCMF_PCIE_CFGREG_MSI_ADDR_L 0x5C > #define BRCMF_PCIE_CFGREG_MSI_ADDR_H 0x60 > #define BRCMF_PCIE_CFGREG_MSI_DATA 0x64 > +#define BRCMF_PCIE_CFGREG_REVID 0x6C > #define BRCMF_PCIE_CFGREG_LINK_STATUS_CTRL 0xBC > #define BRCMF_PCIE_CFGREG_LINK_STATUS_CTRL2 0xDC > #define BRCMF_PCIE_CFGREG_RBAR_CTRL 0x228 > #define BRCMF_PCIE_CFGREG_PML1_SUB_CTRL1 0x248 > #define BRCMF_PCIE_CFGREG_REG_BAR2_CONFIG 0x4E0 > #define BRCMF_PCIE_CFGREG_REG_BAR3_CONFIG 0x4F4 > +#define BRCMF_PCIE_CFGREG_REVID_SECURE_MODE BIT(31) > #define BRCMF_PCIE_LINK_STATUS_CTRL_ASPM_ENAB 3 > > /* Magic number at a magic location to find RAM size */ > #define BRCMF_RAMSIZE_MAGIC 0x534d4152 /* SMAR */ > #define BRCMF_RAMSIZE_OFFSET 0x6c > > +#define BRCMF_ENTROPY_SEED_LEN 64u > +#define BRCMF_ENTROPY_NONCE_LEN 16u > +#define BRCMF_ENTROPY_HOST_LEN (BRCMF_ENTROPY_SEED_LEN + \ > + BRCMF_ENTROPY_NONCE_LEN) > +#define BRCMF_NVRAM_OFFSET_TCM 4u > +#define BRCMF_NVRAM_COMPRS_FACTOR 4u > +#define BRCMF_NVRAM_RNG_SIGNATURE 0xFEEDC0DEu > + > +struct brcmf_rand_metadata { > + __le32 signature; > + __le32 count; > +}; > > struct brcmf_pcie_console { > u32 base_addr; > @@ -679,9 +698,15 @@ static void brcmf_pcie_reset_device(struct brcmf_pciedev_info *devinfo) > val); > > /* Watchdog reset */ > + if (devinfo->ci->blhs) > + devinfo->ci->blhs->init(devinfo->ci); > brcmf_pcie_select_core(devinfo, BCMA_CORE_CHIPCOMMON); > WRITECC32(devinfo, watchdog, 4); > msleep(100); > + if (devinfo->ci->blhs) > + if (devinfo->ci->blhs->post_wdreset(devinfo->ci)) > + return; use single if statement and-ing the two conditions. > + > > /* Restore ASPM */ > brcmf_pcie_select_core(devinfo, BCMA_CORE_PCIE2); > @@ -722,6 +747,9 @@ static void brcmf_pcie_attach(struct brcmf_pciedev_info *devinfo) > > static int brcmf_pcie_enter_download_state(struct brcmf_pciedev_info *devinfo) > { > + struct brcmf_bus *bus = dev_get_drvdata(&devinfo->pdev->dev); > + int err = 0; > + > if (devinfo->ci->chip == BRCM_CC_43602_CHIP_ID) { > brcmf_pcie_select_core(devinfo, BCMA_CORE_ARM_CR4); > brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_ARMCR4REG_BANKIDX, > @@ -733,7 +761,14 @@ static int brcmf_pcie_enter_download_state(struct brcmf_pciedev_info *devinfo) > brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_ARMCR4REG_BANKPDA, > 0); > } > - return 0; > + > + if (devinfo->ci->blhs) { > + err = devinfo->ci->blhs->prep_fwdl(devinfo->ci); > + if (err) > + brcmf_err(bus, "FW download preparation failed"); > + } > + > + return err; > } > > > @@ -747,8 +782,13 @@ static int brcmf_pcie_exit_download_state(struct brcmf_pciedev_info *devinfo, > brcmf_chip_resetcore(core, 0, 0, 0); > } > > - if (!brcmf_chip_set_active(devinfo->ci, resetintr)) > - return -EIO; > + if (devinfo->ci->blhs) { > + devinfo->ci->blhs->post_nvramdl(devinfo->ci); > + } else { > + if (!brcmf_chip_set_active(devinfo->ci, resetintr)) > + return -EIO; > + } > + > return 0; > } > > @@ -1608,6 +1648,27 @@ brcmf_pcie_adjust_ramsize(struct brcmf_pciedev_info *devinfo, u8 *data, > } > > > +static void > +brcmf_pcie_write_rand(struct brcmf_pciedev_info *devinfo, u32 nvram_csm) I mentioned in v1 that there is already a (probably incompatible) mechinism for providing random seed to firmware. Prefer to explore possible reuse or at least align code flow if possible. > +{ > + struct brcmf_rand_metadata rand_data; > + u8 rand_buf[BRCMF_ENTROPY_HOST_LEN]; > + u32 count = BRCMF_ENTROPY_HOST_LEN; > + u32 address; > + > + address = devinfo->ci->rambase + > + (devinfo->ci->ramsize - BRCMF_NVRAM_OFFSET_TCM) - > + ((nvram_csm & 0xffff) * BRCMF_NVRAM_COMPRS_FACTOR) - > + sizeof(rand_data); > + memset(rand_buf, 0, BRCMF_ENTROPY_HOST_LEN); > + rand_data.signature = cpu_to_le32(BRCMF_NVRAM_RNG_SIGNATURE); > + rand_data.count = cpu_to_le32(count); > + memcpy_toio(devinfo->tcm + address, &rand_data, sizeof(rand_data)); > + address -= count; > + get_random_bytes(rand_buf, count); > + memcpy_toio(devinfo->tcm + address, rand_buf, count); > +} > + > static int > brcmf_pcie_init_share_ram_info(struct brcmf_pciedev_info *devinfo, > u32 sharedram_addr) > @@ -1693,6 +1754,8 @@ static int brcmf_pcie_download_fw_nvram(struct brcmf_pciedev_info *devinfo, > int err; > u32 address; > u32 resetintr; > + u32 nvram_lenw; > + u32 nvram_csm; > > brcmf_dbg(PCIE, "Halt ARM.\n"); > err = brcmf_pcie_enter_download_state(devinfo); > @@ -1711,16 +1774,40 @@ static int brcmf_pcie_download_fw_nvram(struct brcmf_pciedev_info *devinfo, > resetintr = get_unaligned_le32(fw->data); > release_firmware(fw); > > - /* reset last 4 bytes of RAM address. to be used for shared > - * area. This identifies when FW is running > - */ > - brcmf_pcie_write_ram32(devinfo, devinfo->ci->ramsize - 4, 0); > + if (devinfo->ci->blhs) { > + err = devinfo->ci->blhs->post_fwdl(devinfo->ci); > + if (err) { > + brcmf_err(bus, "FW download failed, err=%d\n", err); > + return err; > + } > + > + err = devinfo->ci->blhs->chk_validation(devinfo->ci); > + if (err) { > + brcmf_err(bus, "FW valication failed, err=%d\n", err); typo > + return err; > + } > + } else { > + /* reset last 4 bytes of RAM address. to be used for shared > + * area. This identifies when FW is running > + */ > + brcmf_pcie_write_ram32(devinfo, devinfo->ci->ramsize - 4, 0); > + } > > if (nvram) { > brcmf_dbg(PCIE, "Download NVRAM %s\n", devinfo->nvram_name); > address = devinfo->ci->rambase + devinfo->ci->ramsize - > nvram_len; > + > + if (devinfo->ci->blhs) > + address -= 4; > memcpy_toio(devinfo->tcm + address, nvram, nvram_len); > + > + /* Convert nvram_len to words to determine the length token */ > + nvram_lenw = nvram_len / 4; > + /* subtract word used to store the token itself on non-blhs devices */ > + if (!devinfo->ci->blhs) > + nvram_lenw -= 1; > + nvram_csm = (~nvram_lenw << 16) | (nvram_lenw & 0x0000FFFF); > brcmf_fw_nvram_free(nvram); > > if (devinfo->otp.valid) { > @@ -1743,10 +1830,20 @@ static int brcmf_pcie_download_fw_nvram(struct brcmf_pciedev_info *devinfo, > brcmf_pcie_provide_random_bytes(devinfo, address); > } > } else { > + nvram_csm = 0; > brcmf_dbg(PCIE, "No matching NVRAM file found %s\n", > devinfo->nvram_name); > } > > + if (devinfo->ci->chip == CY_CC_55572_CHIP_ID) { > + /* Write the length token to the last word of RAM address */ > + brcmf_pcie_write_ram32(devinfo, devinfo->ci->ramsize - 4, > + (u32)cpu_to_le32(nvram_csm)); > + > + /* Write random numbers to TCM for randomizing heap address */ > + brcmf_pcie_write_rand(devinfo, nvram_csm); > + } > + > sharedram_addr_written = brcmf_pcie_read_ram32(devinfo, > devinfo->ci->ramsize - > 4); > @@ -1837,6 +1934,21 @@ static void brcmf_pcie_release_resource(struct brcmf_pciedev_info *devinfo) > pci_disable_device(devinfo->pdev); > } > > +static u32 brcmf_pcie_buscore_blhs_read(void *ctx, u32 reg_offset) > +{ > + struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)ctx; > + > + brcmf_pcie_select_core(devinfo, BCMA_CORE_PCIE2); > + return brcmf_pcie_read_reg32(devinfo, reg_offset); > +} > + > +static void brcmf_pcie_buscore_blhs_write(void *ctx, u32 reg_offset, u32 value) > +{ > + struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)ctx; > + > + brcmf_pcie_select_core(devinfo, BCMA_CORE_PCIE2); > + brcmf_pcie_write_reg32(devinfo, reg_offset, value); > +} > > static u32 brcmf_pcie_buscore_prep_addr(const struct pci_dev *pdev, u32 addr) > { > @@ -1907,12 +2019,63 @@ static void brcmf_pcie_buscore_activate(void *ctx, struct brcmf_chip *chip, > } > > > +static int brcmf_pcie_buscore_blhs_attach(void *ctx, struct brcmf_blhs **blhs, > + u32 flag, uint timeout, uint interval) > +{ > + struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)ctx; > + struct brcmf_bus *bus = dev_get_drvdata(&devinfo->pdev->dev); > + struct brcmf_blhs *blhsh; > + u32 regdata; > + u32 pcie_enum; > + u32 addr; > + > + if (devinfo->pdev->vendor != CY_PCIE_VENDOR_ID_CYPRESS) > + return 0; > + > + pci_read_config_dword(devinfo->pdev, BRCMF_PCIE_CFGREG_REVID, ®data); > + if (regdata & BRCMF_PCIE_CFGREG_REVID_SECURE_MODE) { > + blhsh = kzalloc(sizeof(*blhsh), GFP_KERNEL); > + if (!blhsh) > + return -ENOMEM; > + > + blhsh->d2h = BRCMF_PCIE_PCIE2REG_DAR_D2H_MSG_0; > + blhsh->h2d = BRCMF_PCIE_PCIE2REG_DAR_H2D_MSG_0; > + blhsh->read = brcmf_pcie_buscore_blhs_read; > + blhsh->write = brcmf_pcie_buscore_blhs_write; > + > + /* Host indication for bootloarder to start the init */ > + if (devinfo->pdev->device == CY_PCIE_55572_DEVICE_ID) > + pcie_enum = BRCMF_CYW55572_PCIE_BAR0_PCIE_ENUM_OFFSET; > + else > + pcie_enum = BRCMF_PCIE_BAR0_PCIE_ENUM_OFFSET; > + > + pci_read_config_dword(devinfo->pdev, PCI_BASE_ADDRESS_0, > + ®data); > + addr = regdata + pcie_enum + blhsh->h2d; > + brcmf_pcie_buscore_write32(ctx, addr, 0); > + > + addr = regdata + pcie_enum + blhsh->d2h; > + SPINWAIT_MS((brcmf_pcie_buscore_read32(ctx, addr) & flag) == 0, > + timeout, interval); > + regdata = brcmf_pcie_buscore_read32(ctx, addr); > + if (!(regdata & flag)) { > + brcmf_err(bus, "Timeout waiting for bootloader ready\n"); > + kfree(blhsh); > + return -EPERM; > + } > + *blhs = blhsh; > + } > + > + return 0; > +} > + > static const struct brcmf_buscore_ops brcmf_pcie_buscore_ops = { > .prepare = brcmf_pcie_buscoreprep, > .reset = brcmf_pcie_buscore_reset, > .activate = brcmf_pcie_buscore_activate, > .read32 = brcmf_pcie_buscore_read32, > .write32 = brcmf_pcie_buscore_write32, > + .blhs_attach = brcmf_pcie_buscore_blhs_attach, > }; > > #define BRCMF_OTP_SYS_VENDOR 0x15 > @@ -2243,6 +2406,9 @@ brcmf_pcie_prepare_fw_request(struct brcmf_pciedev_info *devinfo) > { ".txcap_blob", devinfo->txcap_name }, > }; > > + if (devinfo->ci->blhs) > + fwnames[BRCMF_PCIE_FW_CODE].extension = ".trxse"; > + > fwreq = brcmf_fw_alloc_request(devinfo->ci->chip, devinfo->ci->chiprev, > brcmf_pcie_fwnames, > ARRAY_SIZE(brcmf_pcie_fwnames), > @@ -2250,7 +2416,10 @@ brcmf_pcie_prepare_fw_request(struct brcmf_pciedev_info *devinfo) > if (!fwreq) > return NULL; > > - fwreq->items[BRCMF_PCIE_FW_CODE].type = BRCMF_FW_TYPE_BINARY; > + if (devinfo->ci->blhs) > + fwreq->items[BRCMF_PCIE_FW_CODE].type = BRCMF_FW_TYPE_TRXSE; > + else > + fwreq->items[BRCMF_PCIE_FW_CODE].type = BRCMF_FW_TYPE_BINARY; > fwreq->items[BRCMF_PCIE_FW_NVRAM].type = BRCMF_FW_TYPE_NVRAM; > fwreq->items[BRCMF_PCIE_FW_NVRAM].flags = BRCMF_FW_REQF_OPTIONAL; > fwreq->items[BRCMF_PCIE_FW_CLM].type = BRCMF_FW_TYPE_BINARY; > @@ -2678,6 +2847,9 @@ static const struct dev_pm_ops brcmf_pciedrvr_pm = { > BRCMF_FWVENDOR_ ## fw_vend \ > } > > +#define BRCMF_PCIE_DEVICE_CY(dev_id) { CY_PCIE_VENDOR_ID_CYPRESS, dev_id,\ > + PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_OTHER << 8, 0xffff00, 0 } > + > static const struct pci_device_id brcmf_pcie_devid_table[] = { > BRCMF_PCIE_DEVICE(BRCM_PCIE_4350_DEVICE_ID, WCC), > BRCMF_PCIE_DEVICE_SUB(0x4355, BRCM_PCIE_VENDOR_ID_BROADCOM, 0x4355, WCC), > @@ -2706,7 +2878,7 @@ static const struct pci_device_id brcmf_pcie_devid_table[] = { > BRCMF_PCIE_DEVICE(BRCM_PCIE_4377_DEVICE_ID, WCC), > BRCMF_PCIE_DEVICE(BRCM_PCIE_4378_DEVICE_ID, WCC), > BRCMF_PCIE_DEVICE(BRCM_PCIE_4387_DEVICE_ID, WCC), > - > + BRCMF_PCIE_DEVICE_CY(CY_PCIE_55572_DEVICE_ID), > { /* end: all zeroes */ } > }; > > diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c > index 08881e366cae2..3bb03de1c2d29 100644 > --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c > +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c > @@ -59,6 +59,10 @@ > #define CY_435X_F2_WATERMARK 0x40 > #define CY_435X_F1_MESBUSYCTRL (CY_435X_F2_WATERMARK | \ > SBSDIO_MESBUSYCTRL_ENAB) > +#define CYW55572_F2_WATERMARK 0x40 > +#define CYW55572_MES_WATERMARK 0x40 > +#define CYW55572_F1_MESBUSYCTRL (CYW55572_MES_WATERMARK | \ > + SBSDIO_MESBUSYCTRL_ENAB) > > #ifdef DEBUG > > @@ -626,6 +630,7 @@ BRCMF_FW_DEF(4359, "brcmfmac4359-sdio"); > BRCMF_FW_CLM_DEF(4373, "brcmfmac4373-sdio"); > BRCMF_FW_CLM_DEF(43012, "brcmfmac43012-sdio"); > BRCMF_FW_CLM_DEF(43752, "brcmfmac43752-sdio"); > +CY_FW_TRXSE_DEF(55572, "cyfmac55572-sdio"); > > /* firmware config files */ > MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-sdio.*.txt"); > @@ -658,7 +663,8 @@ static const struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = { > BRCMF_FW_ENTRY(CY_CC_4373_CHIP_ID, 0xFFFFFFFF, 4373), > 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_43752_CHIP_ID, 0xFFFFFFFF, 43752), > + BRCMF_FW_ENTRY(CY_CC_55572_CHIP_ID, 0xFFFFFFFF, 55572) > }; > > #define TXCTL_CREDITS 2 > @@ -719,7 +725,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_55572_CHIP_ID)) > return err; > > if (on) { > @@ -3435,7 +3442,8 @@ static int brcmf_sdio_download_firmware(struct brcmf_sdio *bus, > 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_43752_CHIP_ID || > + bus->ci->chip == CY_CC_55572_CHIP_ID) > return true; > else > return false; > @@ -4352,6 +4360,19 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err, > brcmf_sdiod_writeb(sdiod, SBSDIO_FUNC1_MESBUSYCTRL, > CY_435X_F1_MESBUSYCTRL, &err); > break; > + case SDIO_DEVICE_ID_CYPRESS_55572: > + brcmf_dbg(INFO, "set F2 watermark to 0x%x*4 bytes\n", > + CYW55572_F2_WATERMARK); > + brcmf_sdiod_writeb(sdiod, SBSDIO_WATERMARK, > + CYW55572_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, > + CYW55572_F1_MESBUSYCTRL, &err); > + break; > default: > brcmf_sdiod_writeb(sdiod, SBSDIO_WATERMARK, > DEFAULT_F2_WATERMARK, &err); > diff --git a/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h b/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h > index 44684bf1b9acc..fc1757c505312 100644 > --- a/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h > +++ b/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h > @@ -14,6 +14,7 @@ > #define BRCM_USB_VENDOR_ID_LINKSYS 0x13b1 > #define CY_USB_VENDOR_ID_CYPRESS 0x04b4 > #define BRCM_PCIE_VENDOR_ID_BROADCOM PCI_VENDOR_ID_BROADCOM > +#define CY_PCIE_VENDOR_ID_CYPRESS 0x12be Looked up this vendor id and it is registered to Anchor Chips Inc. which apparently was acquired by Cypress in 1999. Maybe good to add a definition in include/linux/pci_ids for this, but not sure whether to call it PCI_VENDOR_ID_CYPRESS or PCI_VENDOR_ID_INFINEON. PCI_VENDOR_ID_ANCHOR_CHIPS seems a bit stale to choose. > /* Chipcommon Core Chip IDs */ > #define BRCM_CC_43143_CHIP_ID 43143 > @@ -59,6 +60,7 @@ > #define CY_CC_43012_CHIP_ID 43012 > #define CY_CC_43439_CHIP_ID 43439 > #define CY_CC_43752_CHIP_ID 43752 > +#define CY_CC_55572_CHIP_ID 0xd908 > > /* USB Device IDs */ > #define BRCM_USB_43143_DEVICE_ID 0xbd1e > @@ -97,6 +99,7 @@ > #define BRCM_PCIE_4377_DEVICE_ID 0x4488 > #define BRCM_PCIE_4378_DEVICE_ID 0x4425 > #define BRCM_PCIE_4387_DEVICE_ID 0x4433 > +#define CY_PCIE_55572_DEVICE_ID 0xbd31 > > /* brcmsmac IDs */ > #define BCM4313_D11N2G_ID 0x4727 /* 4313 802.11n 2.4G device */ > diff --git a/drivers/net/wireless/broadcom/brcm80211/include/brcmu_utils.h b/drivers/net/wireless/broadcom/brcm80211/include/brcmu_utils.h > index 9465323286673..48791ac87496d 100644 > --- a/drivers/net/wireless/broadcom/brcm80211/include/brcmu_utils.h > +++ b/drivers/net/wireless/broadcom/brcm80211/include/brcmu_utils.h > @@ -21,6 +21,19 @@ > } \ > } > > +/* Spin at most 'ms' milliseconds with polling interval 'interval' milliseconds > + * while 'exp' is true. Caller should explicitly test 'exp' when this completes > + * and take appropriate error action if 'exp' is still true. > + */ > +#define SPINWAIT_MS(exp, ms, interval) { \ > + typeof(interval) interval_ = (interval); \ > + uint countdown = (ms) + (interval_ - 1U); \ > + while ((exp) && (countdown >= interval_)) { \ > + msleep(interval_); \ > + countdown -= interval_; \ > + } \ > +} Don't like this construct and it seems unnecessary. wait_event() and/or friends can probably do the trick. The exp/condition usage in wait_event() is also bit more intuitive. > /* osl multi-precedence packet queue */ > #define PKTQ_LEN_DEFAULT 128 /* Max 128 packets */ > #define PKTQ_MAX_PREC 16 /* Maximum precedence levels */ > diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h > index 60b94b944e9f1..fe1cb2aeaef38 100644 > --- a/include/linux/bcma/bcma.h > +++ b/include/linux/bcma/bcma.h > @@ -154,6 +154,7 @@ struct bcma_host_ops { > #define BCMA_CORE_USB30_DEV 0x83D > #define BCMA_CORE_ARM_CR4 0x83E > #define BCMA_CORE_GCI 0x840 > +#define BCMA_CORE_SR 0x841 > #define BCMA_CORE_CMEM 0x846 /* CNDS DDR2/3 memory controller */ > #define BCMA_CORE_ARM_CA7 0x847 > #define BCMA_CORE_SYS_MEM 0x849 > diff --git a/include/linux/mmc/sdio_ids.h b/include/linux/mmc/sdio_ids.h > index 7cddfdac2f576..8ba3f25217a21 100644 > --- a/include/linux/mmc/sdio_ids.h > +++ b/include/linux/mmc/sdio_ids.h > @@ -80,6 +80,7 @@ > > #define SDIO_VENDOR_ID_CYPRESS 0x04b4 > #define SDIO_DEVICE_ID_BROADCOM_CYPRESS_43439 0xbd3d > +#define SDIO_DEVICE_ID_CYPRESS_55572 0xbd31 > > #define SDIO_VENDOR_ID_MARVELL 0x02df > #define SDIO_DEVICE_ID_MARVELL_LIBERTAS 0x9103
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c index d35262335eaf7..ae89d73eefb87 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c @@ -46,6 +46,8 @@ #define SDIO_4373_FUNC2_BLOCKSIZE 256 #define SDIO_435X_FUNC2_BLOCKSIZE 256 #define SDIO_4329_FUNC2_BLOCKSIZE 128 +#define SDIO_CYW55572_FUNC2_BLOCKSIZE 256 + /* Maximum milliseconds to wait for F2 to come up */ #define SDIO_WAIT_F2RDY 3000 @@ -917,6 +919,9 @@ int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev) case SDIO_DEVICE_ID_BROADCOM_4329: f2_blksz = SDIO_4329_FUNC2_BLOCKSIZE; break; + case SDIO_DEVICE_ID_CYPRESS_55572: + f2_blksz = SDIO_CYW55572_FUNC2_BLOCKSIZE; + break; default: break; } @@ -996,6 +1001,7 @@ static const struct sdio_device_id brcmf_sdmmc_ids[] = { BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_43752, CYW), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_89359, CYW), CYW_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_43439, CYW), + CYW_SDIO_DEVICE(SDIO_DEVICE_ID_CYPRESS_55572, 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 2ef92ef25517e..c5188a31c9efb 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c @@ -216,6 +216,32 @@ struct sbsocramregs { #define ARMCR4_BSZ_MULT 8192 #define ARMCR4_BLK_1K_MASK 0x200 +/* CYW55572 dedicated space and RAM base */ +#define CYW55572_TCAM_SIZE 0x800 +#define CYW55572_TRXHDR_SIZE 0x2b4 +#define CYW55572_RAM_BASE (0x370000 + \ + CYW55572_TCAM_SIZE + CYW55572_TRXHDR_SIZE) + +#define BRCMF_BLHS_POLL_INTERVAL 10 /* msec */ +#define BRCMF_BLHS_D2H_READY_TIMEOUT 100 /* msec */ +#define BRCMF_BLHS_D2H_TRXHDR_PARSE_DONE_TIMEOUT 50 /* msec */ +#define BRCMF_BLHS_D2H_VALDN_DONE_TIMEOUT 250 /* msec */ + +/* Bootloader handshake flags - dongle to host */ +#define BRCMF_BLHS_D2H_START BIT(0) +#define BRCMF_BLHS_D2H_READY BIT(1) +#define BRCMF_BLHS_D2H_STEADY BIT(2) +#define BRCMF_BLHS_D2H_TRXHDR_PARSE_DONE BIT(3) +#define BRCMF_BLHS_D2H_VALDN_START BIT(4) +#define BRCMF_BLHS_D2H_VALDN_RESULT BIT(5) +#define BRCMF_BLHS_D2H_VALDN_DONE BIT(6) + +/* Bootloader handshake flags - host to dongle */ +#define BRCMF_BLHS_H2D_DL_FW_START BIT(0) +#define BRCMF_BLHS_H2D_DL_FW_DONE BIT(1) +#define BRCMF_BLHS_H2D_DL_NVRAM_DONE BIT(2) +#define BRCMF_BLHS_H2D_BL_RESET_ON_ERROR BIT(3) + struct brcmf_core_priv { struct brcmf_core pub; u32 wrapbase; @@ -501,6 +527,21 @@ char *brcmf_chip_name(u32 id, u32 rev, char *buf, uint len) return buf; } +static bool brcmf_chip_find_coreid(struct brcmf_chip_priv *ci, u16 coreid) +{ + struct brcmf_core_priv *core; + + list_for_each_entry(core, &ci->cores, list) { + brcmf_dbg(TRACE, " core 0x%x:%-2d base 0x%08x wrap 0x%08x\n", + core->pub.id, core->pub.rev, core->pub.base, + core->wrapbase); + if (core->pub.id == coreid) + return true; + } + + return false; +} + static struct brcmf_core *brcmf_chip_add_core(struct brcmf_chip_priv *ci, u16 coreid, u32 base, u32 wrapbase) @@ -745,6 +786,8 @@ static u32 brcmf_chip_tcm_rambase(struct brcmf_chip_priv *ci) return 0x352000; case BRCM_CC_4387_CHIP_ID: return 0x740000; + case CY_CC_55572_CHIP_ID: + return CYW55572_RAM_BASE; default: brcmf_err("unknown chip: %s\n", ci->pub.name); break; @@ -763,6 +806,9 @@ int brcmf_chip_get_raminfo(struct brcmf_chip *pub) if (mem) { mem_core = container_of(mem, struct brcmf_core_priv, pub); ci->pub.ramsize = brcmf_chip_tcm_ramsize(mem_core); + if (ci->pub.chip == CY_CC_55572_CHIP_ID) + ci->pub.ramsize -= (CYW55572_TCAM_SIZE + + CYW55572_TRXHDR_SIZE); ci->pub.rambase = brcmf_chip_tcm_rambase(ci); if (ci->pub.rambase == INVALID_RAMBASE) { brcmf_err("RAM base not provided with ARM CR4 core\n"); @@ -942,7 +988,8 @@ int brcmf_chip_dmp_erom_scan(struct brcmf_chip_priv *ci) /* need core with ports */ if (nmw + nsw == 0 && id != BCMA_CORE_PMU && - id != BCMA_CORE_GCI) + id != BCMA_CORE_GCI && + id != BCMA_CORE_SR) continue; /* try to obtain register address info */ @@ -966,6 +1013,144 @@ u32 brcmf_chip_enum_base(u16 devid) return SI_ENUM_BASE_DEFAULT; } +static void brcmf_blhs_init(struct brcmf_chip *pub) +{ + struct brcmf_chip_priv *chip; + u32 addr; + + chip = container_of(pub, struct brcmf_chip_priv, pub); + addr = pub->blhs->h2d; + pub->blhs->write(chip->ctx, addr, 0); +} + +static int brcmf_blhs_is_bootloader_ready(struct brcmf_chip_priv *chip) +{ + u32 regdata; + u32 addr; + + addr = chip->pub.blhs->d2h; + SPINWAIT_MS((chip->pub.blhs->read(chip->ctx, addr) & + BRCMF_BLHS_D2H_READY) == 0, + BRCMF_BLHS_D2H_READY_TIMEOUT, BRCMF_BLHS_POLL_INTERVAL); + + regdata = chip->pub.blhs->read(chip->ctx, addr); + if (!(regdata & BRCMF_BLHS_D2H_READY)) { + brcmf_err("Timeout waiting for bootloader ready\n"); + return -EPERM; + } + + return 0; +} + +static int brcmf_blhs_prep_fw_download(struct brcmf_chip *pub) +{ + struct brcmf_chip_priv *chip; + u32 addr; + int err; + + /* Host indication for bootloader to start the init */ + brcmf_blhs_init(pub); + + chip = container_of(pub, struct brcmf_chip_priv, pub); + err = brcmf_blhs_is_bootloader_ready(chip); + if (err) + return err; + + /* Host notification about FW download start */ + addr = pub->blhs->h2d; + pub->blhs->write(chip->ctx, addr, BRCMF_BLHS_H2D_DL_FW_START); + + return 0; +} + +static int brcmf_blhs_post_fw_download(struct brcmf_chip *pub) +{ + struct brcmf_chip_priv *chip; + u32 addr; + u32 regdata; + + chip = container_of(pub, struct brcmf_chip_priv, pub); + addr = pub->blhs->h2d; + pub->blhs->write(chip->ctx, addr, BRCMF_BLHS_H2D_DL_FW_DONE); + addr = pub->blhs->d2h; + SPINWAIT_MS((pub->blhs->read(chip->ctx, addr) & + BRCMF_BLHS_D2H_TRXHDR_PARSE_DONE) == 0, + BRCMF_BLHS_D2H_TRXHDR_PARSE_DONE_TIMEOUT, + BRCMF_BLHS_POLL_INTERVAL); + + regdata = pub->blhs->read(chip->ctx, addr); + if (!(regdata & BRCMF_BLHS_D2H_TRXHDR_PARSE_DONE)) { + brcmf_err("TRX header parsing failed\n"); + + /* Host indication for bootloader to get reset on error */ + addr = pub->blhs->h2d; + regdata = pub->blhs->read(chip->ctx, addr); + regdata |= BRCMF_BLHS_H2D_BL_RESET_ON_ERROR; + pub->blhs->write(chip->ctx, addr, regdata); + + return -EPERM; + } + + return 0; +} + +static void brcmf_blhs_post_nvram_download(struct brcmf_chip *pub) +{ + struct brcmf_chip_priv *chip; + u32 addr; + u32 regdata; + + chip = container_of(pub, struct brcmf_chip_priv, pub); + addr = pub->blhs->h2d; + regdata = pub->blhs->read(chip->ctx, addr); + regdata |= BRCMF_BLHS_H2D_DL_NVRAM_DONE; + pub->blhs->write(chip->ctx, addr, regdata); +} + +static int brcmf_blhs_chk_validation(struct brcmf_chip *pub) +{ + struct brcmf_chip_priv *chip; + u32 addr; + u32 regdata; + + chip = container_of(pub, struct brcmf_chip_priv, pub); + addr = pub->blhs->d2h; + SPINWAIT_MS((pub->blhs->read(chip->ctx, addr) & + BRCMF_BLHS_D2H_VALDN_DONE) == 0, + BRCMF_BLHS_D2H_VALDN_DONE_TIMEOUT, + BRCMF_BLHS_POLL_INTERVAL); + + regdata = pub->blhs->read(chip->ctx, addr); + if (!(regdata & BRCMF_BLHS_D2H_VALDN_DONE) || + !(regdata & BRCMF_BLHS_D2H_VALDN_RESULT)) { + brcmf_err("TRX image validation check failed\n"); + + /* Host notification for bootloader to get reset on error */ + addr = pub->blhs->h2d; + regdata = pub->blhs->read(chip->ctx, addr); + regdata |= BRCMF_BLHS_H2D_BL_RESET_ON_ERROR; + pub->blhs->write(chip->ctx, addr, regdata); + + return -EPERM; + } + + return 0; +} + +static int brcmf_blhs_post_watchdog_reset(struct brcmf_chip *pub) +{ + struct brcmf_chip_priv *chip; + int err; + + /* Host indication for bootloader to start the init */ + brcmf_blhs_init(pub); + + chip = container_of(pub, struct brcmf_chip_priv, pub); + err = brcmf_blhs_is_bootloader_ready(chip); + + return err; +} + static int brcmf_chip_recognition(struct brcmf_chip_priv *ci) { struct brcmf_core *core; @@ -1123,6 +1308,7 @@ struct brcmf_chip *brcmf_chip_attach(void *ctx, u16 devid, const struct brcmf_buscore_ops *ops) { struct brcmf_chip_priv *chip; + struct brcmf_blhs *blhs; int err = 0; if (WARN_ON(!ops->read32)) @@ -1150,6 +1336,26 @@ struct brcmf_chip *brcmf_chip_attach(void *ctx, u16 devid, if (err < 0) goto fail; + blhs = NULL; + if (chip->ops->blhs_attach) { + err = chip->ops->blhs_attach(chip->ctx, &blhs, + BRCMF_BLHS_D2H_READY, + BRCMF_BLHS_D2H_READY_TIMEOUT, + BRCMF_BLHS_POLL_INTERVAL); + if (err < 0) + goto fail; + + if (blhs) { + blhs->init = brcmf_blhs_init; + blhs->prep_fwdl = brcmf_blhs_prep_fw_download; + blhs->post_fwdl = brcmf_blhs_post_fw_download; + blhs->post_nvramdl = brcmf_blhs_post_nvram_download; + blhs->chk_validation = brcmf_blhs_chk_validation; + blhs->post_wdreset = brcmf_blhs_post_watchdog_reset; + } + } + chip->pub.blhs = blhs; + err = brcmf_chip_recognition(chip); if (err < 0) goto fail; @@ -1176,6 +1382,7 @@ void brcmf_chip_detach(struct brcmf_chip *pub) list_del(&core->list); kfree(core); } + kfree(pub->blhs); kfree(chip); } @@ -1309,7 +1516,8 @@ brcmf_chip_cr4_set_passive(struct brcmf_chip_priv *chip) int i; struct brcmf_core *core; - brcmf_chip_disable_arm(chip, BCMA_CORE_ARM_CR4); + if (!chip->pub.blhs) + brcmf_chip_disable_arm(chip, BCMA_CORE_ARM_CR4); /* Disable the cores only and let the firmware enable them. * Releasing reset ourselves breaks BCM4387 in weird ways. @@ -1456,6 +1664,8 @@ bool brcmf_chip_sr_capable(struct brcmf_chip *pub) reg = chip->ops->read32(chip->ctx, addr); return (reg & (PMU_RCTL_MACPHY_DISABLE_MASK | PMU_RCTL_LOGIC_DISABLE_MASK)) == 0; + case CY_CC_55572_CHIP_ID: + return brcmf_chip_find_coreid(chip, BCMA_CORE_SR); default: addr = CORE_CC_REG(pmu->base, pmucapabilities_ext); reg = chip->ops->read32(chip->ctx, addr); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h index d69f101f58344..0a00fb9d7632e 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h @@ -10,6 +10,8 @@ #define CORE_CC_REG(base, field) \ (base + offsetof(struct chipcregs, field)) +struct brcmf_blhs; + /** * struct brcmf_chip - chip level information. * @@ -24,6 +26,7 @@ * @ramsize: amount of RAM on chip including retention. * @srsize: amount of retention RAM on chip. * @name: string representation of the chip identifier. + * @blhs: bootlooder handshake handle. */ struct brcmf_chip { u32 chip; @@ -37,6 +40,7 @@ struct brcmf_chip { u32 ramsize; u32 srsize; char name[12]; + struct brcmf_blhs *blhs; }; /** @@ -61,6 +65,7 @@ struct brcmf_core { * @setup: bus-specific core setup. * @active: chip becomes active. * The callback should use the provided @rstvec when non-zero. + * @blhs_attach: attach bootloader handshake handle */ struct brcmf_buscore_ops { u32 (*read32)(void *ctx, u32 addr); @@ -69,6 +74,35 @@ struct brcmf_buscore_ops { int (*reset)(void *ctx, struct brcmf_chip *chip); int (*setup)(void *ctx, struct brcmf_chip *chip); void (*activate)(void *ctx, struct brcmf_chip *chip, u32 rstvec); + int (*blhs_attach)(void *ctx, struct brcmf_blhs **blhs, u32 flag, + uint timeout, uint interval); +}; + +/** + * struct brcmf_blhs - bootloader handshake handle related information. + * + * @d2h: offset of dongle to host register for the handshake. + * @h2d: offset of host to dongle register for the handshake. + * @init: bootloader handshake initialization. + * @prep_fwdl: handshake before firmware download. + * @post_fwdl: handshake after firmware download. + * @post_nvramdl: handshake after nvram download. + * @chk_validation: handshake for firmware validation check. + * @post_wdreset: handshake after watchdog reset. + * @read: read value with register offset for the handshake. + * @write: write value with register offset for the handshake. + */ +struct brcmf_blhs { + u32 d2h; + u32 h2d; + void (*init)(struct brcmf_chip *pub); + int (*prep_fwdl)(struct brcmf_chip *pub); + int (*post_fwdl)(struct brcmf_chip *pub); + void (*post_nvramdl)(struct brcmf_chip *pub); + int (*chk_validation)(struct brcmf_chip *pub); + int (*post_wdreset)(struct brcmf_chip *pub); + u32 (*read)(void *ctx, u32 addr); + void (*write)(void *ctx, u32 addr, u32 value); }; int brcmf_chip_get_raminfo(struct brcmf_chip *pub); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c index 83f8ed7d00f96..1d5be3ce51ccf 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c @@ -527,7 +527,8 @@ static void brcmf_fw_free_request(struct brcmf_fw_request *req) int i; for (i = 0, item = &req->items[0]; i < req->n_items; i++, item++) { - if (item->type == BRCMF_FW_TYPE_BINARY) + if (item->type == BRCMF_FW_TYPE_BINARY || + item->type == BRCMF_FW_TYPE_TRXSE) release_firmware(item->binary); else if (item->type == BRCMF_FW_TYPE_NVRAM) brcmf_fw_nvram_free(item->nv_data.data); @@ -599,6 +600,7 @@ static int brcmf_fw_complete_request(const struct firmware *fw, ret = brcmf_fw_request_nvram_done(fw, fwctx); break; case BRCMF_FW_TYPE_BINARY: + case BRCMF_FW_TYPE_TRXSE: if (fw) cur->binary = fw; else @@ -672,8 +674,19 @@ static int brcmf_fw_request_firmware(const struct firmware **fw, static void brcmf_fw_request_done(const struct firmware *fw, void *ctx) { struct brcmf_fw *fwctx = ctx; + struct brcmf_fw_item *cur = &fwctx->req->items[fwctx->curpos]; + char alt_path[BRCMF_FW_NAME_LEN]; int ret; + if (!fw && cur->type == BRCMF_FW_TYPE_TRXSE) { + strscpy(alt_path, cur->path, BRCMF_FW_NAME_LEN); + /* strip 'se' from .trxse at the end */ + alt_path[strlen(alt_path) - 2] = 0; + ret = request_firmware(&fw, alt_path, fwctx->dev); + if (!ret) + cur->path = alt_path; + } + ret = brcmf_fw_complete_request(fw, fwctx); while (ret == 0 && ++fwctx->curpos < fwctx->req->n_items) { diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h index 4002d326fd21b..ab709babd649a 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h @@ -41,6 +41,11 @@ static const char BRCM_ ## fw_name ## _FIRMWARE_BASENAME[] = \ MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH fw_base ".bin"); \ MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH fw_base ".clm_blob") +#define CY_FW_TRXSE_DEF(fw_name, fw_base) \ +static const char BRCM_ ## fw_name ## _FIRMWARE_BASENAME[] = \ + BRCMF_FW_DEFAULT_PATH fw_base; \ +MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH fw_base ".trxse") + #define BRCMF_FW_ENTRY(chipid, mask, name) \ { chipid, mask, BRCM_ ## name ## _FIRMWARE_BASENAME } @@ -48,7 +53,8 @@ void brcmf_fw_nvram_free(void *nvram); enum brcmf_fw_type { BRCMF_FW_TYPE_BINARY, - BRCMF_FW_TYPE_NVRAM + BRCMF_FW_TYPE_NVRAM, + BRCMF_FW_TYPE_TRXSE }; struct brcmf_fw_item { diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c index 058a742d17eda..15b045ab477ca 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c @@ -71,6 +71,7 @@ BRCMF_FW_CLM_DEF(4377B3, "brcmfmac4377b3-pcie"); BRCMF_FW_CLM_DEF(4378B1, "brcmfmac4378b1-pcie"); BRCMF_FW_CLM_DEF(4378B3, "brcmfmac4378b3-pcie"); BRCMF_FW_CLM_DEF(4387C2, "brcmfmac4387c2-pcie"); +CY_FW_TRXSE_DEF(55572, "cyfmac55572-pcie"); /* firmware config files */ MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-pcie.txt"); @@ -109,6 +110,7 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { BRCMF_FW_ENTRY(BRCM_CC_4378_CHIP_ID, 0x0000000F, 4378B1), /* revision ID 3 */ BRCMF_FW_ENTRY(BRCM_CC_4378_CHIP_ID, 0xFFFFFFE0, 4378B3), /* revision ID 5 */ BRCMF_FW_ENTRY(BRCM_CC_4387_CHIP_ID, 0xFFFFFFFF, 4387C2), /* revision ID 7 */ + BRCMF_FW_ENTRY(CY_CC_55572_CHIP_ID, 0xFFFFFFFF, 55572), }; #define BRCMF_PCIE_FW_UP_TIMEOUT 5000 /* msec */ @@ -121,7 +123,8 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { #define BRCMF_PCIE_BAR0_WRAPPERBASE 0x70 #define BRCMF_PCIE_BAR0_WRAPBASE_DMP_OFFSET 0x1000 -#define BRCMF_PCIE_BARO_PCIE_ENUM_OFFSET 0x2000 +#define BRCMF_PCIE_BAR0_PCIE_ENUM_OFFSET 0x2000 +#define BRCMF_CYW55572_PCIE_BAR0_PCIE_ENUM_OFFSET 0x3000 #define BRCMF_PCIE_ARMCR4REG_BANKIDX 0x40 #define BRCMF_PCIE_ARMCR4REG_BANKPDA 0x4C @@ -139,6 +142,8 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { #define BRCMF_PCIE_PCIE2REG_CONFIGDATA 0x124 #define BRCMF_PCIE_PCIE2REG_H2D_MAILBOX_0 0x140 #define BRCMF_PCIE_PCIE2REG_H2D_MAILBOX_1 0x144 +#define BRCMF_PCIE_PCIE2REG_DAR_D2H_MSG_0 0xA80 +#define BRCMF_PCIE_PCIE2REG_DAR_H2D_MSG_0 0xA90 #define BRCMF_PCIE_64_PCIE2REG_INTMASK 0xC14 #define BRCMF_PCIE_64_PCIE2REG_MAILBOXINT 0xC30 @@ -271,18 +276,32 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { #define BRCMF_PCIE_CFGREG_MSI_ADDR_L 0x5C #define BRCMF_PCIE_CFGREG_MSI_ADDR_H 0x60 #define BRCMF_PCIE_CFGREG_MSI_DATA 0x64 +#define BRCMF_PCIE_CFGREG_REVID 0x6C #define BRCMF_PCIE_CFGREG_LINK_STATUS_CTRL 0xBC #define BRCMF_PCIE_CFGREG_LINK_STATUS_CTRL2 0xDC #define BRCMF_PCIE_CFGREG_RBAR_CTRL 0x228 #define BRCMF_PCIE_CFGREG_PML1_SUB_CTRL1 0x248 #define BRCMF_PCIE_CFGREG_REG_BAR2_CONFIG 0x4E0 #define BRCMF_PCIE_CFGREG_REG_BAR3_CONFIG 0x4F4 +#define BRCMF_PCIE_CFGREG_REVID_SECURE_MODE BIT(31) #define BRCMF_PCIE_LINK_STATUS_CTRL_ASPM_ENAB 3 /* Magic number at a magic location to find RAM size */ #define BRCMF_RAMSIZE_MAGIC 0x534d4152 /* SMAR */ #define BRCMF_RAMSIZE_OFFSET 0x6c +#define BRCMF_ENTROPY_SEED_LEN 64u +#define BRCMF_ENTROPY_NONCE_LEN 16u +#define BRCMF_ENTROPY_HOST_LEN (BRCMF_ENTROPY_SEED_LEN + \ + BRCMF_ENTROPY_NONCE_LEN) +#define BRCMF_NVRAM_OFFSET_TCM 4u +#define BRCMF_NVRAM_COMPRS_FACTOR 4u +#define BRCMF_NVRAM_RNG_SIGNATURE 0xFEEDC0DEu + +struct brcmf_rand_metadata { + __le32 signature; + __le32 count; +}; struct brcmf_pcie_console { u32 base_addr; @@ -679,9 +698,15 @@ static void brcmf_pcie_reset_device(struct brcmf_pciedev_info *devinfo) val); /* Watchdog reset */ + if (devinfo->ci->blhs) + devinfo->ci->blhs->init(devinfo->ci); brcmf_pcie_select_core(devinfo, BCMA_CORE_CHIPCOMMON); WRITECC32(devinfo, watchdog, 4); msleep(100); + if (devinfo->ci->blhs) + if (devinfo->ci->blhs->post_wdreset(devinfo->ci)) + return; + /* Restore ASPM */ brcmf_pcie_select_core(devinfo, BCMA_CORE_PCIE2); @@ -722,6 +747,9 @@ static void brcmf_pcie_attach(struct brcmf_pciedev_info *devinfo) static int brcmf_pcie_enter_download_state(struct brcmf_pciedev_info *devinfo) { + struct brcmf_bus *bus = dev_get_drvdata(&devinfo->pdev->dev); + int err = 0; + if (devinfo->ci->chip == BRCM_CC_43602_CHIP_ID) { brcmf_pcie_select_core(devinfo, BCMA_CORE_ARM_CR4); brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_ARMCR4REG_BANKIDX, @@ -733,7 +761,14 @@ static int brcmf_pcie_enter_download_state(struct brcmf_pciedev_info *devinfo) brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_ARMCR4REG_BANKPDA, 0); } - return 0; + + if (devinfo->ci->blhs) { + err = devinfo->ci->blhs->prep_fwdl(devinfo->ci); + if (err) + brcmf_err(bus, "FW download preparation failed"); + } + + return err; } @@ -747,8 +782,13 @@ static int brcmf_pcie_exit_download_state(struct brcmf_pciedev_info *devinfo, brcmf_chip_resetcore(core, 0, 0, 0); } - if (!brcmf_chip_set_active(devinfo->ci, resetintr)) - return -EIO; + if (devinfo->ci->blhs) { + devinfo->ci->blhs->post_nvramdl(devinfo->ci); + } else { + if (!brcmf_chip_set_active(devinfo->ci, resetintr)) + return -EIO; + } + return 0; } @@ -1608,6 +1648,27 @@ brcmf_pcie_adjust_ramsize(struct brcmf_pciedev_info *devinfo, u8 *data, } +static void +brcmf_pcie_write_rand(struct brcmf_pciedev_info *devinfo, u32 nvram_csm) +{ + struct brcmf_rand_metadata rand_data; + u8 rand_buf[BRCMF_ENTROPY_HOST_LEN]; + u32 count = BRCMF_ENTROPY_HOST_LEN; + u32 address; + + address = devinfo->ci->rambase + + (devinfo->ci->ramsize - BRCMF_NVRAM_OFFSET_TCM) - + ((nvram_csm & 0xffff) * BRCMF_NVRAM_COMPRS_FACTOR) - + sizeof(rand_data); + memset(rand_buf, 0, BRCMF_ENTROPY_HOST_LEN); + rand_data.signature = cpu_to_le32(BRCMF_NVRAM_RNG_SIGNATURE); + rand_data.count = cpu_to_le32(count); + memcpy_toio(devinfo->tcm + address, &rand_data, sizeof(rand_data)); + address -= count; + get_random_bytes(rand_buf, count); + memcpy_toio(devinfo->tcm + address, rand_buf, count); +} + static int brcmf_pcie_init_share_ram_info(struct brcmf_pciedev_info *devinfo, u32 sharedram_addr) @@ -1693,6 +1754,8 @@ static int brcmf_pcie_download_fw_nvram(struct brcmf_pciedev_info *devinfo, int err; u32 address; u32 resetintr; + u32 nvram_lenw; + u32 nvram_csm; brcmf_dbg(PCIE, "Halt ARM.\n"); err = brcmf_pcie_enter_download_state(devinfo); @@ -1711,16 +1774,40 @@ static int brcmf_pcie_download_fw_nvram(struct brcmf_pciedev_info *devinfo, resetintr = get_unaligned_le32(fw->data); release_firmware(fw); - /* reset last 4 bytes of RAM address. to be used for shared - * area. This identifies when FW is running - */ - brcmf_pcie_write_ram32(devinfo, devinfo->ci->ramsize - 4, 0); + if (devinfo->ci->blhs) { + err = devinfo->ci->blhs->post_fwdl(devinfo->ci); + if (err) { + brcmf_err(bus, "FW download failed, err=%d\n", err); + return err; + } + + err = devinfo->ci->blhs->chk_validation(devinfo->ci); + if (err) { + brcmf_err(bus, "FW valication failed, err=%d\n", err); + return err; + } + } else { + /* reset last 4 bytes of RAM address. to be used for shared + * area. This identifies when FW is running + */ + brcmf_pcie_write_ram32(devinfo, devinfo->ci->ramsize - 4, 0); + } if (nvram) { brcmf_dbg(PCIE, "Download NVRAM %s\n", devinfo->nvram_name); address = devinfo->ci->rambase + devinfo->ci->ramsize - nvram_len; + + if (devinfo->ci->blhs) + address -= 4; memcpy_toio(devinfo->tcm + address, nvram, nvram_len); + + /* Convert nvram_len to words to determine the length token */ + nvram_lenw = nvram_len / 4; + /* subtract word used to store the token itself on non-blhs devices */ + if (!devinfo->ci->blhs) + nvram_lenw -= 1; + nvram_csm = (~nvram_lenw << 16) | (nvram_lenw & 0x0000FFFF); brcmf_fw_nvram_free(nvram); if (devinfo->otp.valid) { @@ -1743,10 +1830,20 @@ static int brcmf_pcie_download_fw_nvram(struct brcmf_pciedev_info *devinfo, brcmf_pcie_provide_random_bytes(devinfo, address); } } else { + nvram_csm = 0; brcmf_dbg(PCIE, "No matching NVRAM file found %s\n", devinfo->nvram_name); } + if (devinfo->ci->chip == CY_CC_55572_CHIP_ID) { + /* Write the length token to the last word of RAM address */ + brcmf_pcie_write_ram32(devinfo, devinfo->ci->ramsize - 4, + (u32)cpu_to_le32(nvram_csm)); + + /* Write random numbers to TCM for randomizing heap address */ + brcmf_pcie_write_rand(devinfo, nvram_csm); + } + sharedram_addr_written = brcmf_pcie_read_ram32(devinfo, devinfo->ci->ramsize - 4); @@ -1837,6 +1934,21 @@ static void brcmf_pcie_release_resource(struct brcmf_pciedev_info *devinfo) pci_disable_device(devinfo->pdev); } +static u32 brcmf_pcie_buscore_blhs_read(void *ctx, u32 reg_offset) +{ + struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)ctx; + + brcmf_pcie_select_core(devinfo, BCMA_CORE_PCIE2); + return brcmf_pcie_read_reg32(devinfo, reg_offset); +} + +static void brcmf_pcie_buscore_blhs_write(void *ctx, u32 reg_offset, u32 value) +{ + struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)ctx; + + brcmf_pcie_select_core(devinfo, BCMA_CORE_PCIE2); + brcmf_pcie_write_reg32(devinfo, reg_offset, value); +} static u32 brcmf_pcie_buscore_prep_addr(const struct pci_dev *pdev, u32 addr) { @@ -1907,12 +2019,63 @@ static void brcmf_pcie_buscore_activate(void *ctx, struct brcmf_chip *chip, } +static int brcmf_pcie_buscore_blhs_attach(void *ctx, struct brcmf_blhs **blhs, + u32 flag, uint timeout, uint interval) +{ + struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)ctx; + struct brcmf_bus *bus = dev_get_drvdata(&devinfo->pdev->dev); + struct brcmf_blhs *blhsh; + u32 regdata; + u32 pcie_enum; + u32 addr; + + if (devinfo->pdev->vendor != CY_PCIE_VENDOR_ID_CYPRESS) + return 0; + + pci_read_config_dword(devinfo->pdev, BRCMF_PCIE_CFGREG_REVID, ®data); + if (regdata & BRCMF_PCIE_CFGREG_REVID_SECURE_MODE) { + blhsh = kzalloc(sizeof(*blhsh), GFP_KERNEL); + if (!blhsh) + return -ENOMEM; + + blhsh->d2h = BRCMF_PCIE_PCIE2REG_DAR_D2H_MSG_0; + blhsh->h2d = BRCMF_PCIE_PCIE2REG_DAR_H2D_MSG_0; + blhsh->read = brcmf_pcie_buscore_blhs_read; + blhsh->write = brcmf_pcie_buscore_blhs_write; + + /* Host indication for bootloarder to start the init */ + if (devinfo->pdev->device == CY_PCIE_55572_DEVICE_ID) + pcie_enum = BRCMF_CYW55572_PCIE_BAR0_PCIE_ENUM_OFFSET; + else + pcie_enum = BRCMF_PCIE_BAR0_PCIE_ENUM_OFFSET; + + pci_read_config_dword(devinfo->pdev, PCI_BASE_ADDRESS_0, + ®data); + addr = regdata + pcie_enum + blhsh->h2d; + brcmf_pcie_buscore_write32(ctx, addr, 0); + + addr = regdata + pcie_enum + blhsh->d2h; + SPINWAIT_MS((brcmf_pcie_buscore_read32(ctx, addr) & flag) == 0, + timeout, interval); + regdata = brcmf_pcie_buscore_read32(ctx, addr); + if (!(regdata & flag)) { + brcmf_err(bus, "Timeout waiting for bootloader ready\n"); + kfree(blhsh); + return -EPERM; + } + *blhs = blhsh; + } + + return 0; +} + static const struct brcmf_buscore_ops brcmf_pcie_buscore_ops = { .prepare = brcmf_pcie_buscoreprep, .reset = brcmf_pcie_buscore_reset, .activate = brcmf_pcie_buscore_activate, .read32 = brcmf_pcie_buscore_read32, .write32 = brcmf_pcie_buscore_write32, + .blhs_attach = brcmf_pcie_buscore_blhs_attach, }; #define BRCMF_OTP_SYS_VENDOR 0x15 @@ -2243,6 +2406,9 @@ brcmf_pcie_prepare_fw_request(struct brcmf_pciedev_info *devinfo) { ".txcap_blob", devinfo->txcap_name }, }; + if (devinfo->ci->blhs) + fwnames[BRCMF_PCIE_FW_CODE].extension = ".trxse"; + fwreq = brcmf_fw_alloc_request(devinfo->ci->chip, devinfo->ci->chiprev, brcmf_pcie_fwnames, ARRAY_SIZE(brcmf_pcie_fwnames), @@ -2250,7 +2416,10 @@ brcmf_pcie_prepare_fw_request(struct brcmf_pciedev_info *devinfo) if (!fwreq) return NULL; - fwreq->items[BRCMF_PCIE_FW_CODE].type = BRCMF_FW_TYPE_BINARY; + if (devinfo->ci->blhs) + fwreq->items[BRCMF_PCIE_FW_CODE].type = BRCMF_FW_TYPE_TRXSE; + else + fwreq->items[BRCMF_PCIE_FW_CODE].type = BRCMF_FW_TYPE_BINARY; fwreq->items[BRCMF_PCIE_FW_NVRAM].type = BRCMF_FW_TYPE_NVRAM; fwreq->items[BRCMF_PCIE_FW_NVRAM].flags = BRCMF_FW_REQF_OPTIONAL; fwreq->items[BRCMF_PCIE_FW_CLM].type = BRCMF_FW_TYPE_BINARY; @@ -2678,6 +2847,9 @@ static const struct dev_pm_ops brcmf_pciedrvr_pm = { BRCMF_FWVENDOR_ ## fw_vend \ } +#define BRCMF_PCIE_DEVICE_CY(dev_id) { CY_PCIE_VENDOR_ID_CYPRESS, dev_id,\ + PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_OTHER << 8, 0xffff00, 0 } + static const struct pci_device_id brcmf_pcie_devid_table[] = { BRCMF_PCIE_DEVICE(BRCM_PCIE_4350_DEVICE_ID, WCC), BRCMF_PCIE_DEVICE_SUB(0x4355, BRCM_PCIE_VENDOR_ID_BROADCOM, 0x4355, WCC), @@ -2706,7 +2878,7 @@ static const struct pci_device_id brcmf_pcie_devid_table[] = { BRCMF_PCIE_DEVICE(BRCM_PCIE_4377_DEVICE_ID, WCC), BRCMF_PCIE_DEVICE(BRCM_PCIE_4378_DEVICE_ID, WCC), BRCMF_PCIE_DEVICE(BRCM_PCIE_4387_DEVICE_ID, WCC), - + BRCMF_PCIE_DEVICE_CY(CY_PCIE_55572_DEVICE_ID), { /* end: all zeroes */ } }; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index 08881e366cae2..3bb03de1c2d29 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -59,6 +59,10 @@ #define CY_435X_F2_WATERMARK 0x40 #define CY_435X_F1_MESBUSYCTRL (CY_435X_F2_WATERMARK | \ SBSDIO_MESBUSYCTRL_ENAB) +#define CYW55572_F2_WATERMARK 0x40 +#define CYW55572_MES_WATERMARK 0x40 +#define CYW55572_F1_MESBUSYCTRL (CYW55572_MES_WATERMARK | \ + SBSDIO_MESBUSYCTRL_ENAB) #ifdef DEBUG @@ -626,6 +630,7 @@ BRCMF_FW_DEF(4359, "brcmfmac4359-sdio"); BRCMF_FW_CLM_DEF(4373, "brcmfmac4373-sdio"); BRCMF_FW_CLM_DEF(43012, "brcmfmac43012-sdio"); BRCMF_FW_CLM_DEF(43752, "brcmfmac43752-sdio"); +CY_FW_TRXSE_DEF(55572, "cyfmac55572-sdio"); /* firmware config files */ MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-sdio.*.txt"); @@ -658,7 +663,8 @@ static const struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = { BRCMF_FW_ENTRY(CY_CC_4373_CHIP_ID, 0xFFFFFFFF, 4373), 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_43752_CHIP_ID, 0xFFFFFFFF, 43752), + BRCMF_FW_ENTRY(CY_CC_55572_CHIP_ID, 0xFFFFFFFF, 55572) }; #define TXCTL_CREDITS 2 @@ -719,7 +725,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_55572_CHIP_ID)) return err; if (on) { @@ -3435,7 +3442,8 @@ static int brcmf_sdio_download_firmware(struct brcmf_sdio *bus, 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_43752_CHIP_ID || + bus->ci->chip == CY_CC_55572_CHIP_ID) return true; else return false; @@ -4352,6 +4360,19 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err, brcmf_sdiod_writeb(sdiod, SBSDIO_FUNC1_MESBUSYCTRL, CY_435X_F1_MESBUSYCTRL, &err); break; + case SDIO_DEVICE_ID_CYPRESS_55572: + brcmf_dbg(INFO, "set F2 watermark to 0x%x*4 bytes\n", + CYW55572_F2_WATERMARK); + brcmf_sdiod_writeb(sdiod, SBSDIO_WATERMARK, + CYW55572_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, + CYW55572_F1_MESBUSYCTRL, &err); + break; default: brcmf_sdiod_writeb(sdiod, SBSDIO_WATERMARK, DEFAULT_F2_WATERMARK, &err); diff --git a/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h b/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h index 44684bf1b9acc..fc1757c505312 100644 --- a/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h +++ b/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h @@ -14,6 +14,7 @@ #define BRCM_USB_VENDOR_ID_LINKSYS 0x13b1 #define CY_USB_VENDOR_ID_CYPRESS 0x04b4 #define BRCM_PCIE_VENDOR_ID_BROADCOM PCI_VENDOR_ID_BROADCOM +#define CY_PCIE_VENDOR_ID_CYPRESS 0x12be /* Chipcommon Core Chip IDs */ #define BRCM_CC_43143_CHIP_ID 43143 @@ -59,6 +60,7 @@ #define CY_CC_43012_CHIP_ID 43012 #define CY_CC_43439_CHIP_ID 43439 #define CY_CC_43752_CHIP_ID 43752 +#define CY_CC_55572_CHIP_ID 0xd908 /* USB Device IDs */ #define BRCM_USB_43143_DEVICE_ID 0xbd1e @@ -97,6 +99,7 @@ #define BRCM_PCIE_4377_DEVICE_ID 0x4488 #define BRCM_PCIE_4378_DEVICE_ID 0x4425 #define BRCM_PCIE_4387_DEVICE_ID 0x4433 +#define CY_PCIE_55572_DEVICE_ID 0xbd31 /* brcmsmac IDs */ #define BCM4313_D11N2G_ID 0x4727 /* 4313 802.11n 2.4G device */ diff --git a/drivers/net/wireless/broadcom/brcm80211/include/brcmu_utils.h b/drivers/net/wireless/broadcom/brcm80211/include/brcmu_utils.h index 9465323286673..48791ac87496d 100644 --- a/drivers/net/wireless/broadcom/brcm80211/include/brcmu_utils.h +++ b/drivers/net/wireless/broadcom/brcm80211/include/brcmu_utils.h @@ -21,6 +21,19 @@ } \ } +/* Spin at most 'ms' milliseconds with polling interval 'interval' milliseconds + * while 'exp' is true. Caller should explicitly test 'exp' when this completes + * and take appropriate error action if 'exp' is still true. + */ +#define SPINWAIT_MS(exp, ms, interval) { \ + typeof(interval) interval_ = (interval); \ + uint countdown = (ms) + (interval_ - 1U); \ + while ((exp) && (countdown >= interval_)) { \ + msleep(interval_); \ + countdown -= interval_; \ + } \ +} + /* osl multi-precedence packet queue */ #define PKTQ_LEN_DEFAULT 128 /* Max 128 packets */ #define PKTQ_MAX_PREC 16 /* Maximum precedence levels */ diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h index 60b94b944e9f1..fe1cb2aeaef38 100644 --- a/include/linux/bcma/bcma.h +++ b/include/linux/bcma/bcma.h @@ -154,6 +154,7 @@ struct bcma_host_ops { #define BCMA_CORE_USB30_DEV 0x83D #define BCMA_CORE_ARM_CR4 0x83E #define BCMA_CORE_GCI 0x840 +#define BCMA_CORE_SR 0x841 #define BCMA_CORE_CMEM 0x846 /* CNDS DDR2/3 memory controller */ #define BCMA_CORE_ARM_CA7 0x847 #define BCMA_CORE_SYS_MEM 0x849 diff --git a/include/linux/mmc/sdio_ids.h b/include/linux/mmc/sdio_ids.h index 7cddfdac2f576..8ba3f25217a21 100644 --- a/include/linux/mmc/sdio_ids.h +++ b/include/linux/mmc/sdio_ids.h @@ -80,6 +80,7 @@ #define SDIO_VENDOR_ID_CYPRESS 0x04b4 #define SDIO_DEVICE_ID_BROADCOM_CYPRESS_43439 0xbd3d +#define SDIO_DEVICE_ID_CYPRESS_55572 0xbd31 #define SDIO_VENDOR_ID_MARVELL 0x02df #define SDIO_DEVICE_ID_MARVELL_LIBERTAS 0x9103