From: Luciano Coelho Date: Fri, 23 Dec 2011 07:32:17 +0000 (+0200) Subject: wl12xx: use two MAC addresses based on the NVS or from fuse ROM X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=5e037e74802a10a71dddbb05585753b2fcbd8ad7;p=linux-beck.git 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: Arik Nemtsov Signed-off-by: Igal Chernobelsky Signed-off-by: Luciano Coelho --- diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c index 599919e2a60d..32a7f9b69d7c 100644 --- a/drivers/net/wireless/wl12xx/boot.c +++ b/drivers/net/wireless/wl12xx/boot.c @@ -258,12 +258,12 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) } /* update current MAC address to NVS */ - nvs_ptr[11] = wl->mac_addr[0]; - nvs_ptr[10] = wl->mac_addr[1]; - nvs_ptr[6] = wl->mac_addr[2]; - nvs_ptr[5] = wl->mac_addr[3]; - nvs_ptr[4] = wl->mac_addr[4]; - nvs_ptr[3] = wl->mac_addr[5]; + nvs_ptr[11] = wl->addresses[0].addr[0]; + nvs_ptr[10] = wl->addresses[0].addr[1]; + nvs_ptr[6] = wl->addresses[0].addr[2]; + nvs_ptr[5] = wl->addresses[0].addr[3]; + nvs_ptr[4] = wl->addresses[0].addr[4]; + nvs_ptr[3] = wl->addresses[0].addr[5]; /* * Layout before the actual NVS tables: @@ -626,7 +626,7 @@ static int wl127x_boot_clk(struct wl1271 *wl) u32 pause; 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; if (wl->ref_clock == CONF_REF_CLK_19_2_E || diff --git a/drivers/net/wireless/wl12xx/boot.h b/drivers/net/wireless/wl12xx/boot.h index 06dad9380fa7..c3adc09f403d 100644 --- a/drivers/net/wireless/wl12xx/boot.h +++ b/drivers/net/wireless/wl12xx/boot.h @@ -55,16 +55,6 @@ struct wl1271_static_data { #define OCP_REG_CLK_POLARITY 0x0cb2 #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 POLARITY_LOW BIT(1) diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index a41af84f649d..6c92f86217cd 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -2132,7 +2132,7 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, * we still need this in order to configure the fw * 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); if (!booted) { @@ -4859,6 +4859,76 @@ static struct bin_attribute fwlog_attr = { .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) { int ret; @@ -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; + 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); out: return ret; @@ -4885,6 +4962,7 @@ out: static int wl1271_register_hw(struct wl1271 *wl) { int ret; + u32 oui_addr = 0, nic_addr = 0; if (wl->mac80211_registered) return 0; @@ -4903,15 +4981,20 @@ static int wl1271_register_hw(struct wl1271 *wl) */ u8 *nvs_ptr = (u8 *)wl->nvs; - wl->mac_addr[0] = nvs_ptr[11]; - wl->mac_addr[1] = nvs_ptr[10]; - wl->mac_addr[2] = nvs_ptr[6]; - wl->mac_addr[3] = nvs_ptr[5]; - wl->mac_addr[4] = nvs_ptr[4]; - wl->mac_addr[5] = nvs_ptr[3]; + oui_addr = + (nvs_ptr[11] << 16) + (nvs_ptr[10] << 8) + nvs_ptr[6]; + nic_addr = + (nvs_ptr[5] << 16) + (nvs_ptr[4] << 8) + 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); if (ret < 0) { diff --git a/drivers/net/wireless/wl12xx/reg.h b/drivers/net/wireless/wl12xx/reg.h index df34d5977b98..340db324bc26 100644 --- a/drivers/net/wireless/wl12xx/reg.h +++ b/drivers/net/wireless/wl12xx/reg.h @@ -525,4 +525,31 @@ b12-b0 - Supported Rate indicator bits as defined below. */ #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 diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index b2b09cd02022..1f629fac02e4 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -313,7 +313,12 @@ struct wl1271 { 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; u8 system_hlid;