From 02ad06fbf2b35916ee329a9bb80d73840d6e2973 Mon Sep 17 00:00:00 2001 From: Stan Skowronek Date: Sat, 30 Jan 2021 18:23:20 -0500 Subject: [PATCH] brcmfmac: Add support for BCM4378 on Apple hardware (with their special OTP). Signed-off-by: Stan Skowronek --- .../broadcom/brcm80211/brcmfmac/cfg80211.c | 7 +- .../broadcom/brcm80211/brcmfmac/chip.c | 4 + .../broadcom/brcm80211/brcmfmac/common.c | 37 +-- .../broadcom/brcm80211/brcmfmac/common.h | 23 +- .../broadcom/brcm80211/brcmfmac/firmware.c | 38 ++- .../broadcom/brcm80211/brcmfmac/p2p.c | 14 +- .../broadcom/brcm80211/brcmfmac/pcie.c | 286 ++++++++++++++++-- .../broadcom/brcm80211/include/brcm_hw_ids.h | 2 + 8 files changed, 344 insertions(+), 67 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 0ee421f30aa249..8f7db434de1118 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -5136,8 +5136,13 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN; ie_len = len - ie_offset; - if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif) + if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif) { vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif; + if (vif == NULL) { + bphy_err(drvr, "No p2p device available for probe response\n"); + return -ENODEV; + } + } err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBRSP_FLAG, &buf[ie_offset], diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c index 5bf11e46fc49a9..4058edddbdc23a 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c @@ -726,6 +726,8 @@ static u32 brcmf_chip_tcm_rambase(struct brcmf_chip_priv *ci) case BRCM_CC_4364_CHIP_ID: case CY_CC_4373_CHIP_ID: return 0x160000; + case BRCM_CC_4378_CHIP_ID: + return 0x352000; default: brcmf_err("unknown chip: %s\n", ci->pub.name); break; @@ -1425,5 +1427,7 @@ 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 BRCM_CC_4378_CHIP_ID: + return false; } } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c index e3758bd86acf0c..4b91a04afdc345 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c @@ -50,11 +50,24 @@ static int brcmf_feature_disable; module_param_named(feature_disable, brcmf_feature_disable, int, 0); MODULE_PARM_DESC(feature_disable, "Disable features"); -static char brcmf_firmware_path[BRCMF_FW_ALTPATH_LEN]; +char brcmf_firmware_path[BRCMF_FW_ALTPATH_LEN]; module_param_string(alternative_fw_path, brcmf_firmware_path, - BRCMF_FW_ALTPATH_LEN, 0400); + BRCMF_FW_ALTPATH_LEN, 0600); MODULE_PARM_DESC(alternative_fw_path, "Alternative firmware path"); +char brcmf_mac_addr[18]; +module_param_string(nvram_mac_addr, brcmf_mac_addr, + 18, 0600); +MODULE_PARM_DESC(nvram_mac_addr, "Set MAC address in NVRAM"); + +char brcmf_otp_chip_id[BRCMF_OTP_VERSION_MAX]; +module_param_string(otp_chip_id, brcmf_otp_chip_id, BRCMF_OTP_VERSION_MAX, 0400); +MODULE_PARM_DESC(otp_chip_id, "Chip ID and revision from OTP"); + +char brcmf_otp_nvram_id[BRCMF_OTP_VERSION_MAX]; +module_param_string(otp_nvram_id, brcmf_otp_nvram_id, BRCMF_OTP_VERSION_MAX, 0400); +MODULE_PARM_DESC(otp_chip_id, "NVRAM variant from OTP"); + static int brcmf_fcmode; module_param_named(fcmode, brcmf_fcmode, int, 0); MODULE_PARM_DESC(fcmode, "Mode of firmware signalled flow control"); @@ -75,7 +88,6 @@ MODULE_PARM_DESC(ignore_probe_fail, "always succeed probe for debugging"); #endif static struct brcmfmac_platform_data *brcmfmac_pdata; -struct brcmf_mp_global_t brcmf_mp_global; void brcmf_c_set_joinpref_default(struct brcmf_if *ifp) { @@ -376,22 +388,6 @@ void __brcmf_dbg(u32 level, const char *func, const char *fmt, ...) } #endif -static void brcmf_mp_attach(void) -{ - /* If module param firmware path is set then this will always be used, - * if not set then if available use the platform data version. To make - * sure it gets initialized at all, always copy the module param version - */ - strlcpy(brcmf_mp_global.firmware_path, brcmf_firmware_path, - BRCMF_FW_ALTPATH_LEN); - if ((brcmfmac_pdata) && (brcmfmac_pdata->fw_alternative_path) && - (brcmf_mp_global.firmware_path[0] == '\0')) { - strlcpy(brcmf_mp_global.firmware_path, - brcmfmac_pdata->fw_alternative_path, - BRCMF_FW_ALTPATH_LEN); - } -} - struct brcmf_mp_device *brcmf_get_module_param(struct device *dev, enum brcmf_bus_type bus_type, u32 chip, u32 chiprev) @@ -492,9 +488,6 @@ static int __init brcmfmac_module_init(void) if (err == -ENODEV) brcmf_dbg(INFO, "No platform data available.\n"); - /* Initialize global module paramaters */ - brcmf_mp_attach(); - /* Continue the initialization by registering the different busses */ err = brcmf_core_init(); if (err) { diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h index 8b5f49997c8b5e..3b6ba43af4d512 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h @@ -10,25 +10,12 @@ #include "fwil_types.h" #define BRCMF_FW_ALTPATH_LEN 256 +#define BRCMF_OTP_VERSION_MAX 64 -/* Definitions for the module global and device specific settings are defined - * here. Two structs are used for them. brcmf_mp_global_t and brcmf_mp_device. - * The mp_global is instantiated once in a global struct and gets initialized - * by the common_attach function which should be called before any other - * (module) initiliazation takes place. The device specific settings is part - * of the drvr struct and should be initialized on every brcmf_attach. - */ - -/** - * struct brcmf_mp_global_t - Global module paramaters. - * - * @firmware_path: Alternative firmware path. - */ -struct brcmf_mp_global_t { - char firmware_path[BRCMF_FW_ALTPATH_LEN]; -}; - -extern struct brcmf_mp_global_t brcmf_mp_global; +extern char brcmf_firmware_path[BRCMF_FW_ALTPATH_LEN]; +extern char brcmf_mac_addr[18]; +extern char brcmf_otp_chip_id[BRCMF_OTP_VERSION_MAX]; +extern char brcmf_otp_nvram_id[BRCMF_OTP_VERSION_MAX]; /** * struct brcmf_mp_device - Device module paramaters. diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c index d821a4758f8cf0..c3a05e254c8511 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c @@ -368,6 +368,35 @@ static void brcmf_fw_add_defaults(struct nvram_parser *nvp) nvp->nvram_len++; } +static void brcmf_fw_set_macaddr(struct nvram_parser *nvp, const char *mac_addr) +{ + uint8_t mac[6] = { 0 }; + size_t len = strlen("macaddr=") + 17 + 1; /* 17 = "aa:bb:cc:dd:ee:ff" */ + unsigned i = 0; + unsigned long res = 0; + char tmp[3]; + + while(mac_addr[0] && mac_addr[1] && i < 6) { + tmp[0] = mac_addr[0]; + tmp[1] = mac_addr[1]; + tmp[2] = 0; + if(kstrtoul(tmp, 16, &res)) + break; + mac[i] = res; + mac_addr += 2; + i ++; + while(*mac_addr == ':' || *mac_addr == ' ' || *mac_addr == '-') + mac_addr ++; + } + if(i < 6) + pr_warn("invalid MAC address supplied for brcmfmac!\n"); + + memmove(&nvp->nvram[len], &nvp->nvram[0], nvp->nvram_len); + nvp->nvram_len += len; + sprintf(&nvp->nvram[0], "macaddr=%02x:%02x:%02x:%02x:%02x:%02x", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); +} + /* brcmf_nvram_strip :Takes a buffer of "=\n" lines read from a fil * and ending in a NUL. Removes carriage returns, empty lines, comment lines, * and converts newlines to NULs. Shortens buffer as needed and pads with NULs. @@ -404,8 +433,11 @@ static void *brcmf_fw_nvram_strip(const u8 *data, size_t data_len, brcmf_fw_add_defaults(&nvp); + if(brcmf_mac_addr[0]) + brcmf_fw_set_macaddr(&nvp, brcmf_mac_addr); + pad = nvp.nvram_len; - *new_length = roundup(nvp.nvram_len + 1, 4); + *new_length = roundup(nvp.nvram_len + 1, 8) + 4; while (pad != *new_length) { nvp.nvram[pad] = 0; pad++; @@ -721,7 +753,7 @@ brcmf_fw_alloc_request(u32 chip, u32 chiprev, brcmf_info("using %s for chip %s\n", mapping_table[i].fw_base, chipname); - mp_path = brcmf_mp_global.firmware_path; + mp_path = brcmf_firmware_path; mp_path_len = strnlen(mp_path, BRCMF_FW_ALTPATH_LEN); if (mp_path_len) end = mp_path[mp_path_len - 1]; @@ -732,7 +764,7 @@ brcmf_fw_alloc_request(u32 chip, u32 chiprev, fwreq->items[j].path = fwnames[j].path; fwnames[j].path[0] = '\0'; /* check if firmware path is provided by module parameter */ - if (brcmf_mp_global.firmware_path[0] != '\0') { + if (brcmf_firmware_path[0] != '\0') { strlcpy(fwnames[j].path, mp_path, BRCMF_FW_NAME_LEN); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c index ec6fc7a150a6ac..1c1d5131c3f367 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c @@ -565,7 +565,8 @@ static s32 brcmf_p2p_deinit_discovery(struct brcmf_p2p_info *p2p) /* Set the discovery state to SCAN */ vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif; - (void)brcmf_p2p_set_discover_state(vif->ifp, WL_P2P_DISC_ST_SCAN, 0, 0); + if (vif != NULL) + (void)brcmf_p2p_set_discover_state(vif->ifp, WL_P2P_DISC_ST_SCAN, 0, 0); /* Disable P2P discovery in the firmware */ vif = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif; @@ -1351,6 +1352,8 @@ brcmf_p2p_gon_req_collision(struct brcmf_p2p_info *p2p, u8 *mac) * if not (sa addr > da addr), * this device will process gon request and drop gon req of peer. */ + if(p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif == NULL) + return false; ifp = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif->ifp; if (memcmp(mac, ifp->mac_addr, ETH_ALEN) < 0) { brcmf_dbg(INFO, "Block transmit gon req !!!\n"); @@ -1559,6 +1562,10 @@ static s32 brcmf_p2p_tx_action_frame(struct brcmf_p2p_info *p2p, else vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif; + if (vif == NULL) { + bphy_err(drvr, " no P2P interface available\n"); + goto exit; + } err = brcmf_fil_bsscfg_data_set(vif->ifp, "actframe", af_params, sizeof(*af_params)); if (err) { @@ -1734,8 +1741,11 @@ bool brcmf_p2p_send_action_frame(struct brcmf_cfg80211_info *cfg, uint delta_ms; unsigned long dwell_jiffies = 0; bool dwell_overflow = false; - u32 requested_dwell = le32_to_cpu(af_params->dwell_time); + + if(p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif == NULL) + goto exit; + action_frame = &af_params->action_frame; action_frame_len = le16_to_cpu(action_frame->len); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c index 45bc502fcb3413..2890b24a34d1d7 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c @@ -4,6 +4,7 @@ */ #include +#include #include #include #include @@ -58,6 +59,7 @@ BRCMF_FW_DEF(4365C, "brcmfmac4365c-pcie"); BRCMF_FW_DEF(4366B, "brcmfmac4366b-pcie"); BRCMF_FW_DEF(4366C, "brcmfmac4366c-pcie"); BRCMF_FW_DEF(4371, "brcmfmac4371-pcie"); +BRCMF_FW_DEF(4378, "brcmfmac4378-pcie"); static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { BRCMF_FW_ENTRY(BRCM_CC_43602_CHIP_ID, 0xFFFFFFFF, 43602), @@ -78,6 +80,7 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { BRCMF_FW_ENTRY(BRCM_CC_4366_CHIP_ID, 0xFFFFFFF0, 4366C), BRCMF_FW_ENTRY(BRCM_CC_43664_CHIP_ID, 0xFFFFFFF0, 4366C), BRCMF_FW_ENTRY(BRCM_CC_4371_CHIP_ID, 0xFFFFFFFF, 4371), + BRCMF_FW_ENTRY(BRCM_CC_4378_CHIP_ID, 0xFFFFFFFF, 4378), }; #define BRCMF_PCIE_FW_UP_TIMEOUT 5000 /* msec */ @@ -109,6 +112,12 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { #define BRCMF_PCIE_PCIE2REG_H2D_MAILBOX_0 0x140 #define BRCMF_PCIE_PCIE2REG_H2D_MAILBOX_1 0x144 +#define BRCMF_PCIE_64_PCIE2REG_INTMASK 0xC14 +#define BRCMF_PCIE_64_PCIE2REG_MAILBOXINT 0xC30 +#define BRCMF_PCIE_64_PCIE2REG_MAILBOXMASK 0xC34 +#define BRCMF_PCIE_64_PCIE2REG_H2D_MAILBOX_0 0xA20 +#define BRCMF_PCIE_64_PCIE2REG_H2D_MAILBOX_1 0xA24 + #define BRCMF_PCIE2_INTA 0x01 #define BRCMF_PCIE2_INTB 0x02 @@ -137,6 +146,40 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { BRCMF_PCIE_MB_INT_D2H3_DB0 | \ BRCMF_PCIE_MB_INT_D2H3_DB1) +#define BRCMF_PCIE_64_MB_INT_D2H0_DB0 1 +#define BRCMF_PCIE_64_MB_INT_D2H0_DB1 2 +#define BRCMF_PCIE_64_MB_INT_D2H1_DB0 4 +#define BRCMF_PCIE_64_MB_INT_D2H1_DB1 8 +#define BRCMF_PCIE_64_MB_INT_D2H2_DB0 0x10 +#define BRCMF_PCIE_64_MB_INT_D2H2_DB1 0x20 +#define BRCMF_PCIE_64_MB_INT_D2H3_DB0 0x40 +#define BRCMF_PCIE_64_MB_INT_D2H3_DB1 0x80 +#define BRCMF_PCIE_64_MB_INT_D2H4_DB0 0x100 +#define BRCMF_PCIE_64_MB_INT_D2H4_DB1 0x200 +#define BRCMF_PCIE_64_MB_INT_D2H5_DB0 0x400 +#define BRCMF_PCIE_64_MB_INT_D2H5_DB1 0x800 +#define BRCMF_PCIE_64_MB_INT_D2H6_DB0 0x1000 +#define BRCMF_PCIE_64_MB_INT_D2H6_DB1 0x2000 +#define BRCMF_PCIE_64_MB_INT_D2H7_DB0 0x4000 +#define BRCMF_PCIE_64_MB_INT_D2H7_DB1 0x8000 + +#define BRCMF_PCIE_64_MB_INT_D2H_DB (BRCMF_PCIE_64_MB_INT_D2H0_DB0 | \ + BRCMF_PCIE_64_MB_INT_D2H0_DB1 | \ + BRCMF_PCIE_64_MB_INT_D2H1_DB0 | \ + BRCMF_PCIE_64_MB_INT_D2H1_DB1 | \ + BRCMF_PCIE_64_MB_INT_D2H2_DB0 | \ + BRCMF_PCIE_64_MB_INT_D2H2_DB1 | \ + BRCMF_PCIE_64_MB_INT_D2H3_DB0 | \ + BRCMF_PCIE_64_MB_INT_D2H3_DB1 | \ + BRCMF_PCIE_64_MB_INT_D2H4_DB0 | \ + BRCMF_PCIE_64_MB_INT_D2H4_DB1 | \ + BRCMF_PCIE_64_MB_INT_D2H5_DB0 | \ + BRCMF_PCIE_64_MB_INT_D2H5_DB1 | \ + BRCMF_PCIE_64_MB_INT_D2H6_DB0 | \ + BRCMF_PCIE_64_MB_INT_D2H6_DB1 | \ + BRCMF_PCIE_64_MB_INT_D2H7_DB0 | \ + BRCMF_PCIE_64_MB_INT_D2H7_DB1) + #define BRCMF_PCIE_SHARED_VERSION_7 7 #define BRCMF_PCIE_MIN_SHARED_VERSION 5 #define BRCMF_PCIE_MAX_SHARED_VERSION BRCMF_PCIE_SHARED_VERSION_7 @@ -351,6 +394,15 @@ brcmf_pcie_read_reg32(struct brcmf_pciedev_info *devinfo, u32 reg_offset) } +static u16 +brcmf_pcie_read_reg16(struct brcmf_pciedev_info *devinfo, u32 reg_offset) +{ + void __iomem *address = devinfo->regs + reg_offset; + + return (ioread16(address)); +} + + static void brcmf_pcie_write_reg32(struct brcmf_pciedev_info *devinfo, u32 reg_offset, u32 value) @@ -528,6 +580,37 @@ brcmf_pcie_copy_dev_tomem(struct brcmf_pciedev_info *devinfo, u32 mem_offset, } +static u32 +brcmf_pcie_reg_map(struct brcmf_pciedev_info *devinfo, u32 reg) +{ + switch(reg) { + case BRCMF_PCIE_PCIE2REG_INTMASK: + if(devinfo->ci->chip == BRCM_CC_4378_CHIP_ID) + return BRCMF_PCIE_64_PCIE2REG_INTMASK; + return reg; + case BRCMF_PCIE_PCIE2REG_MAILBOXINT: + if(devinfo->ci->chip == BRCM_CC_4378_CHIP_ID) + return BRCMF_PCIE_64_PCIE2REG_MAILBOXINT; + return reg; + case BRCMF_PCIE_PCIE2REG_MAILBOXMASK: + if(devinfo->ci->chip == BRCM_CC_4378_CHIP_ID) + return BRCMF_PCIE_64_PCIE2REG_MAILBOXMASK; + return reg; + case BRCMF_PCIE_PCIE2REG_H2D_MAILBOX_0: + if(devinfo->ci->chip == BRCM_CC_4378_CHIP_ID) + return BRCMF_PCIE_64_PCIE2REG_H2D_MAILBOX_0; + return reg; + case BRCMF_PCIE_PCIE2REG_H2D_MAILBOX_1: + if(devinfo->ci->chip == BRCM_CC_4378_CHIP_ID) + return BRCMF_PCIE_64_PCIE2REG_H2D_MAILBOX_1; + return reg; + default: + return reg; + } +} + + + #define WRITECC32(devinfo, reg, value) brcmf_pcie_write_reg32(devinfo, \ CHIPCREGOFFS(reg), value) @@ -543,6 +626,7 @@ brcmf_pcie_select_core(struct brcmf_pciedev_info *devinfo, u16 coreid) core = brcmf_chip_get_core(devinfo->ci, coreid); if (core) { bar0_win = core->base; + pci_write_config_dword(pdev, BRCMF_PCIE_BAR0_WINDOW, bar0_win); if (pci_read_config_dword(pdev, BRCMF_PCIE_BAR0_WINDOW, &bar0_win) == 0) { @@ -615,11 +699,129 @@ static void brcmf_pcie_reset_device(struct brcmf_pciedev_info *devinfo) } } +#define OTP_SIZE 64 +#define OTP_CORE_ID BCMA_CORE_GCI +#define OTP_CC_ADDR_4378 0x1120 + +static void brcmf_pcie_process_otp_tuple(struct brcmf_pciedev_info *devinfo, u8 type, u8 size, u8 *data) +{ + char tmp[OTP_SIZE], t_chiprev[8] = "", t_module[8] = "", t_modrev[8] = "", t_vendor[8] = "", t_chip[8] = ""; + unsigned i, len; + + switch(type) { + case 0x15: /* system vendor OTP */ + if(size < 4) + return; + if(*(u32 *)data != 8) + dev_warn(&devinfo->pdev->dev, "system vendor OTP header unexpected: %d\n", *(u32 *)data); + size -= 4; + data += 4; + while(size) { + if(data[0] == 0xFF) + break; + for(len=0; lenci->chip > 40000) ? "%05d" : "%04x", devinfo->ci->chip); + dev_info(&devinfo->pdev->dev, "module revision data: chip %s, chip rev %s, module %s, module rev %s, vendor %s\n", t_chip, t_chiprev, t_module, t_modrev, t_vendor); + + if(t_chiprev[0]) + sprintf(brcmf_otp_chip_id, "C-%s__s-%s", t_chip, t_chiprev); + else + sprintf(brcmf_otp_chip_id, "C-%s", t_chip); + sprintf(brcmf_otp_nvram_id, "M-%s_V-%s__m-%s", t_module, t_vendor, t_modrev); + + break; + case 0x80: /* Broadcom CIS */ + if(size < 1) + return; + switch(data[0]) { + case 0x83: /* serial number */ + for(i=0; i<16 && ipdev->dev, "module serial number: %s\n", tmp); + break; + } + break; + } +} + +static u32 brcmf_pcie_buscore_prep_addr(const struct pci_dev *pdev, u32 addr); + +static void brcmf_pcie_read_otp(struct brcmf_pciedev_info *devinfo) +{ + u8 otp[OTP_SIZE], type, size; + unsigned i; + struct brcmf_core *core; + u32 base; + + if (devinfo->ci->chip == BRCM_CC_4378_CHIP_ID) { + /* for whatever reason, reading OTP works only once after reset */ + if(brcmf_otp_chip_id[0]) + return; + + core = brcmf_chip_get_core(devinfo->ci, OTP_CORE_ID); + if(!core) { + dev_err(&devinfo->pdev->dev, "can't find core for OTP\n"); + return; + } + base = brcmf_pcie_buscore_prep_addr(devinfo->pdev, core->base + OTP_CC_ADDR_4378); + + for(i=0; ici->chip == BRCM_CC_4378_CHIP_ID) + brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_64_PCIE2REG_MAILBOXMASK, + BRCMF_PCIE_64_MB_INT_D2H_DB); + else + brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXMASK, + BRCMF_PCIE_MB_INT_D2H_DB | + BRCMF_PCIE_MB_INT_FN0_0 | + BRCMF_PCIE_MB_INT_FN0_1); } static void brcmf_pcie_hostready(struct brcmf_pciedev_info *devinfo) { if (devinfo->shared.flags & BRCMF_PCIE_SHARED_HOSTRDY_DB1) brcmf_pcie_write_reg32(devinfo, - BRCMF_PCIE_PCIE2REG_H2D_MAILBOX_1, 1); + brcmf_pcie_reg_map(devinfo, BRCMF_PCIE_PCIE2REG_H2D_MAILBOX_1), 1); } static irqreturn_t brcmf_pcie_quick_check_isr(int irq, void *arg) { struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)arg; - if (brcmf_pcie_read_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT)) { + if (brcmf_pcie_read_reg32(devinfo, brcmf_pcie_reg_map(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT))) { brcmf_pcie_intr_disable(devinfo); brcmf_dbg(PCIE, "Enter\n"); return IRQ_WAKE_THREAD; @@ -844,18 +1050,23 @@ static irqreturn_t brcmf_pcie_quick_check_isr(int irq, void *arg) static irqreturn_t brcmf_pcie_isr_thread(int irq, void *arg) { struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)arg; - u32 status; + u32 status, mask; + + if(devinfo->ci->chip == BRCM_CC_4378_CHIP_ID) + mask = BRCMF_PCIE_64_MB_INT_D2H_DB; + else + mask = BRCMF_PCIE_MB_INT_D2H_DB; devinfo->in_irq = true; - status = brcmf_pcie_read_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT); + status = brcmf_pcie_read_reg32(devinfo, brcmf_pcie_reg_map(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT)); brcmf_dbg(PCIE, "Enter %x\n", status); if (status) { - brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT, + brcmf_pcie_write_reg32(devinfo, brcmf_pcie_reg_map(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT), status); if (status & (BRCMF_PCIE_MB_INT_FN0_0 | BRCMF_PCIE_MB_INT_FN0_1)) brcmf_pcie_handle_mb_data(devinfo); - if (status & BRCMF_PCIE_MB_INT_D2H_DB) { + if (status & mask) { if (devinfo->state == BRCMFMAC_PCIE_STATE_UP) brcmf_proto_msgbuf_rx_trigger( &devinfo->pdev->dev); @@ -914,8 +1125,8 @@ static void brcmf_pcie_release_irq(struct brcmf_pciedev_info *devinfo) if (devinfo->in_irq) brcmf_err(bus, "Still in IRQ (processing) !!!\n"); - status = brcmf_pcie_read_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT); - brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT, status); + status = brcmf_pcie_read_reg32(devinfo, brcmf_pcie_reg_map(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT)); + brcmf_pcie_write_reg32(devinfo, brcmf_pcie_reg_map(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT), status); devinfo->irq_allocated = false; } @@ -967,7 +1178,7 @@ static int brcmf_pcie_ring_mb_ring_bell(void *ctx) brcmf_dbg(PCIE, "RING !\n"); /* Any arbitrary value will do, lets use 1 */ - brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_H2D_MAILBOX_0, 1); + brcmf_pcie_write_reg32(devinfo, brcmf_pcie_reg_map(devinfo, BRCMF_PCIE_PCIE2REG_H2D_MAILBOX_0), 1); return 0; } @@ -1543,6 +1754,8 @@ brcmf_pcie_init_share_ram_info(struct brcmf_pciedev_info *devinfo, return 0; } +#define RANDOMBYTES_SIZE 264 +#define CLEAR_SIZE 256 static int brcmf_pcie_download_fw_nvram(struct brcmf_pciedev_info *devinfo, const struct firmware *fw, void *nvram, @@ -1553,15 +1766,16 @@ static int brcmf_pcie_download_fw_nvram(struct brcmf_pciedev_info *devinfo, u32 sharedram_addr_written; u32 loop_counter; int err; - u32 address; + u32 address, clraddr; u32 resetintr; + uint8_t randb[RANDOMBYTES_SIZE]; brcmf_dbg(PCIE, "Halt ARM.\n"); err = brcmf_pcie_enter_download_state(devinfo); if (err) return err; - brcmf_dbg(PCIE, "Download FW %s\n", devinfo->fw_name); + brcmf_dbg(PCIE, "Download FW %s 0x%x 0x%x\n", devinfo->fw_name, (unsigned)devinfo->ci->rambase, (unsigned)fw->size); brcmf_pcie_copy_mem_todev(devinfo, devinfo->ci->rambase, (void *)fw->data, fw->size); @@ -1574,20 +1788,38 @@ static int brcmf_pcie_download_fw_nvram(struct brcmf_pciedev_info *devinfo, 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; + brcmf_dbg(PCIE, "Download NVRAM %s 0x%x 0x%x\n", devinfo->nvram_name, address, nvram_len); brcmf_pcie_copy_mem_todev(devinfo, address, nvram, nvram_len); brcmf_fw_nvram_free(nvram); + + address -= RANDOMBYTES_SIZE; + get_random_bytes(randb, RANDOMBYTES_SIZE - 8); + memcpy(randb + RANDOMBYTES_SIZE - 8, "\x00\x01\x00\x00\xde\xc0\xed\xfe", 8); + brcmf_pcie_copy_mem_todev(devinfo, address, randb, RANDOMBYTES_SIZE); } else { brcmf_dbg(PCIE, "No matching NVRAM file found %s\n", devinfo->nvram_name); + address = devinfo->ci->rambase + devinfo->ci->ramsize; + } + + memset(randb, 0, CLEAR_SIZE); + clraddr = devinfo->ci->rambase + fw->size; + while(clraddr < address) { + u32 block = address - clraddr; + if(block > CLEAR_SIZE) + block = CLEAR_SIZE; + if(((clraddr + block - 1) ^ clraddr) & -CLEAR_SIZE) + block = (CLEAR_SIZE - clraddr) & (CLEAR_SIZE - 1); + brcmf_pcie_copy_mem_todev(devinfo, clraddr, randb, block); + clraddr += block; } sharedram_addr_written = brcmf_pcie_read_ram32(devinfo, devinfo->ci->ramsize - 4); - brcmf_dbg(PCIE, "Bring ARM in running state\n"); + brcmf_dbg(PCIE, "Bring ARM in running state (RAM sign: 0x%08x)\n", sharedram_addr_written); err = brcmf_pcie_exit_download_state(devinfo, resetintr); if (err) return err; @@ -1719,9 +1951,9 @@ static int brcmf_pcie_buscore_reset(void *ctx, struct brcmf_chip *chip) devinfo->ci = chip; brcmf_pcie_reset_device(devinfo); - val = brcmf_pcie_read_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT); + val = brcmf_pcie_read_reg32(devinfo, brcmf_pcie_reg_map(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT)); if (val != 0xffffffff) - brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT, + brcmf_pcie_write_reg32(devinfo, brcmf_pcie_reg_map(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT), val); return 0; @@ -1892,6 +2124,16 @@ brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto fail; } + if(devinfo->ci->chip == BRCM_CC_4378_CHIP_ID) { + brcmf_pcie_read_otp(devinfo); + + if(!brcmf_mac_addr[0]) { + dev_info(&pdev->dev, "hardware discovery complete, not starting driver\n"); + ret = -ENODEV; + goto exit; + } + } + pcie_bus_dev = kzalloc(sizeof(*pcie_bus_dev), GFP_KERNEL); if (pcie_bus_dev == NULL) { ret = -ENOMEM; @@ -1954,6 +2196,7 @@ brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) kfree(bus); fail: brcmf_err(NULL, "failed %x:%x\n", pdev->vendor, pdev->device); +exit: brcmf_pcie_release_resource(devinfo); if (devinfo->ci) brcmf_chip_detach(devinfo->ci); @@ -2053,7 +2296,7 @@ static int brcmf_pcie_pm_leave_D3(struct device *dev) brcmf_dbg(PCIE, "Enter, dev=%p, bus=%p\n", dev, bus); /* Check if device is still up and running, if so we are ready */ - if (brcmf_pcie_read_reg32(devinfo, BRCMF_PCIE_PCIE2REG_INTMASK) != 0) { + if (brcmf_pcie_read_reg32(devinfo, brcmf_pcie_reg_map(devinfo, BRCMF_PCIE_PCIE2REG_INTMASK)) != 0) { brcmf_dbg(PCIE, "Try to wakeup device....\n"); if (brcmf_pcie_send_mb_data(devinfo, BRCMF_H2D_HOST_D0_INFORM)) goto cleanup; @@ -2119,6 +2362,7 @@ static const struct pci_device_id brcmf_pcie_devid_table[] = { BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_2G_DEVICE_ID), BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_5G_DEVICE_ID), BRCMF_PCIE_DEVICE(BRCM_PCIE_4371_DEVICE_ID), + BRCMF_PCIE_DEVICE(BRCM_PCIE_4378_DEVICE_ID), { /* end: all zeroes */ } }; 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 c6c4be05159d49..083cc6927417e2 100644 --- a/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h +++ b/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h @@ -49,6 +49,7 @@ #define BRCM_CC_4366_CHIP_ID 0x4366 #define BRCM_CC_43664_CHIP_ID 43664 #define BRCM_CC_4371_CHIP_ID 0x4371 +#define BRCM_CC_4378_CHIP_ID 0x4378 #define CY_CC_4373_CHIP_ID 0x4373 #define CY_CC_43012_CHIP_ID 43012 @@ -83,6 +84,7 @@ #define BRCM_PCIE_4366_2G_DEVICE_ID 0x43c4 #define BRCM_PCIE_4366_5G_DEVICE_ID 0x43c5 #define BRCM_PCIE_4371_DEVICE_ID 0x440d +#define BRCM_PCIE_4378_DEVICE_ID 0x4425 /* brcmsmac IDs */