diff options
Diffstat (limited to 'drivers/net/wireless/ti/wl12xx/main.c')
-rw-r--r-- | drivers/net/wireless/ti/wl12xx/main.c | 621 |
1 files changed, 488 insertions, 133 deletions
diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c index d7dd3def07b..f429fc110cb 100644 --- a/drivers/net/wireless/ti/wl12xx/main.c +++ b/drivers/net/wireless/ti/wl12xx/main.c @@ -39,6 +39,10 @@ #include "reg.h" #include "cmd.h" #include "acx.h" +#include "debugfs.h" + +static char *fref_param; +static char *tcxo_param; static struct wlcore_conf wl12xx_conf = { .sg = { @@ -212,7 +216,7 @@ static struct wlcore_conf wl12xx_conf = { .suspend_wake_up_event = CONF_WAKE_UP_EVENT_N_DTIM, .suspend_listen_interval = 3, .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED, - .bcn_filt_ie_count = 2, + .bcn_filt_ie_count = 3, .bcn_filt_ie = { [0] = { .ie = WLAN_EID_CHANNEL_SWITCH, @@ -222,9 +226,13 @@ static struct wlcore_conf wl12xx_conf = { .ie = WLAN_EID_HT_OPERATION, .rule = CONF_BCN_RULE_PASS_ON_CHANGE, }, + [2] = { + .ie = WLAN_EID_ERP_INFO, + .rule = CONF_BCN_RULE_PASS_ON_CHANGE, + }, }, - .synch_fail_thold = 10, - .bss_lose_timeout = 100, + .synch_fail_thold = 12, + .bss_lose_timeout = 400, .beacon_rx_timeout = 10000, .broadcast_timeout = 20000, .rx_broadcast_in_ps = 1, @@ -234,10 +242,11 @@ static struct wlcore_conf wl12xx_conf = { .psm_entry_retries = 8, .psm_exit_retries = 16, .psm_entry_nullfunc_retries = 3, - .dynamic_ps_timeout = 40, + .dynamic_ps_timeout = 1500, .forced_ps = false, .keep_alive_interval = 55000, .max_listen_interval = 20, + .sta_sleep_auth = WL1271_PSM_ILLEGAL, }, .itrim = { .enable = false, @@ -245,7 +254,7 @@ static struct wlcore_conf wl12xx_conf = { }, .pm_config = { .host_clk_settling_time = 5000, - .host_fast_wakeup_support = false + .host_fast_wakeup_support = CONF_FAST_WAKEUP_DISABLE, }, .roam_trigger = { .trigger_pacing = 1, @@ -305,8 +314,8 @@ static struct wlcore_conf wl12xx_conf = { .swallow_period = 5, .n_divider_fref_set_1 = 0xff, /* default */ .n_divider_fref_set_2 = 12, - .m_divider_fref_set_1 = 148, - .m_divider_fref_set_2 = 0xffff, /* default */ + .m_divider_fref_set_1 = 0xffff, + .m_divider_fref_set_2 = 148, /* default */ .coex_pll_stabilization_time = 0xffffffff, /* default */ .ldo_stabilization_time = 0xffff, /* default */ .fm_disturbed_band_margin = 0xff, /* default */ @@ -581,19 +590,21 @@ static const int wl12xx_rtable[REG_TABLE_LEN] = { }; /* TODO: maybe move to a new header file? */ -#define WL127X_FW_NAME_MULTI "ti-connectivity/wl127x-fw-4-mr.bin" -#define WL127X_FW_NAME_SINGLE "ti-connectivity/wl127x-fw-4-sr.bin" -#define WL127X_PLT_FW_NAME "ti-connectivity/wl127x-fw-4-plt.bin" +#define WL127X_FW_NAME_MULTI "ti-connectivity/wl127x-fw-5-mr.bin" +#define WL127X_FW_NAME_SINGLE "ti-connectivity/wl127x-fw-5-sr.bin" +#define WL127X_PLT_FW_NAME "ti-connectivity/wl127x-fw-5-plt.bin" -#define WL128X_FW_NAME_MULTI "ti-connectivity/wl128x-fw-4-mr.bin" -#define WL128X_FW_NAME_SINGLE "ti-connectivity/wl128x-fw-4-sr.bin" -#define WL128X_PLT_FW_NAME "ti-connectivity/wl128x-fw-4-plt.bin" +#define WL128X_FW_NAME_MULTI "ti-connectivity/wl128x-fw-5-mr.bin" +#define WL128X_FW_NAME_SINGLE "ti-connectivity/wl128x-fw-5-sr.bin" +#define WL128X_PLT_FW_NAME "ti-connectivity/wl128x-fw-5-plt.bin" -static void wl127x_prepare_read(struct wl1271 *wl, u32 rx_desc, u32 len) +static int wl127x_prepare_read(struct wl1271 *wl, u32 rx_desc, u32 len) { + int ret; + if (wl->chip.id != CHIP_ID_1283_PG20) { struct wl1271_acx_mem_map *wl_mem_map = wl->target_mem_map; - struct wl1271_rx_mem_pool_addr rx_mem_addr; + struct wl127x_rx_mem_pool_addr rx_mem_addr; /* * Choose the block we want to read @@ -607,9 +618,13 @@ static void wl127x_prepare_read(struct wl1271 *wl, u32 rx_desc, u32 len) rx_mem_addr.addr_extra = rx_mem_addr.addr + 4; - wl1271_write(wl, WL1271_SLV_REG_DATA, - &rx_mem_addr, sizeof(rx_mem_addr), false); + ret = wlcore_write(wl, WL1271_SLV_REG_DATA, &rx_mem_addr, + sizeof(rx_mem_addr), false); + if (ret < 0) + return ret; } + + return 0; } static int wl12xx_identify_chip(struct wl1271 *wl) @@ -621,10 +636,9 @@ static int wl12xx_identify_chip(struct wl1271 *wl) wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete", wl->chip.id); - /* clear the alignment quirk, since we don't support it */ - wl->quirks &= ~WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN; - - wl->quirks |= WLCORE_QUIRK_LEGACY_NVS; + wl->quirks |= WLCORE_QUIRK_LEGACY_NVS | + WLCORE_QUIRK_DUAL_PROBE_TMPL | + WLCORE_QUIRK_TKIP_HEADER_SPACE; wl->sr_fw_name = WL127X_FW_NAME_SINGLE; wl->mr_fw_name = WL127X_FW_NAME_MULTI; memcpy(&wl->conf.mem, &wl12xx_default_priv_conf.mem_wl127x, @@ -633,16 +647,18 @@ static int wl12xx_identify_chip(struct wl1271 *wl) /* read data preparation is only needed by wl127x */ wl->ops->prepare_read = wl127x_prepare_read; + wlcore_set_min_fw_ver(wl, WL127X_CHIP_VER, WL127X_IFTYPE_VER, + WL127X_MAJOR_VER, WL127X_SUBTYPE_VER, + WL127X_MINOR_VER); break; case CHIP_ID_1271_PG20: wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)", wl->chip.id); - /* clear the alignment quirk, since we don't support it */ - wl->quirks &= ~WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN; - - wl->quirks |= WLCORE_QUIRK_LEGACY_NVS; + wl->quirks |= WLCORE_QUIRK_LEGACY_NVS | + WLCORE_QUIRK_DUAL_PROBE_TMPL | + WLCORE_QUIRK_TKIP_HEADER_SPACE; wl->plt_fw_name = WL127X_PLT_FW_NAME; wl->sr_fw_name = WL127X_FW_NAME_SINGLE; wl->mr_fw_name = WL127X_FW_NAME_MULTI; @@ -652,6 +668,9 @@ static int wl12xx_identify_chip(struct wl1271 *wl) /* read data preparation is only needed by wl127x */ wl->ops->prepare_read = wl127x_prepare_read; + wlcore_set_min_fw_ver(wl, WL127X_CHIP_VER, WL127X_IFTYPE_VER, + WL127X_MAJOR_VER, WL127X_SUBTYPE_VER, + WL127X_MINOR_VER); break; case CHIP_ID_1283_PG20: @@ -660,6 +679,15 @@ static int wl12xx_identify_chip(struct wl1271 *wl) wl->plt_fw_name = WL128X_PLT_FW_NAME; wl->sr_fw_name = WL128X_FW_NAME_SINGLE; wl->mr_fw_name = WL128X_FW_NAME_MULTI; + + /* wl128x requires TX blocksize alignment */ + wl->quirks |= WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN | + WLCORE_QUIRK_DUAL_PROBE_TMPL | + WLCORE_QUIRK_TKIP_HEADER_SPACE; + + wlcore_set_min_fw_ver(wl, WL128X_CHIP_VER, WL128X_IFTYPE_VER, + WL128X_MAJOR_VER, WL128X_SUBTYPE_VER, + WL128X_MINOR_VER); break; case CHIP_ID_1283_PG10: default: @@ -672,64 +700,95 @@ out: return ret; } -static void wl12xx_top_reg_write(struct wl1271 *wl, int addr, u16 val) +static int __must_check wl12xx_top_reg_write(struct wl1271 *wl, int addr, + u16 val) { + int ret; + /* write address >> 1 + 0x30000 to OCP_POR_CTR */ addr = (addr >> 1) + 0x30000; - wl1271_write32(wl, WL12XX_OCP_POR_CTR, addr); + ret = wlcore_write32(wl, WL12XX_OCP_POR_CTR, addr); + if (ret < 0) + goto out; /* write value to OCP_POR_WDATA */ - wl1271_write32(wl, WL12XX_OCP_DATA_WRITE, val); + ret = wlcore_write32(wl, WL12XX_OCP_DATA_WRITE, val); + if (ret < 0) + goto out; /* write 1 to OCP_CMD */ - wl1271_write32(wl, WL12XX_OCP_CMD, OCP_CMD_WRITE); + ret = wlcore_write32(wl, WL12XX_OCP_CMD, OCP_CMD_WRITE); + if (ret < 0) + goto out; + +out: + return ret; } -static u16 wl12xx_top_reg_read(struct wl1271 *wl, int addr) +static int __must_check wl12xx_top_reg_read(struct wl1271 *wl, int addr, + u16 *out) { u32 val; int timeout = OCP_CMD_LOOP; + int ret; /* write address >> 1 + 0x30000 to OCP_POR_CTR */ addr = (addr >> 1) + 0x30000; - wl1271_write32(wl, WL12XX_OCP_POR_CTR, addr); + ret = wlcore_write32(wl, WL12XX_OCP_POR_CTR, addr); + if (ret < 0) + return ret; /* write 2 to OCP_CMD */ - wl1271_write32(wl, WL12XX_OCP_CMD, OCP_CMD_READ); + ret = wlcore_write32(wl, WL12XX_OCP_CMD, OCP_CMD_READ); + if (ret < 0) + return ret; /* poll for data ready */ do { - val = wl1271_read32(wl, WL12XX_OCP_DATA_READ); + ret = wlcore_read32(wl, WL12XX_OCP_DATA_READ, &val); + if (ret < 0) + return ret; } while (!(val & OCP_READY_MASK) && --timeout); if (!timeout) { wl1271_warning("Top register access timed out."); - return 0xffff; + return -ETIMEDOUT; } /* check data status and return if OK */ - if ((val & OCP_STATUS_MASK) == OCP_STATUS_OK) - return val & 0xffff; - else { + if ((val & OCP_STATUS_MASK) != OCP_STATUS_OK) { wl1271_warning("Top register access returned error."); - return 0xffff; + return -EIO; } + + if (out) + *out = val & 0xffff; + + return 0; } static int wl128x_switch_tcxo_to_fref(struct wl1271 *wl) { u16 spare_reg; + int ret; /* Mask bits [2] & [8:4] in the sys_clk_cfg register */ - spare_reg = wl12xx_top_reg_read(wl, WL_SPARE_REG); + ret = wl12xx_top_reg_read(wl, WL_SPARE_REG, &spare_reg); + if (ret < 0) + return ret; + if (spare_reg == 0xFFFF) return -EFAULT; spare_reg |= (BIT(3) | BIT(5) | BIT(6)); - wl12xx_top_reg_write(wl, WL_SPARE_REG, spare_reg); + ret = wl12xx_top_reg_write(wl, WL_SPARE_REG, spare_reg); + if (ret < 0) + return ret; /* Enable FREF_CLK_REQ & mux MCS and coex PLLs to FREF */ - wl12xx_top_reg_write(wl, SYS_CLK_CFG_REG, - WL_CLK_REQ_TYPE_PG2 | MCS_PLL_CLK_SEL_FREF); + ret = wl12xx_top_reg_write(wl, SYS_CLK_CFG_REG, + WL_CLK_REQ_TYPE_PG2 | MCS_PLL_CLK_SEL_FREF); + if (ret < 0) + return ret; /* Delay execution for 15msec, to let the HW settle */ mdelay(15); @@ -740,8 +799,12 @@ static int wl128x_switch_tcxo_to_fref(struct wl1271 *wl) static bool wl128x_is_tcxo_valid(struct wl1271 *wl) { u16 tcxo_detection; + int ret; + + ret = wl12xx_top_reg_read(wl, TCXO_CLK_DETECT_REG, &tcxo_detection); + if (ret < 0) + return false; - tcxo_detection = wl12xx_top_reg_read(wl, TCXO_CLK_DETECT_REG); if (tcxo_detection & TCXO_DET_FAILED) return false; @@ -751,8 +814,12 @@ static bool wl128x_is_tcxo_valid(struct wl1271 *wl) static bool wl128x_is_fref_valid(struct wl1271 *wl) { u16 fref_detection; + int ret; + + ret = wl12xx_top_reg_read(wl, FREF_CLK_DETECT_REG, &fref_detection); + if (ret < 0) + return false; - fref_detection = wl12xx_top_reg_read(wl, FREF_CLK_DETECT_REG); if (fref_detection & FREF_CLK_DETECT_FAIL) return false; @@ -761,11 +828,21 @@ static bool wl128x_is_fref_valid(struct wl1271 *wl) static int wl128x_manually_configure_mcs_pll(struct wl1271 *wl) { - wl12xx_top_reg_write(wl, MCS_PLL_M_REG, MCS_PLL_M_REG_VAL); - wl12xx_top_reg_write(wl, MCS_PLL_N_REG, MCS_PLL_N_REG_VAL); - wl12xx_top_reg_write(wl, MCS_PLL_CONFIG_REG, MCS_PLL_CONFIG_REG_VAL); + int ret; - return 0; + ret = wl12xx_top_reg_write(wl, MCS_PLL_M_REG, MCS_PLL_M_REG_VAL); + if (ret < 0) + goto out; + + ret = wl12xx_top_reg_write(wl, MCS_PLL_N_REG, MCS_PLL_N_REG_VAL); + if (ret < 0) + goto out; + + ret = wl12xx_top_reg_write(wl, MCS_PLL_CONFIG_REG, + MCS_PLL_CONFIG_REG_VAL); + +out: + return ret; } static int wl128x_configure_mcs_pll(struct wl1271 *wl, int clk) @@ -773,30 +850,40 @@ static int wl128x_configure_mcs_pll(struct wl1271 *wl, int clk) u16 spare_reg; u16 pll_config; u8 input_freq; + struct wl12xx_priv *priv = wl->priv; + int ret; /* Mask bits [3:1] in the sys_clk_cfg register */ - spare_reg = wl12xx_top_reg_read(wl, WL_SPARE_REG); + ret = wl12xx_top_reg_read(wl, WL_SPARE_REG, &spare_reg); + if (ret < 0) + return ret; + if (spare_reg == 0xFFFF) return -EFAULT; spare_reg |= BIT(2); - wl12xx_top_reg_write(wl, WL_SPARE_REG, spare_reg); + ret = wl12xx_top_reg_write(wl, WL_SPARE_REG, spare_reg); + if (ret < 0) + return ret; /* Handle special cases of the TCXO clock */ - if (wl->tcxo_clock == WL12XX_TCXOCLOCK_16_8 || - wl->tcxo_clock == WL12XX_TCXOCLOCK_33_6) + if (priv->tcxo_clock == WL12XX_TCXOCLOCK_16_8 || + priv->tcxo_clock == WL12XX_TCXOCLOCK_33_6) return wl128x_manually_configure_mcs_pll(wl); /* Set the input frequency according to the selected clock source */ input_freq = (clk & 1) + 1; - pll_config = wl12xx_top_reg_read(wl, MCS_PLL_CONFIG_REG); + ret = wl12xx_top_reg_read(wl, MCS_PLL_CONFIG_REG, &pll_config); + if (ret < 0) + return ret; + if (pll_config == 0xFFFF) return -EFAULT; pll_config |= (input_freq << MCS_SEL_IN_FREQ_SHIFT); pll_config |= MCS_PLL_ENABLE_HP; - wl12xx_top_reg_write(wl, MCS_PLL_CONFIG_REG, pll_config); + ret = wl12xx_top_reg_write(wl, MCS_PLL_CONFIG_REG, pll_config); - return 0; + return ret; } /* @@ -808,26 +895,31 @@ static int wl128x_configure_mcs_pll(struct wl1271 *wl, int clk) */ static int wl128x_boot_clk(struct wl1271 *wl, int *selected_clock) { + struct wl12xx_priv *priv = wl->priv; u16 sys_clk_cfg; + int ret; /* For XTAL-only modes, FREF will be used after switching from TCXO */ - if (wl->ref_clock == WL12XX_REFCLOCK_26_XTAL || - wl->ref_clock == WL12XX_REFCLOCK_38_XTAL) { + if (priv->ref_clock == WL12XX_REFCLOCK_26_XTAL || + priv->ref_clock == WL12XX_REFCLOCK_38_XTAL) { if (!wl128x_switch_tcxo_to_fref(wl)) return -EINVAL; goto fref_clk; } /* Query the HW, to determine which clock source we should use */ - sys_clk_cfg = wl12xx_top_reg_read(wl, SYS_CLK_CFG_REG); + ret = wl12xx_top_reg_read(wl, SYS_CLK_CFG_REG, &sys_clk_cfg); + if (ret < 0) + return ret; + if (sys_clk_cfg == 0xFFFF) return -EINVAL; if (sys_clk_cfg & PRCM_CM_EN_MUX_WLAN_FREF) goto fref_clk; /* If TCXO is either 32.736MHz or 16.368MHz, switch to FREF */ - if (wl->tcxo_clock == WL12XX_TCXOCLOCK_16_368 || - wl->tcxo_clock == WL12XX_TCXOCLOCK_32_736) { + if (priv->tcxo_clock == WL12XX_TCXOCLOCK_16_368 || + priv->tcxo_clock == WL12XX_TCXOCLOCK_32_736) { if (!wl128x_switch_tcxo_to_fref(wl)) return -EINVAL; goto fref_clk; @@ -836,14 +928,14 @@ static int wl128x_boot_clk(struct wl1271 *wl, int *selected_clock) /* TCXO clock is selected */ if (!wl128x_is_tcxo_valid(wl)) return -EINVAL; - *selected_clock = wl->tcxo_clock; + *selected_clock = priv->tcxo_clock; goto config_mcs_pll; fref_clk: /* FREF clock is selected */ if (!wl128x_is_fref_valid(wl)) return -EINVAL; - *selected_clock = wl->ref_clock; + *selected_clock = priv->ref_clock; config_mcs_pll: return wl128x_configure_mcs_pll(wl, *selected_clock); @@ -851,69 +943,98 @@ config_mcs_pll: static int wl127x_boot_clk(struct wl1271 *wl) { + struct wl12xx_priv *priv = wl->priv; u32 pause; u32 clk; + int ret; if (WL127X_PG_GET_MAJOR(wl->hw_pg_ver) < 3) wl->quirks |= WLCORE_QUIRK_END_OF_TRANSACTION; - if (wl->ref_clock == CONF_REF_CLK_19_2_E || - wl->ref_clock == CONF_REF_CLK_38_4_E || - wl->ref_clock == CONF_REF_CLK_38_4_M_XTAL) + if (priv->ref_clock == CONF_REF_CLK_19_2_E || + priv->ref_clock == CONF_REF_CLK_38_4_E || + priv->ref_clock == CONF_REF_CLK_38_4_M_XTAL) /* ref clk: 19.2/38.4/38.4-XTAL */ clk = 0x3; - else if (wl->ref_clock == CONF_REF_CLK_26_E || - wl->ref_clock == CONF_REF_CLK_52_E) + else if (priv->ref_clock == CONF_REF_CLK_26_E || + priv->ref_clock == CONF_REF_CLK_26_M_XTAL || + priv->ref_clock == CONF_REF_CLK_52_E) /* ref clk: 26/52 */ clk = 0x5; else return -EINVAL; - if (wl->ref_clock != CONF_REF_CLK_19_2_E) { + if (priv->ref_clock != CONF_REF_CLK_19_2_E) { u16 val; /* Set clock type (open drain) */ - val = wl12xx_top_reg_read(wl, OCP_REG_CLK_TYPE); + ret = wl12xx_top_reg_read(wl, OCP_REG_CLK_TYPE, &val); + if (ret < 0) + goto out; + val &= FREF_CLK_TYPE_BITS; - wl12xx_top_reg_write(wl, OCP_REG_CLK_TYPE, val); + ret = wl12xx_top_reg_write(wl, OCP_REG_CLK_TYPE, val); + if (ret < 0) + goto out; /* Set clock pull mode (no pull) */ - val = wl12xx_top_reg_read(wl, OCP_REG_CLK_PULL); + ret = wl12xx_top_reg_read(wl, OCP_REG_CLK_PULL, &val); + if (ret < 0) + goto out; + val |= NO_PULL; - wl12xx_top_reg_write(wl, OCP_REG_CLK_PULL, val); + ret = wl12xx_top_reg_write(wl, OCP_REG_CLK_PULL, val); + if (ret < 0) + goto out; } else { u16 val; /* Set clock polarity */ - val = wl12xx_top_reg_read(wl, OCP_REG_CLK_POLARITY); + ret = wl12xx_top_reg_read(wl, OCP_REG_CLK_POLARITY, &val); + if (ret < 0) + goto out; + val &= FREF_CLK_POLARITY_BITS; val |= CLK_REQ_OUTN_SEL; - wl12xx_top_reg_write(wl, OCP_REG_CLK_POLARITY, val); + ret = wl12xx_top_reg_write(wl, OCP_REG_CLK_POLARITY, val); + if (ret < 0) + goto out; } - wl1271_write32(wl, WL12XX_PLL_PARAMETERS, clk); + ret = wlcore_write32(wl, WL12XX_PLL_PARAMETERS, clk); + if (ret < 0) + goto out; - pause = wl1271_read32(wl, WL12XX_PLL_PARAMETERS); + ret = wlcore_read32(wl, WL12XX_PLL_PARAMETERS, &pause); + if (ret < 0) + goto out; wl1271_debug(DEBUG_BOOT, "pause1 0x%x", pause); pause &= ~(WU_COUNTER_PAUSE_VAL); pause |= WU_COUNTER_PAUSE_VAL; - wl1271_write32(wl, WL12XX_WU_COUNTER_PAUSE, pause); + ret = wlcore_write32(wl, WL12XX_WU_COUNTER_PAUSE, pause); - return 0; +out: + return ret; } static int wl1271_boot_soft_reset(struct wl1271 *wl) { unsigned long timeout; u32 boot_data; + int ret = 0; /* perform soft reset */ - wl1271_write32(wl, WL12XX_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT); + ret = wlcore_write32(wl, WL12XX_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT); + if (ret < 0) + goto out; /* SOFT_RESET is self clearing */ timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME); while (1) { - boot_data = wl1271_read32(wl, WL12XX_SLV_SOFT_RESET); + ret = wlcore_read32(wl, WL12XX_SLV_SOFT_RESET, &boot_data); + if (ret < 0) + goto out; + wl1271_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data); if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0) break; @@ -929,16 +1050,20 @@ static int wl1271_boot_soft_reset(struct wl1271 *wl) } /* disable Rx/Tx */ - wl1271_write32(wl, WL12XX_ENABLE, 0x0); + ret = wlcore_write32(wl, WL12XX_ENABLE, 0x0); + if (ret < 0) + goto out; /* disable auto calibration on start*/ - wl1271_write32(wl, WL12XX_SPARE_A2, 0xffff); + ret = wlcore_write32(wl, WL12XX_SPARE_A2, 0xffff); - return 0; +out: + return ret; } static int wl12xx_pre_boot(struct wl1271 *wl) { + struct wl12xx_priv *priv = wl->priv; int ret = 0; u32 clk; int selected_clock = -1; @@ -954,30 +1079,43 @@ static int wl12xx_pre_boot(struct wl1271 *wl) } /* Continue the ELP wake up sequence */ - wl1271_write32(wl, WL12XX_WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL); + ret = wlcore_write32(wl, WL12XX_WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL); + if (ret < 0) + goto out; + udelay(500); - wlcore_set_partition(wl, &wl->ptable[PART_DRPW]); + ret = wlcore_set_partition(wl, &wl->ptable[PART_DRPW]); + if (ret < 0) + goto out; /* Read-modify-write DRPW_SCRATCH_START register (see next state) to be used by DRPw FW. The RTRIM value will be added by the FW before taking DRPw out of reset */ - clk = wl1271_read32(wl, WL12XX_DRPW_SCRATCH_START); + ret = wlcore_read32(wl, WL12XX_DRPW_SCRATCH_START, &clk); + if (ret < 0) + goto out; wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk); if (wl->chip.id == CHIP_ID_1283_PG20) clk |= ((selected_clock & 0x3) << 1) << 4; else - clk |= (wl->ref_clock << 1) << 4; + clk |= (priv->ref_clock << 1) << 4; - wl1271_write32(wl, WL12XX_DRPW_SCRATCH_START, clk); + ret = wlcore_write32(wl, WL12XX_DRPW_SCRATCH_START, clk); + if (ret < 0) + goto out; - wlcore_set_partition(wl, &wl->ptable[PART_WORK]); + ret = wlcore_set_partition(wl, &wl->ptable[PART_WORK]); + if (ret < 0) + goto out; /* Disable interrupts */ - wlcore_write_reg(wl, REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL); + ret = wlcore_write_reg(wl, REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL); + if (ret < 0) + goto out; ret = wl1271_boot_soft_reset(wl); if (ret < 0) @@ -987,47 +1125,72 @@ out: return ret; } -static void wl12xx_pre_upload(struct wl1271 *wl) +static int wl12xx_pre_upload(struct wl1271 *wl) { u32 tmp; + u16 polarity; + int ret; /* write firmware's last address (ie. it's length) to * ACX_EEPROMLESS_IND_REG */ wl1271_debug(DEBUG_BOOT, "ACX_EEPROMLESS_IND_REG"); - wl1271_write32(wl, WL12XX_EEPROMLESS_IND, WL12XX_EEPROMLESS_IND); + ret = wlcore_write32(wl, WL12XX_EEPROMLESS_IND, WL12XX_EEPROMLESS_IND); + if (ret < 0) + goto out; - tmp = wlcore_read_reg(wl, REG_CHIP_ID_B); + ret = wlcore_read_reg(wl, REG_CHIP_ID_B, &tmp); + if (ret < 0) + goto out; wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp); /* 6. read the EEPROM parameters */ - tmp = wl1271_read32(wl, WL12XX_SCR_PAD2); + ret = wlcore_read32(wl, WL12XX_SCR_PAD2, &tmp); + if (ret < 0) + goto out; /* WL1271: The reference driver skips steps 7 to 10 (jumps directly * to upload_fw) */ - if (wl->chip.id == CHIP_ID_1283_PG20) - wl12xx_top_reg_write(wl, SDIO_IO_DS, HCI_IO_DS_6MA); -} - -static void wl12xx_enable_interrupts(struct wl1271 *wl) -{ - u32 polarity; + if (wl->chip.id == CHIP_ID_1283_PG20) { + ret = wl12xx_top_reg_write(wl, SDIO_IO_DS, HCI_IO_DS_6MA); + if (ret < 0) + goto out; + } - polarity = wl12xx_top_reg_read(wl, OCP_REG_POLARITY); + /* polarity must be set before the firmware is loaded */ + ret = wl12xx_top_reg_read(wl, OCP_REG_POLARITY, &polarity); + if (ret < 0) + goto out; /* We use HIGH polarity, so unset the LOW bit */ polarity &= ~POLARITY_LOW; - wl12xx_top_reg_write(wl, OCP_REG_POLARITY, polarity); + ret = wl12xx_top_reg_write(wl, OCP_REG_POLARITY, polarity); + +out: + return ret; +} - wlcore_write_reg(wl, REG_INTERRUPT_MASK, WL1271_ACX_ALL_EVENTS_VECTOR); +static int wl12xx_enable_interrupts(struct wl1271 *wl) +{ + int ret; + + ret = wlcore_write_reg(wl, REG_INTERRUPT_MASK, + WL12XX_ACX_ALL_EVENTS_VECTOR); + if (ret < 0) + goto out; wlcore_enable_interrupts(wl); - wlcore_write_reg(wl, REG_INTERRUPT_MASK, - WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK)); + ret = wlcore_write_reg(wl, REG_INTERRUPT_MASK, + WL1271_ACX_INTR_ALL & ~(WL12XX_INTR_MASK)); + if (ret < 0) + goto out; + + ret = wlcore_write32(wl, WL12XX_HI_CFG, HI_CFG_DEF_VAL); - wl1271_write32(wl, WL12XX_HI_CFG, HI_CFG_DEF_VAL); +out: + return ret; } static int wl12xx_boot(struct wl1271 *wl) @@ -1042,7 +1205,9 @@ static int wl12xx_boot(struct wl1271 *wl) if (ret < 0) goto out; - wl12xx_pre_upload(wl); + ret = wl12xx_pre_upload(wl); + if (ret < 0) + goto out; ret = wlcore_boot_upload_firmware(wl); if (ret < 0) @@ -1052,22 +1217,30 @@ static int wl12xx_boot(struct wl1271 *wl) if (ret < 0) goto out; - wl12xx_enable_interrupts(wl); + ret = wl12xx_enable_interrupts(wl); out: return ret; } -static void wl12xx_trigger_cmd(struct wl1271 *wl, int cmd_box_addr, +static int wl12xx_trigger_cmd(struct wl1271 *wl, int cmd_box_addr, void *buf, size_t len) { - wl1271_write(wl, cmd_box_addr, buf, len, false); - wlcore_write_reg(wl, REG_INTERRUPT_TRIG, WL12XX_INTR_TRIG_CMD); + int ret; + + ret = wlcore_write(wl, cmd_box_addr, buf, len, false); + if (ret < 0) + return ret; + + ret = wlcore_write_reg(wl, REG_INTERRUPT_TRIG, WL12XX_INTR_TRIG_CMD); + + return ret; } -static void wl12xx_ack_event(struct wl1271 *wl) +static int wl12xx_ack_event(struct wl1271 *wl) { - wlcore_write_reg(wl, REG_INTERRUPT_TRIG, WL12XX_INTR_TRIG_EVENT_ACK); + return wlcore_write_reg(wl, REG_INTERRUPT_TRIG, + WL12XX_INTR_TRIG_EVENT_ACK); } static u32 wl12xx_calc_tx_blocks(struct wl1271 *wl, u32 len, u32 spare_blks) @@ -1147,12 +1320,13 @@ static u32 wl12xx_get_rx_packet_len(struct wl1271 *wl, void *rx_data, return data_len - sizeof(*desc) - desc->pad_len; } -static void wl12xx_tx_delayed_compl(struct wl1271 *wl) +static int wl12xx_tx_delayed_compl(struct wl1271 *wl) { - if (wl->fw_status->tx_results_counter == (wl->tx_results_count & 0xff)) - return; + if (wl->fw_status_1->tx_results_counter == + (wl->tx_results_count & 0xff)) + return 0; - wl1271_tx_complete(wl); + return wlcore_tx_complete(wl); } static int wl12xx_hw_init(struct wl1271 *wl) @@ -1165,6 +1339,14 @@ static int wl12xx_hw_init(struct wl1271 *wl) ret = wl128x_cmd_general_parms(wl); if (ret < 0) goto out; + + /* + * If we are in calibrator based auto detect then we got the FEM nr + * in wl->fem_manuf. No need to continue further + */ + if (wl->plt_mode == PLT_FEM_DETECT) + goto out; + ret = wl128x_cmd_radio_parms(wl); if (ret < 0) goto out; @@ -1181,6 +1363,14 @@ static int wl12xx_hw_init(struct wl1271 *wl) ret = wl1271_cmd_general_parms(wl); if (ret < 0) goto out; + + /* + * If we are in calibrator based auto detect then we got the FEM nr + * in wl->fem_manuf. No need to continue further + */ + if (wl->plt_mode == PLT_FEM_DETECT) + goto out; + ret = wl1271_cmd_radio_parms(wl); if (ret < 0) goto out; @@ -1253,45 +1443,151 @@ static bool wl12xx_mac_in_fuse(struct wl1271 *wl) return supported; } -static void wl12xx_get_fuse_mac(struct wl1271 *wl) +static int wl12xx_get_fuse_mac(struct wl1271 *wl) { u32 mac1, mac2; + int ret; + + ret = wlcore_set_partition(wl, &wl->ptable[PART_DRPW]); + if (ret < 0) + goto out; - wlcore_set_partition(wl, &wl->ptable[PART_DRPW]); + ret = wlcore_read32(wl, WL12XX_REG_FUSE_BD_ADDR_1, &mac1); + if (ret < 0) + goto out; - mac1 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_1); - mac2 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_2); + ret = wlcore_read32(wl, WL12XX_REG_FUSE_BD_ADDR_2, &mac2); + if (ret < 0) + goto out; /* 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; - wlcore_set_partition(wl, &wl->ptable[PART_DOWN]); + ret = wlcore_set_partition(wl, &wl->ptable[PART_DOWN]); + +out: + return ret; } -static s8 wl12xx_get_pg_ver(struct wl1271 *wl) +static int wl12xx_get_pg_ver(struct wl1271 *wl, s8 *ver) { - u32 die_info; + u16 die_info; + int ret; if (wl->chip.id == CHIP_ID_1283_PG20) - die_info = wl12xx_top_reg_read(wl, WL128X_REG_FUSE_DATA_2_1); + ret = wl12xx_top_reg_read(wl, WL128X_REG_FUSE_DATA_2_1, + &die_info); else - die_info = wl12xx_top_reg_read(wl, WL127X_REG_FUSE_DATA_2_1); + ret = wl12xx_top_reg_read(wl, WL127X_REG_FUSE_DATA_2_1, + &die_info); - return (s8) (die_info & PG_VER_MASK) >> PG_VER_OFFSET; + if (ret >= 0 && ver) + *ver = (s8)((die_info & PG_VER_MASK) >> PG_VER_OFFSET); + + return ret; } -static void wl12xx_get_mac(struct wl1271 *wl) +static int wl12xx_get_mac(struct wl1271 *wl) { if (wl12xx_mac_in_fuse(wl)) - wl12xx_get_fuse_mac(wl); + return wl12xx_get_fuse_mac(wl); + + return 0; +} + +static void wl12xx_set_tx_desc_csum(struct wl1271 *wl, + struct wl1271_tx_hw_descr *desc, + struct sk_buff *skb) +{ + desc->wl12xx_reserved = 0; +} + +static int wl12xx_plt_init(struct wl1271 *wl) +{ + int ret; + + ret = wl->ops->boot(wl); + if (ret < 0) + goto out; + + ret = wl->ops->hw_init(wl); + if (ret < 0) + goto out_irq_disable; + + /* + * If we are in calibrator based auto detect then we got the FEM nr + * in wl->fem_manuf. No need to continue further + */ + if (wl->plt_mode == PLT_FEM_DETECT) + goto out; + + ret = wl1271_acx_init_mem_config(wl); + if (ret < 0) + goto out_irq_disable; + + ret = wl12xx_acx_mem_cfg(wl); + if (ret < 0) + goto out_free_memmap; + + /* Enable data path */ + ret = wl1271_cmd_data_path(wl, 1); + if (ret < 0) + goto out_free_memmap; + + /* Configure for CAM power saving (ie. always active) */ + ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM); + if (ret < 0) + goto out_free_memmap; + + /* configure PM */ + ret = wl1271_acx_pm_config(wl); + if (ret < 0) + goto out_free_memmap; + + goto out; + +out_free_memmap: + kfree(wl->target_mem_map); + wl->target_mem_map = NULL; + +out_irq_disable: + mutex_unlock(&wl->mutex); + /* Unlocking the mutex in the middle of handling is + inherently unsafe. In this case we deem it safe to do, + because we need to let any possibly pending IRQ out of + the system (and while we are WL1271_STATE_OFF the IRQ + work function will not do anything.) Also, any other + possible concurrent operations will fail due to the + current state, hence the wl1271 struct should be safe. */ + wlcore_disable_interrupts(wl); + mutex_lock(&wl->mutex); +out: + return ret; +} + +static int wl12xx_get_spare_blocks(struct wl1271 *wl, bool is_gem) +{ + if (is_gem) + return WL12XX_TX_HW_BLOCK_GEM_SPARE; + + return WL12XX_TX_HW_BLOCK_SPARE_DEFAULT; +} + +static int wl12xx_set_key(struct wl1271 *wl, enum set_key_cmd cmd, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key_conf) +{ + return wlcore_set_key(wl, cmd, vif, sta, key_conf); } static struct wlcore_ops wl12xx_ops = { .identify_chip = wl12xx_identify_chip, .identify_fw = wl12xx_identify_fw, .boot = wl12xx_boot, + .plt_init = wl12xx_plt_init, .trigger_cmd = wl12xx_trigger_cmd, .ack_event = wl12xx_ack_event, .calc_tx_blocks = wl12xx_calc_tx_blocks, @@ -1306,6 +1602,13 @@ static struct wlcore_ops wl12xx_ops = { .sta_get_ap_rate_mask = wl12xx_sta_get_ap_rate_mask, .get_pg_ver = wl12xx_get_pg_ver, .get_mac = wl12xx_get_mac, + .set_tx_desc_csum = wl12xx_set_tx_desc_csum, + .set_rx_csum = NULL, + .ap_get_mimo_wide_rate_mask = NULL, + .debugfs_init = wl12xx_debugfs_add_files, + .get_spare_blocks = wl12xx_get_spare_blocks, + .set_key = wl12xx_set_key, + .pre_pkt_send = NULL, }; static struct ieee80211_sta_ht_cap wl12xx_ht_cap = { @@ -1323,6 +1626,7 @@ static struct ieee80211_sta_ht_cap wl12xx_ht_cap = { static int __devinit wl12xx_probe(struct platform_device *pdev) { + struct wl12xx_platform_data *pdata = pdev->dev.platform_data; struct wl1271 *wl; struct ieee80211_hw *hw; struct wl12xx_priv *priv; @@ -1334,19 +1638,63 @@ static int __devinit wl12xx_probe(struct platform_device *pdev) } wl = hw->priv; + priv = wl->priv; wl->ops = &wl12xx_ops; wl->ptable = wl12xx_ptable; wl->rtable = wl12xx_rtable; wl->num_tx_desc = 16; - wl->normal_tx_spare = WL12XX_TX_HW_BLOCK_SPARE_DEFAULT; - wl->gem_tx_spare = WL12XX_TX_HW_BLOCK_GEM_SPARE; + wl->num_rx_desc = 8; wl->band_rate_to_idx = wl12xx_band_rate_to_idx; wl->hw_tx_rate_tbl_size = WL12XX_CONF_HW_RXTX_RATE_MAX; wl->hw_min_ht_rate = WL12XX_CONF_HW_RXTX_RATE_MCS0; wl->fw_status_priv_len = 0; - memcpy(&wl->ht_cap, &wl12xx_ht_cap, sizeof(wl12xx_ht_cap)); + wl->stats.fw_stats_len = sizeof(struct wl12xx_acx_statistics); + wlcore_set_ht_cap(wl, IEEE80211_BAND_2GHZ, &wl12xx_ht_cap); + wlcore_set_ht_cap(wl, IEEE80211_BAND_5GHZ, &wl12xx_ht_cap); wl12xx_conf_init(wl); + if (!fref_param) { + priv->ref_clock = pdata->board_ref_clock; + } else { + if (!strcmp(fref_param, "19.2")) + priv->ref_clock = WL12XX_REFCLOCK_19; + else if (!strcmp(fref_param, "26")) + priv->ref_clock = WL12XX_REFCLOCK_26; + else if (!strcmp(fref_param, "26x")) + priv->ref_clock = WL12XX_REFCLOCK_26_XTAL; + else if (!strcmp(fref_param, "38.4")) + priv->ref_clock = WL12XX_REFCLOCK_38; + else if (!strcmp(fref_param, "38.4x")) + priv->ref_clock = WL12XX_REFCLOCK_38_XTAL; + else if (!strcmp(fref_param, "52")) + priv->ref_clock = WL12XX_REFCLOCK_52; + else + wl1271_error("Invalid fref parameter %s", fref_param); + } + + if (!tcxo_param) { + priv->tcxo_clock = pdata->board_tcxo_clock; + } else { + if (!strcmp(tcxo_param, "19.2")) + priv->tcxo_clock = WL12XX_TCXOCLOCK_19_2; + else if (!strcmp(tcxo_param, "26")) + priv->tcxo_clock = WL12XX_TCXOCLOCK_26; + else if (!strcmp(tcxo_param, "38.4")) + priv->tcxo_clock = WL12XX_TCXOCLOCK_38_4; + else if (!strcmp(tcxo_param, "52")) + priv->tcxo_clock = WL12XX_TCXOCLOCK_52; + else if (!strcmp(tcxo_param, "16.368")) + priv->tcxo_clock = WL12XX_TCXOCLOCK_16_368; + else if (!strcmp(tcxo_param, "32.736")) + priv->tcxo_clock = WL12XX_TCXOCLOCK_32_736; + else if (!strcmp(tcxo_param, "16.8")) + priv->tcxo_clock = WL12XX_TCXOCLOCK_16_8; + else if (!strcmp(tcxo_param, "33.6")) + priv->tcxo_clock = WL12XX_TCXOCLOCK_33_6; + else + wl1271_error("Invalid tcxo parameter %s", tcxo_param); + } + return wlcore_probe(wl, pdev); } @@ -1378,6 +1726,13 @@ static void __exit wl12xx_exit(void) } module_exit(wl12xx_exit); +module_param_named(fref, fref_param, charp, 0); +MODULE_PARM_DESC(fref, "FREF clock: 19.2, 26, 26x, 38.4, 38.4x, 52"); + +module_param_named(tcxo, tcxo_param, charp, 0); +MODULE_PARM_DESC(tcxo, + "TCXO clock: 19.2, 26, 38.4, 52, 16.368, 32.736, 16.8, 33.6"); + MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>"); MODULE_FIRMWARE(WL127X_FW_NAME_SINGLE); |