2021-02-20 08:39:12 +00:00
|
|
|
From 02ad06fbf2b35916ee329a9bb80d73840d6e2973 Mon Sep 17 00:00:00 2001
|
|
|
|
|
From: Stan Skowronek <stan@corellium.com>
|
|
|
|
|
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 <stan@corellium.com>
|
|
|
|
|
---
|
|
|
|
|
.../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 0ee421f30aa24..8f7db434de111 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 5bf11e46fc49a..4058edddbdc23 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)
|
|
|
|
|
return 0x160000;
|
2021-11-01 23:59:37 +05:30
|
|
|
case CY_CC_43752_CHIP_ID:
|
|
|
|
|
return 0x170000;
|
2021-02-20 08:39:12 +00:00
|
|
|
+ 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 e3758bd86acf0..4b91a04afdc34 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 8b5f49997c8b5..3b6ba43af4d51 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 d821a4758f8cf..c3a05e254c851 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 "<var>=<value>\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 ec6fc7a150a6a..1c1d5131c3f36 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 45bc502fcb341..2890b24a34d1d 100644
|
|
|
|
|
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
|
|
|
|
|
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
|
|
|
|
|
@@ -4,6 +4,7 @@
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
|
+#include <linux/random.h>
|
|
|
|
|
#include <linux/module.h>
|
|
|
|
|
#include <linux/firmware.h>
|
|
|
|
|
#include <linux/pci.h>
|
|
|
|
|
@@ -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),
|
2021-08-07 19:22:02 +05:30
|
|
|
@@ -79,6 +81,7 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = {
|
2021-02-20 08:39:12 +00:00
|
|
|
BRCMF_FW_ENTRY(BRCM_CC_43664_CHIP_ID, 0xFFFFFFF0, 4366C),
|
2021-08-07 15:12:00 +05:30
|
|
|
BRCMF_FW_ENTRY(BRCM_CC_43666_CHIP_ID, 0xFFFFFFF0, 4366C),
|
2021-02-20 08:39:12 +00:00
|
|
|
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; len<size; len++)
|
|
|
|
|
+ if(data[len] == 0x00 || data[len] == ' ' || data[len] == 0xFF)
|
|
|
|
|
+ break;
|
|
|
|
|
+ memcpy(tmp, data, len);
|
|
|
|
|
+ tmp[len] = 0;
|
|
|
|
|
+ data += len;
|
|
|
|
|
+ size -= len;
|
|
|
|
|
+ if(size) {
|
|
|
|
|
+ data ++;
|
|
|
|
|
+ size --;
|
|
|
|
|
+ }
|
|
|
|
|
+ brcmf_dbg(PCIE, "system vendor OTP element '%s'\n", tmp);
|
|
|
|
|
+
|
|
|
|
|
+ if(len < 2)
|
|
|
|
|
+ continue;
|
|
|
|
|
+ if(tmp[1] == '=' && len < 8)
|
|
|
|
|
+ switch(tmp[0]) {
|
|
|
|
|
+ case 's':
|
|
|
|
|
+ strcpy(t_chiprev, tmp + 2);
|
|
|
|
|
+ break;
|
|
|
|
|
+ case 'M':
|
|
|
|
|
+ strcpy(t_module, tmp + 2);
|
|
|
|
|
+ break;
|
|
|
|
|
+ case 'm':
|
|
|
|
|
+ strcpy(t_modrev, tmp + 2);
|
|
|
|
|
+ break;
|
|
|
|
|
+ case 'V':
|
|
|
|
|
+ strcpy(t_vendor, tmp + 2);
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ sprintf(t_chip, (devinfo->ci->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 && i<size-1; i++)
|
|
|
|
|
+ sprintf(tmp + 2 * i, "%02x", data[i+1]);
|
|
|
|
|
+ dev_info(&devinfo->pdev->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; i<OTP_SIZE; i+=2)
|
|
|
|
|
+ ((u16 *)otp)[i/2] = brcmf_pcie_read_reg16(devinfo, base + i);
|
|
|
|
|
+
|
|
|
|
|
+ i = 0;
|
|
|
|
|
+ while(i < OTP_SIZE - 1) {
|
|
|
|
|
+ type = otp[i];
|
|
|
|
|
+ if(!type) { /* null tuple */
|
|
|
|
|
+ i ++;
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ size = otp[i + 1];
|
|
|
|
|
+ i += 2;
|
|
|
|
|
+ if(i + size <= OTP_SIZE)
|
|
|
|
|
+ brcmf_pcie_process_otp_tuple(devinfo, type, size, otp + i);
|
|
|
|
|
+ i += size;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
|
|
|
|
|
static void brcmf_pcie_attach(struct brcmf_pciedev_info *devinfo)
|
|
|
|
|
{
|
|
|
|
|
u32 config;
|
|
|
|
|
|
|
|
|
|
+ brcmf_pcie_read_otp(devinfo);
|
|
|
|
|
+
|
|
|
|
|
/* BAR1 window may not be sized properly */
|
|
|
|
|
brcmf_pcie_select_core(devinfo, BCMA_CORE_PCIE2);
|
|
|
|
|
brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_CONFIGADDR, 0x4e0);
|
|
|
|
|
@@ -809,30 +1011,34 @@ static void brcmf_pcie_bus_console_read(struct brcmf_pciedev_info *devinfo,
|
|
|
|
|
|
|
|
|
|
static void brcmf_pcie_intr_disable(struct brcmf_pciedev_info *devinfo)
|
|
|
|
|
{
|
|
|
|
|
- brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXMASK, 0);
|
|
|
|
|
+ brcmf_pcie_write_reg32(devinfo, brcmf_pcie_reg_map(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXMASK), 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void brcmf_pcie_intr_enable(struct brcmf_pciedev_info *devinfo)
|
|
|
|
|
{
|
|
|
|
|
- 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);
|
|
|
|
|
+ if(devinfo->ci->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 c6c4be05159d4..083cc6927417e 100644
|
|
|
|
|
--- a/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h
|
|
|
|
|
+++ b/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h
|
2021-08-07 19:22:02 +05:30
|
|
|
@@ -50,6 +50,7 @@
|
2021-02-20 08:39:12 +00:00
|
|
|
#define BRCM_CC_43664_CHIP_ID 43664
|
2021-08-07 13:47:24 +05:30
|
|
|
#define BRCM_CC_43666_CHIP_ID 43666
|
2021-02-20 08:39:12 +00:00
|
|
|
#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
|
2021-11-01 23:59:37 +05:30
|
|
|
#define CY_CC_43752_CHIP_ID 43752
|
2021-02-20 08:39:12 +00:00
|
|
|
@@ -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 */
|