Commit 5e037e74 authored by Luciano Coelho's avatar Luciano Coelho

wl12xx: use two MAC addresses based on the NVS or from fuse ROM

Add support for two MAC addresses.  If the NVS has a valid MAC
address, that takes precedence and we use two sequential address
starting from the one specified.

If the NVS doesn't contain a valid MAC address (ie. if it is set to
00:00:00:00:00:00), we check if the HW PG version in use has the
BD_ADDR written in the fuse ROM.  If it does, we read it and derive
the two subsequent addresses for WLAN.

During production, 3 addresses are reserved per device.  The first for
Bluetooth (burnt in the fuse ROM) and the following two for WLAN.

This patch has some code by Igal and Arik (squashed from internal
patches).
Signed-off-by: default avatarArik Nemtsov <arik@wizery.com>
Signed-off-by: default avatarIgal Chernobelsky <igalc@ti.com>
Signed-off-by: default avatarLuciano Coelho <coelho@ti.com>
parent 30c5dbd1
...@@ -258,12 +258,12 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) ...@@ -258,12 +258,12 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
} }
/* update current MAC address to NVS */ /* update current MAC address to NVS */
nvs_ptr[11] = wl->mac_addr[0]; nvs_ptr[11] = wl->addresses[0].addr[0];
nvs_ptr[10] = wl->mac_addr[1]; nvs_ptr[10] = wl->addresses[0].addr[1];
nvs_ptr[6] = wl->mac_addr[2]; nvs_ptr[6] = wl->addresses[0].addr[2];
nvs_ptr[5] = wl->mac_addr[3]; nvs_ptr[5] = wl->addresses[0].addr[3];
nvs_ptr[4] = wl->mac_addr[4]; nvs_ptr[4] = wl->addresses[0].addr[4];
nvs_ptr[3] = wl->mac_addr[5]; nvs_ptr[3] = wl->addresses[0].addr[5];
/* /*
* Layout before the actual NVS tables: * Layout before the actual NVS tables:
...@@ -626,7 +626,7 @@ static int wl127x_boot_clk(struct wl1271 *wl) ...@@ -626,7 +626,7 @@ static int wl127x_boot_clk(struct wl1271 *wl)
u32 pause; u32 pause;
u32 clk; u32 clk;
if (((wl->hw_pg_ver & PG_MAJOR_VER_MASK) >> PG_MAJOR_VER_OFFSET) < 3) if (WL127X_PG_GET_MAJOR(wl->hw_pg_ver) < 3)
wl->quirks |= WL12XX_QUIRK_END_OF_TRANSACTION; wl->quirks |= WL12XX_QUIRK_END_OF_TRANSACTION;
if (wl->ref_clock == CONF_REF_CLK_19_2_E || if (wl->ref_clock == CONF_REF_CLK_19_2_E ||
......
...@@ -55,16 +55,6 @@ struct wl1271_static_data { ...@@ -55,16 +55,6 @@ struct wl1271_static_data {
#define OCP_REG_CLK_POLARITY 0x0cb2 #define OCP_REG_CLK_POLARITY 0x0cb2
#define OCP_REG_CLK_PULL 0x0cb4 #define OCP_REG_CLK_PULL 0x0cb4
#define WL127X_REG_FUSE_DATA_2_1 0x050a
#define WL128X_REG_FUSE_DATA_2_1 0x2152
#define PG_VER_MASK 0x3c
#define PG_VER_OFFSET 2
#define PG_MAJOR_VER_MASK 0x3
#define PG_MAJOR_VER_OFFSET 0x0
#define PG_MINOR_VER_MASK 0xc
#define PG_MINOR_VER_OFFSET 0x2
#define CMD_MBOX_ADDRESS 0x407B4 #define CMD_MBOX_ADDRESS 0x407B4
#define POLARITY_LOW BIT(1) #define POLARITY_LOW BIT(1)
......
...@@ -2132,7 +2132,7 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, ...@@ -2132,7 +2132,7 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
* we still need this in order to configure the fw * we still need this in order to configure the fw
* while uploading the nvs * while uploading the nvs
*/ */
memcpy(wl->mac_addr, vif->addr, ETH_ALEN); memcpy(wl->addresses[0].addr, vif->addr, ETH_ALEN);
booted = wl12xx_init_fw(wl); booted = wl12xx_init_fw(wl);
if (!booted) { if (!booted) {
...@@ -4859,6 +4859,76 @@ static struct bin_attribute fwlog_attr = { ...@@ -4859,6 +4859,76 @@ static struct bin_attribute fwlog_attr = {
.read = wl1271_sysfs_read_fwlog, .read = wl1271_sysfs_read_fwlog,
}; };
static bool wl12xx_mac_in_fuse(struct wl1271 *wl)
{
bool supported = false;
u8 major, minor;
if (wl->chip.id == CHIP_ID_1283_PG20) {
major = WL128X_PG_GET_MAJOR(wl->hw_pg_ver);
minor = WL128X_PG_GET_MINOR(wl->hw_pg_ver);
/* in wl128x we have the MAC address if the PG is >= (2, 1) */
if (major > 2 || (major == 2 && minor >= 1))
supported = true;
} else {
major = WL127X_PG_GET_MAJOR(wl->hw_pg_ver);
minor = WL127X_PG_GET_MINOR(wl->hw_pg_ver);
/* in wl127x we have the MAC address if the PG is >= (3, 1) */
if (major == 3 && minor >= 1)
supported = true;
}
wl1271_debug(DEBUG_PROBE,
"PG Ver major = %d minor = %d, MAC %s present",
major, minor, supported ? "is" : "is not");
return supported;
}
static void wl12xx_derive_mac_addresses(struct wl1271 *wl,
u32 oui, u32 nic, int n)
{
int i;
wl1271_debug(DEBUG_PROBE, "base address: oui %06x nic %06x, n %d",
oui, nic, n);
if (nic + n - 1 > 0xffffff)
wl1271_warning("NIC part of the MAC address wraps around!");
for (i = 0; i < n; i++) {
wl->addresses[i].addr[0] = (u8)(oui >> 16);
wl->addresses[i].addr[1] = (u8)(oui >> 8);
wl->addresses[i].addr[2] = (u8) oui;
wl->addresses[i].addr[3] = (u8)(nic >> 16);
wl->addresses[i].addr[4] = (u8)(nic >> 8);
wl->addresses[i].addr[5] = (u8) nic;
nic++;
}
wl->hw->wiphy->n_addresses = n;
wl->hw->wiphy->addresses = wl->addresses;
}
static void wl12xx_get_fuse_mac(struct wl1271 *wl)
{
u32 mac1, mac2;
wl1271_set_partition(wl, &wl12xx_part_table[PART_DRPW]);
mac1 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_1);
mac2 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_2);
/* these are the two parts of the BD_ADDR */
wl->fuse_oui_addr = ((mac2 & 0xffff) << 8) +
((mac1 & 0xff000000) >> 24);
wl->fuse_nic_addr = mac1 & 0xffffff;
wl1271_set_partition(wl, &wl12xx_part_table[PART_DOWN]);
}
static int wl12xx_get_hw_info(struct wl1271 *wl) static int wl12xx_get_hw_info(struct wl1271 *wl)
{ {
int ret; int ret;
...@@ -4877,6 +4947,13 @@ static int wl12xx_get_hw_info(struct wl1271 *wl) ...@@ -4877,6 +4947,13 @@ static int wl12xx_get_hw_info(struct wl1271 *wl)
wl->hw_pg_ver = (s8) (die_info & PG_VER_MASK) >> PG_VER_OFFSET; wl->hw_pg_ver = (s8) (die_info & PG_VER_MASK) >> PG_VER_OFFSET;
if (!wl12xx_mac_in_fuse(wl)) {
wl->fuse_oui_addr = 0;
wl->fuse_nic_addr = 0;
} else {
wl12xx_get_fuse_mac(wl);
}
wl1271_power_off(wl); wl1271_power_off(wl);
out: out:
return ret; return ret;
...@@ -4885,6 +4962,7 @@ static int wl12xx_get_hw_info(struct wl1271 *wl) ...@@ -4885,6 +4962,7 @@ static int wl12xx_get_hw_info(struct wl1271 *wl)
static int wl1271_register_hw(struct wl1271 *wl) static int wl1271_register_hw(struct wl1271 *wl)
{ {
int ret; int ret;
u32 oui_addr = 0, nic_addr = 0;
if (wl->mac80211_registered) if (wl->mac80211_registered)
return 0; return 0;
...@@ -4903,15 +4981,20 @@ static int wl1271_register_hw(struct wl1271 *wl) ...@@ -4903,15 +4981,20 @@ static int wl1271_register_hw(struct wl1271 *wl)
*/ */
u8 *nvs_ptr = (u8 *)wl->nvs; u8 *nvs_ptr = (u8 *)wl->nvs;
wl->mac_addr[0] = nvs_ptr[11]; oui_addr =
wl->mac_addr[1] = nvs_ptr[10]; (nvs_ptr[11] << 16) + (nvs_ptr[10] << 8) + nvs_ptr[6];
wl->mac_addr[2] = nvs_ptr[6]; nic_addr =
wl->mac_addr[3] = nvs_ptr[5]; (nvs_ptr[5] << 16) + (nvs_ptr[4] << 8) + nvs_ptr[3];
wl->mac_addr[4] = nvs_ptr[4]; }
wl->mac_addr[5] = nvs_ptr[3];
/* if the MAC address is zeroed in the NVS derive from fuse */
if (oui_addr == 0 && nic_addr == 0) {
oui_addr = wl->fuse_oui_addr;
/* fuse has the BD_ADDR, the WLAN addresses are the next two */
nic_addr = wl->fuse_nic_addr + 1;
} }
SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr); wl12xx_derive_mac_addresses(wl, oui_addr, nic_addr, 2);
ret = ieee80211_register_hw(wl->hw); ret = ieee80211_register_hw(wl->hw);
if (ret < 0) { if (ret < 0) {
......
...@@ -525,4 +525,31 @@ b12-b0 - Supported Rate indicator bits as defined below. ...@@ -525,4 +525,31 @@ b12-b0 - Supported Rate indicator bits as defined below.
*/ */
#define INTR_TRIG_TX_PROC1 BIT(18) #define INTR_TRIG_TX_PROC1 BIT(18)
#define WL127X_REG_FUSE_DATA_2_1 0x050a
#define WL128X_REG_FUSE_DATA_2_1 0x2152
#define PG_VER_MASK 0x3c
#define PG_VER_OFFSET 2
#define WL127X_PG_MAJOR_VER_MASK 0x3
#define WL127X_PG_MAJOR_VER_OFFSET 0x0
#define WL127X_PG_MINOR_VER_MASK 0xc
#define WL127X_PG_MINOR_VER_OFFSET 0x2
#define WL128X_PG_MAJOR_VER_MASK 0xc
#define WL128X_PG_MAJOR_VER_OFFSET 0x2
#define WL128X_PG_MINOR_VER_MASK 0x3
#define WL128X_PG_MINOR_VER_OFFSET 0x0
#define WL127X_PG_GET_MAJOR(pg_ver) ((pg_ver & WL127X_PG_MAJOR_VER_MASK) >> \
WL127X_PG_MAJOR_VER_OFFSET)
#define WL127X_PG_GET_MINOR(pg_ver) ((pg_ver & WL127X_PG_MINOR_VER_MASK) >> \
WL127X_PG_MINOR_VER_OFFSET)
#define WL128X_PG_GET_MAJOR(pg_ver) ((pg_ver & WL128X_PG_MAJOR_VER_MASK) >> \
WL128X_PG_MAJOR_VER_OFFSET)
#define WL128X_PG_GET_MINOR(pg_ver) ((pg_ver & WL128X_PG_MINOR_VER_MASK) >> \
WL128X_PG_MINOR_VER_OFFSET)
#define WL12XX_REG_FUSE_BD_ADDR_1 0x00310eb4
#define WL12XX_REG_FUSE_BD_ADDR_2 0x00310eb8
#endif #endif
...@@ -313,7 +313,12 @@ struct wl1271 { ...@@ -313,7 +313,12 @@ struct wl1271 {
s8 hw_pg_ver; s8 hw_pg_ver;
u8 mac_addr[ETH_ALEN]; /* address read from the fuse ROM */
u32 fuse_oui_addr;
u32 fuse_nic_addr;
/* we have up to 2 MAC addresses */
struct mac_address addresses[2];
int channel; int channel;
u8 system_hlid; u8 system_hlid;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment