Loading drivers/net/wireless/ti/wl18xx/main.c +89 −6 Original line number Diff line number Diff line Loading @@ -623,6 +623,18 @@ static const int wl18xx_rtable[REG_TABLE_LEN] = { [REG_RAW_FW_STATUS_ADDR] = WL18XX_FW_STATUS_ADDR, }; static const struct wl18xx_clk_cfg wl18xx_clk_table_coex[NUM_CLOCK_CONFIGS] = { [CLOCK_CONFIG_16_2_M] = { 8, 121, 0, 0, false }, [CLOCK_CONFIG_16_368_M] = { 8, 120, 0, 0, false }, [CLOCK_CONFIG_16_8_M] = { 8, 117, 0, 0, false }, [CLOCK_CONFIG_19_2_M] = { 10, 128, 0, 0, false }, [CLOCK_CONFIG_26_M] = { 11, 104, 0, 0, false }, [CLOCK_CONFIG_32_736_M] = { 8, 120, 0, 0, false }, [CLOCK_CONFIG_33_6_M] = { 8, 117, 0, 0, false }, [CLOCK_CONFIG_38_468_M] = { 10, 128, 0, 0, false }, [CLOCK_CONFIG_52_M] = { 11, 104, 0, 0, false }, }; static const struct wl18xx_clk_cfg wl18xx_clk_table[NUM_CLOCK_CONFIGS] = { [CLOCK_CONFIG_16_2_M] = { 7, 104, 801, 4, true }, [CLOCK_CONFIG_16_368_M] = { 9, 132, 3751, 4, true }, Loading Loading @@ -704,6 +716,23 @@ static int wl18xx_set_clk(struct wl1271 *wl) wl18xx_clk_table[clk_freq].p, wl18xx_clk_table[clk_freq].q, wl18xx_clk_table[clk_freq].swallow ? "swallow" : "spit"); /* coex PLL configuration */ ret = wl18xx_top_reg_write(wl, PLLSH_COEX_PLL_N, wl18xx_clk_table_coex[clk_freq].n); if (ret < 0) goto out; ret = wl18xx_top_reg_write(wl, PLLSH_COEX_PLL_M, wl18xx_clk_table_coex[clk_freq].m); if (ret < 0) goto out; /* bypass the swallowing logic */ ret = wl18xx_top_reg_write(wl, PLLSH_COEX_PLL_SWALLOW_EN, PLLSH_COEX_PLL_SWALLOW_EN_VAL1); if (ret < 0) goto out; ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_N, wl18xx_clk_table[clk_freq].n); if (ret < 0) Loading Loading @@ -745,6 +774,30 @@ static int wl18xx_set_clk(struct wl1271 *wl) PLLSH_WCS_PLL_SWALLOW_EN_VAL2); } /* choose WCS PLL */ ret = wl18xx_top_reg_write(wl, PLLSH_WL_PLL_SEL, PLLSH_WL_PLL_SEL_WCS_PLL); if (ret < 0) goto out; /* enable both PLLs */ ret = wl18xx_top_reg_write(wl, PLLSH_WL_PLL_EN, PLLSH_WL_PLL_EN_VAL1); if (ret < 0) goto out; udelay(1000); /* disable coex PLL */ ret = wl18xx_top_reg_write(wl, PLLSH_WL_PLL_EN, PLLSH_WL_PLL_EN_VAL2); if (ret < 0) goto out; /* reset the swallowing logic */ ret = wl18xx_top_reg_write(wl, PLLSH_COEX_PLL_SWALLOW_EN, PLLSH_COEX_PLL_SWALLOW_EN_VAL2); if (ret < 0) goto out; out: return ret; } Loading Loading @@ -1175,16 +1228,48 @@ static u32 wl18xx_ap_get_mimo_wide_rate_mask(struct wl1271 *wl, } } static const char *wl18xx_rdl_name(enum wl18xx_rdl_num rdl_num) { switch (rdl_num) { case RDL_1_HP: return "183xH"; case RDL_2_SP: return "183x or 180x"; case RDL_3_HP: return "187xH"; case RDL_4_SP: return "187x"; case RDL_5_SP: return "RDL11 - Not Supported"; case RDL_6_SP: return "180xD"; case RDL_7_SP: return "RDL13 - Not Supported (1893Q)"; case RDL_8_SP: return "18xxQ"; case RDL_NONE: return "UNTRIMMED"; default: return "UNKNOWN"; } } static int wl18xx_get_pg_ver(struct wl1271 *wl, s8 *ver) { u32 fuse; s8 rom = 0, metal = 0, pg_ver = 0, rdl_ver = 0; s8 rom = 0, metal = 0, pg_ver = 0, rdl_ver = 0, package_type = 0; int ret; ret = wlcore_set_partition(wl, &wl->ptable[PART_TOP_PRCM_ELP_SOC]); if (ret < 0) goto out; ret = wlcore_read32(wl, WL18XX_REG_FUSE_DATA_2_3, &fuse); if (ret < 0) goto out; package_type = (fuse >> WL18XX_PACKAGE_TYPE_OFFSET) & 1; ret = wlcore_read32(wl, WL18XX_REG_FUSE_DATA_1_3, &fuse); if (ret < 0) goto out; Loading @@ -1192,7 +1277,7 @@ static int wl18xx_get_pg_ver(struct wl1271 *wl, s8 *ver) pg_ver = (fuse & WL18XX_PG_VER_MASK) >> WL18XX_PG_VER_OFFSET; rom = (fuse & WL18XX_ROM_VER_MASK) >> WL18XX_ROM_VER_OFFSET; if (rom <= 0xE) if ((rom <= 0xE) && (package_type == WL18XX_PACKAGE_TYPE_WSP)) metal = (fuse & WL18XX_METAL_VER_MASK) >> WL18XX_METAL_VER_OFFSET; else Loading @@ -1204,11 +1289,9 @@ static int wl18xx_get_pg_ver(struct wl1271 *wl, s8 *ver) goto out; rdl_ver = (fuse & WL18XX_RDL_VER_MASK) >> WL18XX_RDL_VER_OFFSET; if (rdl_ver > RDL_MAX) rdl_ver = RDL_NONE; wl1271_info("wl18xx HW: RDL %d, %s, PG %x.%x (ROM %x)", rdl_ver, rdl_names[rdl_ver], pg_ver, metal, rom); wl1271_info("wl18xx HW: %s, PG %d.%d (ROM 0x%x)", wl18xx_rdl_name(rdl_ver), pg_ver, metal, rom); if (ver) *ver = pg_ver; Loading drivers/net/wireless/ti/wl18xx/reg.h +23 −10 Original line number Diff line number Diff line Loading @@ -114,6 +114,11 @@ #define PLATFORM_DETECTION 0xA0E3E0 #define OCS_EN 0xA02080 #define PRIMARY_CLK_DETECT 0xA020A6 #define PLLSH_COEX_PLL_N 0xA02384 #define PLLSH_COEX_PLL_M 0xA02382 #define PLLSH_COEX_PLL_SWALLOW_EN 0xA0238E #define PLLSH_WL_PLL_SEL 0xA02398 #define PLLSH_WCS_PLL_N 0xA02362 #define PLLSH_WCS_PLL_M 0xA02360 #define PLLSH_WCS_PLL_Q_FACTOR_CFG_1 0xA02364 Loading @@ -128,19 +133,30 @@ #define PLLSH_WCS_PLL_P_FACTOR_CFG_1_MASK 0xFFFF #define PLLSH_WCS_PLL_P_FACTOR_CFG_2_MASK 0x000F #define PLLSH_WL_PLL_EN_VAL1 0x7 #define PLLSH_WL_PLL_EN_VAL2 0x2 #define PLLSH_COEX_PLL_SWALLOW_EN_VAL1 0x2 #define PLLSH_COEX_PLL_SWALLOW_EN_VAL2 0x11 #define PLLSH_WCS_PLL_SWALLOW_EN_VAL1 0x1 #define PLLSH_WCS_PLL_SWALLOW_EN_VAL2 0x12 #define PLLSH_WL_PLL_SEL_WCS_PLL 0x0 #define PLLSH_WL_PLL_SEL_COEX_PLL 0x1 #define WL18XX_REG_FUSE_DATA_1_3 0xA0260C #define WL18XX_PG_VER_MASK 0x70 #define WL18XX_PG_VER_OFFSET 4 #define WL18XX_ROM_VER_MASK 0x3 #define WL18XX_ROM_VER_OFFSET 0 #define WL18XX_ROM_VER_MASK 0x3e00 #define WL18XX_ROM_VER_OFFSET 9 #define WL18XX_METAL_VER_MASK 0xC #define WL18XX_METAL_VER_OFFSET 2 #define WL18XX_NEW_METAL_VER_MASK 0x180 #define WL18XX_NEW_METAL_VER_OFFSET 7 #define WL18XX_PACKAGE_TYPE_OFFSET 13 #define WL18XX_PACKAGE_TYPE_WSP 0 #define WL18XX_REG_FUSE_DATA_2_3 0xA02614 #define WL18XX_RDL_VER_MASK 0x1f00 #define WL18XX_RDL_VER_OFFSET 8 Loading Loading @@ -201,24 +217,21 @@ enum { NUM_BOARD_TYPES, }; enum { enum wl18xx_rdl_num { RDL_NONE = 0, RDL_1_HP = 1, RDL_2_SP = 2, RDL_3_HP = 3, RDL_4_SP = 4, RDL_5_SP = 0x11, RDL_6_SP = 0x12, RDL_7_SP = 0x13, RDL_8_SP = 0x14, _RDL_LAST, RDL_MAX = _RDL_LAST - 1, }; static const char * const rdl_names[] = { [RDL_NONE] = "", [RDL_1_HP] = "1853 SISO", [RDL_2_SP] = "1857 MIMO", [RDL_3_HP] = "1893 SISO", [RDL_4_SP] = "1897 MIMO", }; /* FPGA_SPARE_1 register - used to change the PHY ATPG clock at boot time */ #define WL18XX_PHY_FPGA_SPARE_1 0x8093CA40 Loading drivers/net/wireless/ti/wlcore/cmd.c +34 −24 Original line number Diff line number Diff line Loading @@ -1126,6 +1126,8 @@ int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, u16 template_id_2_4 = wl->scan_templ_id_2_4; u16 template_id_5 = wl->scan_templ_id_5; wl1271_debug(DEBUG_SCAN, "build probe request band %d", band); skb = ieee80211_probereq_get(wl->hw, vif, ssid, ssid_len, ie_len); if (!skb) { Loading @@ -1135,8 +1137,6 @@ int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, if (ie_len) memcpy(skb_put(skb, ie_len), ie, ie_len); wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", skb->data, skb->len); if (sched_scan && (wl->quirks & WLCORE_QUIRK_DUAL_PROBE_TMPL)) { template_id_2_4 = wl->sched_scan_templ_id_2_4; Loading Loading @@ -1172,7 +1172,7 @@ struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl, if (!skb) goto out; wl1271_dump(DEBUG_SCAN, "AP PROBE REQ: ", skb->data, skb->len); wl1271_debug(DEBUG_SCAN, "set ap probe request template"); rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[wlvif->band]); if (wlvif->band == IEEE80211_BAND_2GHZ) Loading Loading @@ -1607,33 +1607,43 @@ int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid) static int wlcore_get_reg_conf_ch_idx(enum ieee80211_band band, u16 ch) { int idx = -1; /* * map the given band/channel to the respective predefined * bit expected by the fw */ switch (band) { case IEEE80211_BAND_5GHZ: if (ch >= 8 && ch <= 16) idx = ((ch-8)/4 + 18); else if (ch >= 34 && ch <= 64) idx = ((ch-34)/2 + 3 + 18); else if (ch >= 100 && ch <= 140) idx = ((ch-100)/4 + 15 + 18); else if (ch >= 149 && ch <= 165) idx = ((ch-149)/4 + 26 + 18); else idx = -1; break; case IEEE80211_BAND_2GHZ: /* channels 1..14 are mapped to 0..13 */ if (ch >= 1 && ch <= 14) idx = ch - 1; else idx = -1; return ch - 1; break; case IEEE80211_BAND_5GHZ: switch (ch) { case 8 ... 16: /* channels 8,12,16 are mapped to 18,19,20 */ return 18 + (ch-8)/4; case 34 ... 48: /* channels 34,36..48 are mapped to 21..28 */ return 21 + (ch-34)/2; case 52 ... 64: /* channels 52,56..64 are mapped to 29..32 */ return 29 + (ch-52)/4; case 100 ... 140: /* channels 100,104..140 are mapped to 33..43 */ return 33 + (ch-100)/4; case 149 ... 165: /* channels 149,153..165 are mapped to 44..48 */ return 44 + (ch-149)/4; default: wl1271_error("get reg conf ch idx - unknown band: %d", (int)band); break; } break; default: break; } return idx; wl1271_error("%s: unknown band/channel: %d/%d", __func__, band, ch); return -1; } void wlcore_set_pending_regdomain_ch(struct wl1271 *wl, u16 channel, Loading @@ -1646,7 +1656,7 @@ void wlcore_set_pending_regdomain_ch(struct wl1271 *wl, u16 channel, ch_bit_idx = wlcore_get_reg_conf_ch_idx(band, channel); if (ch_bit_idx > 0 && ch_bit_idx <= WL1271_MAX_CHANNELS) if (ch_bit_idx >= 0 && ch_bit_idx <= WL1271_MAX_CHANNELS) set_bit(ch_bit_idx, (long *)wl->reg_ch_conf_pending); } Loading drivers/net/wireless/ti/wlcore/main.c +131 −25 Original line number Diff line number Diff line Loading @@ -1062,7 +1062,8 @@ int wl1271_plt_start(struct wl1271 *wl, const enum plt_mode plt_mode) static const char* const PLT_MODE[] = { "PLT_OFF", "PLT_ON", "PLT_FEM_DETECT" "PLT_FEM_DETECT", "PLT_CHIP_AWAKE" }; int ret; Loading @@ -1088,9 +1089,11 @@ int wl1271_plt_start(struct wl1271 *wl, const enum plt_mode plt_mode) if (ret < 0) goto power_off; if (plt_mode != PLT_CHIP_AWAKE) { ret = wl->ops->plt_init(wl); if (ret < 0) goto power_off; } wl->state = WLCORE_STATE_ON; wl1271_notice("firmware booted in PLT mode %s (%s)", Loading Loading @@ -2008,6 +2011,47 @@ static void wlcore_connection_loss_work(struct work_struct *work) mutex_unlock(&wl->mutex); } static void wlcore_pending_auth_complete_work(struct work_struct *work) { struct delayed_work *dwork; struct wl1271 *wl; struct wl12xx_vif *wlvif; unsigned long time_spare; int ret; dwork = container_of(work, struct delayed_work, work); wlvif = container_of(dwork, struct wl12xx_vif, pending_auth_complete_work); wl = wlvif->wl; mutex_lock(&wl->mutex); if (unlikely(wl->state != WLCORE_STATE_ON)) goto out; /* * Make sure a second really passed since the last auth reply. Maybe * a second auth reply arrived while we were stuck on the mutex. * Check for a little less than the timeout to protect from scheduler * irregularities. */ time_spare = jiffies + msecs_to_jiffies(WLCORE_PEND_AUTH_ROC_TIMEOUT - 50); if (!time_after(time_spare, wlvif->pending_auth_reply_time)) goto out; ret = wl1271_ps_elp_wakeup(wl); if (ret < 0) goto out; /* cancel the ROC if active */ wlcore_update_inconn_sta(wl, wlvif, NULL, false); wl1271_ps_elp_sleep(wl); out: mutex_unlock(&wl->mutex); } static int wl12xx_allocate_rate_policy(struct wl1271 *wl, u8 *idx) { u8 policy = find_first_zero_bit(wl->rate_policies_map, Loading Loading @@ -2159,6 +2203,8 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif) wlcore_channel_switch_work); INIT_DELAYED_WORK(&wlvif->connection_loss_work, wlcore_connection_loss_work); INIT_DELAYED_WORK(&wlvif->pending_auth_complete_work, wlcore_pending_auth_complete_work); INIT_LIST_HEAD(&wlvif->list); setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer, Loading Loading @@ -2376,6 +2422,11 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, int ret = 0; u8 role_type; if (wl->plt) { wl1271_error("Adding Interface not allowed while in PLT mode"); return -EBUSY; } vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER | IEEE80211_VIF_SUPPORTS_CQM_RSSI; Loading Loading @@ -2590,6 +2641,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, cancel_work_sync(&wlvif->rx_streaming_disable_work); cancel_delayed_work_sync(&wlvif->connection_loss_work); cancel_delayed_work_sync(&wlvif->channel_switch_work); cancel_delayed_work_sync(&wlvif->pending_auth_complete_work); mutex_lock(&wl->mutex); } Loading Loading @@ -2875,6 +2927,25 @@ static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif) wlvif->rate_set = wlvif->basic_rate_set; } static void wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif, bool idle) { bool cur_idle = !test_bit(WLVIF_FLAG_ACTIVE, &wlvif->flags); if (idle == cur_idle) return; if (idle) { clear_bit(WLVIF_FLAG_ACTIVE, &wlvif->flags); } else { /* The current firmware only supports sched_scan in idle */ if (wl->sched_vif == wlvif) wl->ops->sched_scan_stop(wl, wlvif); set_bit(WLVIF_FLAG_ACTIVE, &wlvif->flags); } } static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif, struct ieee80211_conf *conf, u32 changed) { Loading Loading @@ -3969,6 +4040,13 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl, } } else { if (test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) { /* * AP might be in ROC in case we have just * sent auth reply. handle it. */ if (test_bit(wlvif->role_id, wl->roc_map)) wl12xx_croc(wl, wlvif->role_id); ret = wl12xx_cmd_role_stop_ap(wl, wlvif); if (ret < 0) goto out; Loading Loading @@ -4120,6 +4198,9 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, do_join = true; } if (changed & BSS_CHANGED_IDLE && !is_ibss) wl1271_sta_handle_idle(wl, wlvif, bss_conf->idle); if (changed & BSS_CHANGED_CQM) { bool enable = false; if (bss_conf->cqm_rssi_thold) Loading Loading @@ -4656,28 +4737,48 @@ static void wlcore_roc_if_possible(struct wl1271 *wl, wl12xx_roc(wl, wlvif, wlvif->role_id, wlvif->band, wlvif->channel); } static void wlcore_update_inconn_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, struct wl1271_station *wl_sta, bool in_connection) /* * when wl_sta is NULL, we treat this call as if coming from a * pending auth reply. * wl->mutex must be taken and the FW must be awake when the call * takes place. */ void wlcore_update_inconn_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, struct wl1271_station *wl_sta, bool in_conn) { if (in_connection) { if (WARN_ON(wl_sta->in_connection)) if (in_conn) { if (WARN_ON(wl_sta && wl_sta->in_connection)) return; wl_sta->in_connection = true; if (!wlvif->inconn_count++) if (!wlvif->ap_pending_auth_reply && !wlvif->inconn_count) wlcore_roc_if_possible(wl, wlvif); if (wl_sta) { wl_sta->in_connection = true; wlvif->inconn_count++; } else { wlvif->ap_pending_auth_reply = true; } } else { if (!wl_sta->in_connection) if (wl_sta && !wl_sta->in_connection) return; if (WARN_ON(!wl_sta && !wlvif->ap_pending_auth_reply)) return; if (WARN_ON(wl_sta && !wlvif->inconn_count)) return; if (wl_sta) { wl_sta->in_connection = false; wlvif->inconn_count--; if (WARN_ON(wlvif->inconn_count < 0)) return; } else { wlvif->ap_pending_auth_reply = false; } if (!wlvif->inconn_count) if (test_bit(wlvif->role_id, wl->roc_map)) if (!wlvif->inconn_count && !wlvif->ap_pending_auth_reply && test_bit(wlvif->role_id, wl->roc_map)) wl12xx_croc(wl, wlvif->role_id); } } Loading Loading @@ -5313,10 +5414,7 @@ static struct ieee80211_rate wl1271_rates_5ghz[] = { /* 5 GHz band channels for WL1273 */ static struct ieee80211_channel wl1271_channels_5ghz[] = { { .hw_value = 7, .center_freq = 5035, .max_power = WLCORE_MAX_TXPWR }, { .hw_value = 8, .center_freq = 5040, .max_power = WLCORE_MAX_TXPWR }, { .hw_value = 9, .center_freq = 5045, .max_power = WLCORE_MAX_TXPWR }, { .hw_value = 11, .center_freq = 5055, .max_power = WLCORE_MAX_TXPWR }, { .hw_value = 12, .center_freq = 5060, .max_power = WLCORE_MAX_TXPWR }, { .hw_value = 16, .center_freq = 5080, .max_power = WLCORE_MAX_TXPWR }, { .hw_value = 34, .center_freq = 5170, .max_power = WLCORE_MAX_TXPWR }, Loading Loading @@ -5896,6 +5994,11 @@ static const struct wiphy_wowlan_support wlcore_wowlan_support = { }; #endif static irqreturn_t wlcore_hardirq(int irq, void *cookie) { return IRQ_WAKE_THREAD; } static void wlcore_nvs_cb(const struct firmware *fw, void *context) { struct wl1271 *wl = context; Loading @@ -5904,6 +6007,7 @@ static void wlcore_nvs_cb(const struct firmware *fw, void *context) struct wl12xx_platform_data *pdata = pdev_data->pdata; unsigned long irqflags; int ret; irq_handler_t hardirq_fn = NULL; if (fw) { wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL); Loading Loading @@ -5932,12 +6036,14 @@ static void wlcore_nvs_cb(const struct firmware *fw, void *context) wl->platform_quirks = pdata->platform_quirks; wl->if_ops = pdev_data->if_ops; if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ) if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ) { irqflags = IRQF_TRIGGER_RISING; else hardirq_fn = wlcore_hardirq; } else { irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT; } ret = request_threaded_irq(wl->irq, NULL, wlcore_irq, ret = request_threaded_irq(wl->irq, hardirq_fn, wlcore_irq, irqflags, pdev->name, wl); if (ret < 0) { wl1271_error("request_irq() failed: %d", ret); Loading drivers/net/wireless/ti/wlcore/ps.c +4 −0 Original line number Diff line number Diff line Loading @@ -83,6 +83,10 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl) struct wl12xx_vif *wlvif; u32 timeout; /* We do not enter elp sleep in PLT mode */ if (wl->plt) return; if (wl->sleep_auth != WL1271_PSM_ELP) return; Loading Loading
drivers/net/wireless/ti/wl18xx/main.c +89 −6 Original line number Diff line number Diff line Loading @@ -623,6 +623,18 @@ static const int wl18xx_rtable[REG_TABLE_LEN] = { [REG_RAW_FW_STATUS_ADDR] = WL18XX_FW_STATUS_ADDR, }; static const struct wl18xx_clk_cfg wl18xx_clk_table_coex[NUM_CLOCK_CONFIGS] = { [CLOCK_CONFIG_16_2_M] = { 8, 121, 0, 0, false }, [CLOCK_CONFIG_16_368_M] = { 8, 120, 0, 0, false }, [CLOCK_CONFIG_16_8_M] = { 8, 117, 0, 0, false }, [CLOCK_CONFIG_19_2_M] = { 10, 128, 0, 0, false }, [CLOCK_CONFIG_26_M] = { 11, 104, 0, 0, false }, [CLOCK_CONFIG_32_736_M] = { 8, 120, 0, 0, false }, [CLOCK_CONFIG_33_6_M] = { 8, 117, 0, 0, false }, [CLOCK_CONFIG_38_468_M] = { 10, 128, 0, 0, false }, [CLOCK_CONFIG_52_M] = { 11, 104, 0, 0, false }, }; static const struct wl18xx_clk_cfg wl18xx_clk_table[NUM_CLOCK_CONFIGS] = { [CLOCK_CONFIG_16_2_M] = { 7, 104, 801, 4, true }, [CLOCK_CONFIG_16_368_M] = { 9, 132, 3751, 4, true }, Loading Loading @@ -704,6 +716,23 @@ static int wl18xx_set_clk(struct wl1271 *wl) wl18xx_clk_table[clk_freq].p, wl18xx_clk_table[clk_freq].q, wl18xx_clk_table[clk_freq].swallow ? "swallow" : "spit"); /* coex PLL configuration */ ret = wl18xx_top_reg_write(wl, PLLSH_COEX_PLL_N, wl18xx_clk_table_coex[clk_freq].n); if (ret < 0) goto out; ret = wl18xx_top_reg_write(wl, PLLSH_COEX_PLL_M, wl18xx_clk_table_coex[clk_freq].m); if (ret < 0) goto out; /* bypass the swallowing logic */ ret = wl18xx_top_reg_write(wl, PLLSH_COEX_PLL_SWALLOW_EN, PLLSH_COEX_PLL_SWALLOW_EN_VAL1); if (ret < 0) goto out; ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_N, wl18xx_clk_table[clk_freq].n); if (ret < 0) Loading Loading @@ -745,6 +774,30 @@ static int wl18xx_set_clk(struct wl1271 *wl) PLLSH_WCS_PLL_SWALLOW_EN_VAL2); } /* choose WCS PLL */ ret = wl18xx_top_reg_write(wl, PLLSH_WL_PLL_SEL, PLLSH_WL_PLL_SEL_WCS_PLL); if (ret < 0) goto out; /* enable both PLLs */ ret = wl18xx_top_reg_write(wl, PLLSH_WL_PLL_EN, PLLSH_WL_PLL_EN_VAL1); if (ret < 0) goto out; udelay(1000); /* disable coex PLL */ ret = wl18xx_top_reg_write(wl, PLLSH_WL_PLL_EN, PLLSH_WL_PLL_EN_VAL2); if (ret < 0) goto out; /* reset the swallowing logic */ ret = wl18xx_top_reg_write(wl, PLLSH_COEX_PLL_SWALLOW_EN, PLLSH_COEX_PLL_SWALLOW_EN_VAL2); if (ret < 0) goto out; out: return ret; } Loading Loading @@ -1175,16 +1228,48 @@ static u32 wl18xx_ap_get_mimo_wide_rate_mask(struct wl1271 *wl, } } static const char *wl18xx_rdl_name(enum wl18xx_rdl_num rdl_num) { switch (rdl_num) { case RDL_1_HP: return "183xH"; case RDL_2_SP: return "183x or 180x"; case RDL_3_HP: return "187xH"; case RDL_4_SP: return "187x"; case RDL_5_SP: return "RDL11 - Not Supported"; case RDL_6_SP: return "180xD"; case RDL_7_SP: return "RDL13 - Not Supported (1893Q)"; case RDL_8_SP: return "18xxQ"; case RDL_NONE: return "UNTRIMMED"; default: return "UNKNOWN"; } } static int wl18xx_get_pg_ver(struct wl1271 *wl, s8 *ver) { u32 fuse; s8 rom = 0, metal = 0, pg_ver = 0, rdl_ver = 0; s8 rom = 0, metal = 0, pg_ver = 0, rdl_ver = 0, package_type = 0; int ret; ret = wlcore_set_partition(wl, &wl->ptable[PART_TOP_PRCM_ELP_SOC]); if (ret < 0) goto out; ret = wlcore_read32(wl, WL18XX_REG_FUSE_DATA_2_3, &fuse); if (ret < 0) goto out; package_type = (fuse >> WL18XX_PACKAGE_TYPE_OFFSET) & 1; ret = wlcore_read32(wl, WL18XX_REG_FUSE_DATA_1_3, &fuse); if (ret < 0) goto out; Loading @@ -1192,7 +1277,7 @@ static int wl18xx_get_pg_ver(struct wl1271 *wl, s8 *ver) pg_ver = (fuse & WL18XX_PG_VER_MASK) >> WL18XX_PG_VER_OFFSET; rom = (fuse & WL18XX_ROM_VER_MASK) >> WL18XX_ROM_VER_OFFSET; if (rom <= 0xE) if ((rom <= 0xE) && (package_type == WL18XX_PACKAGE_TYPE_WSP)) metal = (fuse & WL18XX_METAL_VER_MASK) >> WL18XX_METAL_VER_OFFSET; else Loading @@ -1204,11 +1289,9 @@ static int wl18xx_get_pg_ver(struct wl1271 *wl, s8 *ver) goto out; rdl_ver = (fuse & WL18XX_RDL_VER_MASK) >> WL18XX_RDL_VER_OFFSET; if (rdl_ver > RDL_MAX) rdl_ver = RDL_NONE; wl1271_info("wl18xx HW: RDL %d, %s, PG %x.%x (ROM %x)", rdl_ver, rdl_names[rdl_ver], pg_ver, metal, rom); wl1271_info("wl18xx HW: %s, PG %d.%d (ROM 0x%x)", wl18xx_rdl_name(rdl_ver), pg_ver, metal, rom); if (ver) *ver = pg_ver; Loading
drivers/net/wireless/ti/wl18xx/reg.h +23 −10 Original line number Diff line number Diff line Loading @@ -114,6 +114,11 @@ #define PLATFORM_DETECTION 0xA0E3E0 #define OCS_EN 0xA02080 #define PRIMARY_CLK_DETECT 0xA020A6 #define PLLSH_COEX_PLL_N 0xA02384 #define PLLSH_COEX_PLL_M 0xA02382 #define PLLSH_COEX_PLL_SWALLOW_EN 0xA0238E #define PLLSH_WL_PLL_SEL 0xA02398 #define PLLSH_WCS_PLL_N 0xA02362 #define PLLSH_WCS_PLL_M 0xA02360 #define PLLSH_WCS_PLL_Q_FACTOR_CFG_1 0xA02364 Loading @@ -128,19 +133,30 @@ #define PLLSH_WCS_PLL_P_FACTOR_CFG_1_MASK 0xFFFF #define PLLSH_WCS_PLL_P_FACTOR_CFG_2_MASK 0x000F #define PLLSH_WL_PLL_EN_VAL1 0x7 #define PLLSH_WL_PLL_EN_VAL2 0x2 #define PLLSH_COEX_PLL_SWALLOW_EN_VAL1 0x2 #define PLLSH_COEX_PLL_SWALLOW_EN_VAL2 0x11 #define PLLSH_WCS_PLL_SWALLOW_EN_VAL1 0x1 #define PLLSH_WCS_PLL_SWALLOW_EN_VAL2 0x12 #define PLLSH_WL_PLL_SEL_WCS_PLL 0x0 #define PLLSH_WL_PLL_SEL_COEX_PLL 0x1 #define WL18XX_REG_FUSE_DATA_1_3 0xA0260C #define WL18XX_PG_VER_MASK 0x70 #define WL18XX_PG_VER_OFFSET 4 #define WL18XX_ROM_VER_MASK 0x3 #define WL18XX_ROM_VER_OFFSET 0 #define WL18XX_ROM_VER_MASK 0x3e00 #define WL18XX_ROM_VER_OFFSET 9 #define WL18XX_METAL_VER_MASK 0xC #define WL18XX_METAL_VER_OFFSET 2 #define WL18XX_NEW_METAL_VER_MASK 0x180 #define WL18XX_NEW_METAL_VER_OFFSET 7 #define WL18XX_PACKAGE_TYPE_OFFSET 13 #define WL18XX_PACKAGE_TYPE_WSP 0 #define WL18XX_REG_FUSE_DATA_2_3 0xA02614 #define WL18XX_RDL_VER_MASK 0x1f00 #define WL18XX_RDL_VER_OFFSET 8 Loading Loading @@ -201,24 +217,21 @@ enum { NUM_BOARD_TYPES, }; enum { enum wl18xx_rdl_num { RDL_NONE = 0, RDL_1_HP = 1, RDL_2_SP = 2, RDL_3_HP = 3, RDL_4_SP = 4, RDL_5_SP = 0x11, RDL_6_SP = 0x12, RDL_7_SP = 0x13, RDL_8_SP = 0x14, _RDL_LAST, RDL_MAX = _RDL_LAST - 1, }; static const char * const rdl_names[] = { [RDL_NONE] = "", [RDL_1_HP] = "1853 SISO", [RDL_2_SP] = "1857 MIMO", [RDL_3_HP] = "1893 SISO", [RDL_4_SP] = "1897 MIMO", }; /* FPGA_SPARE_1 register - used to change the PHY ATPG clock at boot time */ #define WL18XX_PHY_FPGA_SPARE_1 0x8093CA40 Loading
drivers/net/wireless/ti/wlcore/cmd.c +34 −24 Original line number Diff line number Diff line Loading @@ -1126,6 +1126,8 @@ int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, u16 template_id_2_4 = wl->scan_templ_id_2_4; u16 template_id_5 = wl->scan_templ_id_5; wl1271_debug(DEBUG_SCAN, "build probe request band %d", band); skb = ieee80211_probereq_get(wl->hw, vif, ssid, ssid_len, ie_len); if (!skb) { Loading @@ -1135,8 +1137,6 @@ int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, if (ie_len) memcpy(skb_put(skb, ie_len), ie, ie_len); wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", skb->data, skb->len); if (sched_scan && (wl->quirks & WLCORE_QUIRK_DUAL_PROBE_TMPL)) { template_id_2_4 = wl->sched_scan_templ_id_2_4; Loading Loading @@ -1172,7 +1172,7 @@ struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl, if (!skb) goto out; wl1271_dump(DEBUG_SCAN, "AP PROBE REQ: ", skb->data, skb->len); wl1271_debug(DEBUG_SCAN, "set ap probe request template"); rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[wlvif->band]); if (wlvif->band == IEEE80211_BAND_2GHZ) Loading Loading @@ -1607,33 +1607,43 @@ int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid) static int wlcore_get_reg_conf_ch_idx(enum ieee80211_band band, u16 ch) { int idx = -1; /* * map the given band/channel to the respective predefined * bit expected by the fw */ switch (band) { case IEEE80211_BAND_5GHZ: if (ch >= 8 && ch <= 16) idx = ((ch-8)/4 + 18); else if (ch >= 34 && ch <= 64) idx = ((ch-34)/2 + 3 + 18); else if (ch >= 100 && ch <= 140) idx = ((ch-100)/4 + 15 + 18); else if (ch >= 149 && ch <= 165) idx = ((ch-149)/4 + 26 + 18); else idx = -1; break; case IEEE80211_BAND_2GHZ: /* channels 1..14 are mapped to 0..13 */ if (ch >= 1 && ch <= 14) idx = ch - 1; else idx = -1; return ch - 1; break; case IEEE80211_BAND_5GHZ: switch (ch) { case 8 ... 16: /* channels 8,12,16 are mapped to 18,19,20 */ return 18 + (ch-8)/4; case 34 ... 48: /* channels 34,36..48 are mapped to 21..28 */ return 21 + (ch-34)/2; case 52 ... 64: /* channels 52,56..64 are mapped to 29..32 */ return 29 + (ch-52)/4; case 100 ... 140: /* channels 100,104..140 are mapped to 33..43 */ return 33 + (ch-100)/4; case 149 ... 165: /* channels 149,153..165 are mapped to 44..48 */ return 44 + (ch-149)/4; default: wl1271_error("get reg conf ch idx - unknown band: %d", (int)band); break; } break; default: break; } return idx; wl1271_error("%s: unknown band/channel: %d/%d", __func__, band, ch); return -1; } void wlcore_set_pending_regdomain_ch(struct wl1271 *wl, u16 channel, Loading @@ -1646,7 +1656,7 @@ void wlcore_set_pending_regdomain_ch(struct wl1271 *wl, u16 channel, ch_bit_idx = wlcore_get_reg_conf_ch_idx(band, channel); if (ch_bit_idx > 0 && ch_bit_idx <= WL1271_MAX_CHANNELS) if (ch_bit_idx >= 0 && ch_bit_idx <= WL1271_MAX_CHANNELS) set_bit(ch_bit_idx, (long *)wl->reg_ch_conf_pending); } Loading
drivers/net/wireless/ti/wlcore/main.c +131 −25 Original line number Diff line number Diff line Loading @@ -1062,7 +1062,8 @@ int wl1271_plt_start(struct wl1271 *wl, const enum plt_mode plt_mode) static const char* const PLT_MODE[] = { "PLT_OFF", "PLT_ON", "PLT_FEM_DETECT" "PLT_FEM_DETECT", "PLT_CHIP_AWAKE" }; int ret; Loading @@ -1088,9 +1089,11 @@ int wl1271_plt_start(struct wl1271 *wl, const enum plt_mode plt_mode) if (ret < 0) goto power_off; if (plt_mode != PLT_CHIP_AWAKE) { ret = wl->ops->plt_init(wl); if (ret < 0) goto power_off; } wl->state = WLCORE_STATE_ON; wl1271_notice("firmware booted in PLT mode %s (%s)", Loading Loading @@ -2008,6 +2011,47 @@ static void wlcore_connection_loss_work(struct work_struct *work) mutex_unlock(&wl->mutex); } static void wlcore_pending_auth_complete_work(struct work_struct *work) { struct delayed_work *dwork; struct wl1271 *wl; struct wl12xx_vif *wlvif; unsigned long time_spare; int ret; dwork = container_of(work, struct delayed_work, work); wlvif = container_of(dwork, struct wl12xx_vif, pending_auth_complete_work); wl = wlvif->wl; mutex_lock(&wl->mutex); if (unlikely(wl->state != WLCORE_STATE_ON)) goto out; /* * Make sure a second really passed since the last auth reply. Maybe * a second auth reply arrived while we were stuck on the mutex. * Check for a little less than the timeout to protect from scheduler * irregularities. */ time_spare = jiffies + msecs_to_jiffies(WLCORE_PEND_AUTH_ROC_TIMEOUT - 50); if (!time_after(time_spare, wlvif->pending_auth_reply_time)) goto out; ret = wl1271_ps_elp_wakeup(wl); if (ret < 0) goto out; /* cancel the ROC if active */ wlcore_update_inconn_sta(wl, wlvif, NULL, false); wl1271_ps_elp_sleep(wl); out: mutex_unlock(&wl->mutex); } static int wl12xx_allocate_rate_policy(struct wl1271 *wl, u8 *idx) { u8 policy = find_first_zero_bit(wl->rate_policies_map, Loading Loading @@ -2159,6 +2203,8 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif) wlcore_channel_switch_work); INIT_DELAYED_WORK(&wlvif->connection_loss_work, wlcore_connection_loss_work); INIT_DELAYED_WORK(&wlvif->pending_auth_complete_work, wlcore_pending_auth_complete_work); INIT_LIST_HEAD(&wlvif->list); setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer, Loading Loading @@ -2376,6 +2422,11 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, int ret = 0; u8 role_type; if (wl->plt) { wl1271_error("Adding Interface not allowed while in PLT mode"); return -EBUSY; } vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER | IEEE80211_VIF_SUPPORTS_CQM_RSSI; Loading Loading @@ -2590,6 +2641,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, cancel_work_sync(&wlvif->rx_streaming_disable_work); cancel_delayed_work_sync(&wlvif->connection_loss_work); cancel_delayed_work_sync(&wlvif->channel_switch_work); cancel_delayed_work_sync(&wlvif->pending_auth_complete_work); mutex_lock(&wl->mutex); } Loading Loading @@ -2875,6 +2927,25 @@ static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif) wlvif->rate_set = wlvif->basic_rate_set; } static void wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif, bool idle) { bool cur_idle = !test_bit(WLVIF_FLAG_ACTIVE, &wlvif->flags); if (idle == cur_idle) return; if (idle) { clear_bit(WLVIF_FLAG_ACTIVE, &wlvif->flags); } else { /* The current firmware only supports sched_scan in idle */ if (wl->sched_vif == wlvif) wl->ops->sched_scan_stop(wl, wlvif); set_bit(WLVIF_FLAG_ACTIVE, &wlvif->flags); } } static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif, struct ieee80211_conf *conf, u32 changed) { Loading Loading @@ -3969,6 +4040,13 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl, } } else { if (test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) { /* * AP might be in ROC in case we have just * sent auth reply. handle it. */ if (test_bit(wlvif->role_id, wl->roc_map)) wl12xx_croc(wl, wlvif->role_id); ret = wl12xx_cmd_role_stop_ap(wl, wlvif); if (ret < 0) goto out; Loading Loading @@ -4120,6 +4198,9 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, do_join = true; } if (changed & BSS_CHANGED_IDLE && !is_ibss) wl1271_sta_handle_idle(wl, wlvif, bss_conf->idle); if (changed & BSS_CHANGED_CQM) { bool enable = false; if (bss_conf->cqm_rssi_thold) Loading Loading @@ -4656,28 +4737,48 @@ static void wlcore_roc_if_possible(struct wl1271 *wl, wl12xx_roc(wl, wlvif, wlvif->role_id, wlvif->band, wlvif->channel); } static void wlcore_update_inconn_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, struct wl1271_station *wl_sta, bool in_connection) /* * when wl_sta is NULL, we treat this call as if coming from a * pending auth reply. * wl->mutex must be taken and the FW must be awake when the call * takes place. */ void wlcore_update_inconn_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, struct wl1271_station *wl_sta, bool in_conn) { if (in_connection) { if (WARN_ON(wl_sta->in_connection)) if (in_conn) { if (WARN_ON(wl_sta && wl_sta->in_connection)) return; wl_sta->in_connection = true; if (!wlvif->inconn_count++) if (!wlvif->ap_pending_auth_reply && !wlvif->inconn_count) wlcore_roc_if_possible(wl, wlvif); if (wl_sta) { wl_sta->in_connection = true; wlvif->inconn_count++; } else { wlvif->ap_pending_auth_reply = true; } } else { if (!wl_sta->in_connection) if (wl_sta && !wl_sta->in_connection) return; if (WARN_ON(!wl_sta && !wlvif->ap_pending_auth_reply)) return; if (WARN_ON(wl_sta && !wlvif->inconn_count)) return; if (wl_sta) { wl_sta->in_connection = false; wlvif->inconn_count--; if (WARN_ON(wlvif->inconn_count < 0)) return; } else { wlvif->ap_pending_auth_reply = false; } if (!wlvif->inconn_count) if (test_bit(wlvif->role_id, wl->roc_map)) if (!wlvif->inconn_count && !wlvif->ap_pending_auth_reply && test_bit(wlvif->role_id, wl->roc_map)) wl12xx_croc(wl, wlvif->role_id); } } Loading Loading @@ -5313,10 +5414,7 @@ static struct ieee80211_rate wl1271_rates_5ghz[] = { /* 5 GHz band channels for WL1273 */ static struct ieee80211_channel wl1271_channels_5ghz[] = { { .hw_value = 7, .center_freq = 5035, .max_power = WLCORE_MAX_TXPWR }, { .hw_value = 8, .center_freq = 5040, .max_power = WLCORE_MAX_TXPWR }, { .hw_value = 9, .center_freq = 5045, .max_power = WLCORE_MAX_TXPWR }, { .hw_value = 11, .center_freq = 5055, .max_power = WLCORE_MAX_TXPWR }, { .hw_value = 12, .center_freq = 5060, .max_power = WLCORE_MAX_TXPWR }, { .hw_value = 16, .center_freq = 5080, .max_power = WLCORE_MAX_TXPWR }, { .hw_value = 34, .center_freq = 5170, .max_power = WLCORE_MAX_TXPWR }, Loading Loading @@ -5896,6 +5994,11 @@ static const struct wiphy_wowlan_support wlcore_wowlan_support = { }; #endif static irqreturn_t wlcore_hardirq(int irq, void *cookie) { return IRQ_WAKE_THREAD; } static void wlcore_nvs_cb(const struct firmware *fw, void *context) { struct wl1271 *wl = context; Loading @@ -5904,6 +6007,7 @@ static void wlcore_nvs_cb(const struct firmware *fw, void *context) struct wl12xx_platform_data *pdata = pdev_data->pdata; unsigned long irqflags; int ret; irq_handler_t hardirq_fn = NULL; if (fw) { wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL); Loading Loading @@ -5932,12 +6036,14 @@ static void wlcore_nvs_cb(const struct firmware *fw, void *context) wl->platform_quirks = pdata->platform_quirks; wl->if_ops = pdev_data->if_ops; if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ) if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ) { irqflags = IRQF_TRIGGER_RISING; else hardirq_fn = wlcore_hardirq; } else { irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT; } ret = request_threaded_irq(wl->irq, NULL, wlcore_irq, ret = request_threaded_irq(wl->irq, hardirq_fn, wlcore_irq, irqflags, pdev->name, wl); if (ret < 0) { wl1271_error("request_irq() failed: %d", ret); Loading
drivers/net/wireless/ti/wlcore/ps.c +4 −0 Original line number Diff line number Diff line Loading @@ -83,6 +83,10 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl) struct wl12xx_vif *wlvif; u32 timeout; /* We do not enter elp sleep in PLT mode */ if (wl->plt) return; if (wl->sleep_auth != WL1271_PSM_ELP) return; Loading