Commit 916ef361 authored by Luciano Coelho's avatar Luciano Coelho

Merge branch 'wl12xx-next' into for-linville

parents e66a8ddf 6bac40a6
...@@ -6660,6 +6660,16 @@ L: alsa-devel@alsa-project.org (moderated for non-subscribers) ...@@ -6660,6 +6660,16 @@ L: alsa-devel@alsa-project.org (moderated for non-subscribers)
S: Maintained S: Maintained
F: sound/soc/codecs/twl4030* F: sound/soc/codecs/twl4030*
TI WILINK WIRELESS DRIVERS
M: Luciano Coelho <coelho@ti.com>
L: linux-wireless@vger.kernel.org
W: http://wireless.kernel.org/en/users/Drivers/wl12xx
W: http://wireless.kernel.org/en/users/Drivers/wl1251
T: git git://git.kernel.org/pub/scm/linux/kernel/git/luca/wl12xx.git
S: Maintained
F: drivers/net/wireless/ti/
F: include/linux/wl12xx.h
TIPC NETWORK LAYER TIPC NETWORK LAYER
M: Jon Maloy <jon.maloy@ericsson.com> M: Jon Maloy <jon.maloy@ericsson.com>
M: Allan Stephens <allan.stephens@windriver.com> M: Allan Stephens <allan.stephens@windriver.com>
...@@ -7416,23 +7426,6 @@ M: Miloslav Trmac <mitr@volny.cz> ...@@ -7416,23 +7426,6 @@ M: Miloslav Trmac <mitr@volny.cz>
S: Maintained S: Maintained
F: drivers/input/misc/wistron_btns.c F: drivers/input/misc/wistron_btns.c
WL1251 WIRELESS DRIVER
M: Luciano Coelho <coelho@ti.com>
L: linux-wireless@vger.kernel.org
W: http://wireless.kernel.org/en/users/Drivers/wl1251
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
S: Maintained
F: drivers/net/wireless/wl1251/*
WL1271 WIRELESS DRIVER
M: Luciano Coelho <coelho@ti.com>
L: linux-wireless@vger.kernel.org
W: http://wireless.kernel.org/en/users/Drivers/wl12xx
T: git git://git.kernel.org/pub/scm/linux/kernel/git/luca/wl12xx.git
S: Maintained
F: drivers/net/wireless/wl12xx/
F: include/linux/wl12xx.h
WL3501 WIRELESS PCMCIA CARD DRIVER WL3501 WIRELESS PCMCIA CARD DRIVER
M: Arnaldo Carvalho de Melo <acme@ghostprotocols.net> M: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
L: linux-wireless@vger.kernel.org L: linux-wireless@vger.kernel.org
......
...@@ -282,8 +282,7 @@ source "drivers/net/wireless/orinoco/Kconfig" ...@@ -282,8 +282,7 @@ source "drivers/net/wireless/orinoco/Kconfig"
source "drivers/net/wireless/p54/Kconfig" source "drivers/net/wireless/p54/Kconfig"
source "drivers/net/wireless/rt2x00/Kconfig" source "drivers/net/wireless/rt2x00/Kconfig"
source "drivers/net/wireless/rtlwifi/Kconfig" source "drivers/net/wireless/rtlwifi/Kconfig"
source "drivers/net/wireless/wl1251/Kconfig" source "drivers/net/wireless/ti/Kconfig"
source "drivers/net/wireless/wl12xx/Kconfig"
source "drivers/net/wireless/zd1211rw/Kconfig" source "drivers/net/wireless/zd1211rw/Kconfig"
source "drivers/net/wireless/mwifiex/Kconfig" source "drivers/net/wireless/mwifiex/Kconfig"
......
...@@ -51,9 +51,7 @@ obj-$(CONFIG_ATH_COMMON) += ath/ ...@@ -51,9 +51,7 @@ obj-$(CONFIG_ATH_COMMON) += ath/
obj-$(CONFIG_MAC80211_HWSIM) += mac80211_hwsim.o obj-$(CONFIG_MAC80211_HWSIM) += mac80211_hwsim.o
obj-$(CONFIG_WL1251) += wl1251/ obj-$(CONFIG_WL_TI) += ti/
obj-$(CONFIG_WL12XX) += wl12xx/
obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx/
obj-$(CONFIG_IWM) += iwmc3200wifi/ obj-$(CONFIG_IWM) += iwmc3200wifi/
......
menuconfig WL_TI
bool "TI Wireless LAN support"
---help---
This section contains support for all the wireless drivers
for Texas Instruments WLAN chips, such as wl1251 and the wl12xx
family.
if WL_TI
source "drivers/net/wireless/ti/wl1251/Kconfig"
source "drivers/net/wireless/ti/wl12xx/Kconfig"
# keep last for automatic dependencies
source "drivers/net/wireless/ti/wlcore/Kconfig"
endif # WL_TI
obj-$(CONFIG_WLCORE) += wlcore/
obj-$(CONFIG_WL12XX) += wl12xx/
obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wlcore/
obj-$(CONFIG_WL1251) += wl1251/
config WL12XX
tristate "TI wl12xx support"
select WLCORE
---help---
This module adds support for wireless adapters based on TI wl1271,
wl1273, wl1281 and wl1283 chipsets. This module does *not* include
support for wl1251. For wl1251 support, use the separate homonymous
driver instead.
wl12xx-objs = main.o cmd.o acx.o
obj-$(CONFIG_WL12XX) += wl12xx.o
/*
* This file is part of wl12xx
*
* Copyright (C) 2008-2009 Nokia Corporation
* Copyright (C) 2011 Texas Instruments Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#include "../wlcore/cmd.h"
#include "../wlcore/debug.h"
#include "../wlcore/acx.h"
#include "acx.h"
int wl1271_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap)
{
struct wl1271_acx_host_config_bitmap *bitmap_conf;
int ret;
bitmap_conf = kzalloc(sizeof(*bitmap_conf), GFP_KERNEL);
if (!bitmap_conf) {
ret = -ENOMEM;
goto out;
}
bitmap_conf->host_cfg_bitmap = cpu_to_le32(host_cfg_bitmap);
ret = wl1271_cmd_configure(wl, ACX_HOST_IF_CFG_BITMAP,
bitmap_conf, sizeof(*bitmap_conf));
if (ret < 0) {
wl1271_warning("wl1271 bitmap config opt failed: %d", ret);
goto out;
}
out:
kfree(bitmap_conf);
return ret;
}
/*
* This file is part of wl12xx
*
* Copyright (C) 1998-2009, 2011 Texas Instruments. All rights reserved.
* Copyright (C) 2008-2010 Nokia Corporation
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#ifndef __WL12XX_ACX_H__
#define __WL12XX_ACX_H__
#include "../wlcore/wlcore.h"
struct wl1271_acx_host_config_bitmap {
struct acx_header header;
__le32 host_cfg_bitmap;
} __packed;
int wl1271_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap);
#endif /* __WL12XX_ACX_H__ */
/*
* This file is part of wl12xx
*
* Copyright (C) 2009-2010 Nokia Corporation
* Copyright (C) 2011 Texas Instruments Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#include "../wlcore/cmd.h"
#include "../wlcore/debug.h"
#include "wl12xx.h"
#include "cmd.h"
int wl1271_cmd_ext_radio_parms(struct wl1271 *wl)
{
struct wl1271_ext_radio_parms_cmd *ext_radio_parms;
struct wl12xx_priv *priv = wl->priv;
struct wl12xx_conf_rf *rf = &priv->conf.rf;
int ret;
if (!wl->nvs)
return -ENODEV;
ext_radio_parms = kzalloc(sizeof(*ext_radio_parms), GFP_KERNEL);
if (!ext_radio_parms)
return -ENOMEM;
ext_radio_parms->test.id = TEST_CMD_INI_FILE_RF_EXTENDED_PARAM;
memcpy(ext_radio_parms->tx_per_channel_power_compensation_2,
rf->tx_per_channel_power_compensation_2,
CONF_TX_PWR_COMPENSATION_LEN_2);
memcpy(ext_radio_parms->tx_per_channel_power_compensation_5,
rf->tx_per_channel_power_compensation_5,
CONF_TX_PWR_COMPENSATION_LEN_5);
wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_EXT_RADIO_PARAM: ",
ext_radio_parms, sizeof(*ext_radio_parms));
ret = wl1271_cmd_test(wl, ext_radio_parms, sizeof(*ext_radio_parms), 0);
if (ret < 0)
wl1271_warning("TEST_CMD_INI_FILE_RF_EXTENDED_PARAM failed");
kfree(ext_radio_parms);
return ret;
}
int wl1271_cmd_general_parms(struct wl1271 *wl)
{
struct wl1271_general_parms_cmd *gen_parms;
struct wl1271_ini_general_params *gp =
&((struct wl1271_nvs_file *)wl->nvs)->general_params;
bool answer = false;
int ret;
if (!wl->nvs)
return -ENODEV;
if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) {
wl1271_warning("FEM index from INI out of bounds");
return -EINVAL;
}
gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL);
if (!gen_parms)
return -ENOMEM;
gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM;
memcpy(&gen_parms->general_params, gp, sizeof(*gp));
if (gp->tx_bip_fem_auto_detect)
answer = true;
/* Override the REF CLK from the NVS with the one from platform data */
gen_parms->general_params.ref_clock = wl->ref_clock;
ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer);
if (ret < 0) {
wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed");
goto out;
}
gp->tx_bip_fem_manufacturer =
gen_parms->general_params.tx_bip_fem_manufacturer;
if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) {
wl1271_warning("FEM index from FW out of bounds");
ret = -EINVAL;
goto out;
}
wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n",
answer ? "auto" : "manual", gp->tx_bip_fem_manufacturer);
out:
kfree(gen_parms);
return ret;
}
int wl128x_cmd_general_parms(struct wl1271 *wl)
{
struct wl128x_general_parms_cmd *gen_parms;
struct wl128x_ini_general_params *gp =
&((struct wl128x_nvs_file *)wl->nvs)->general_params;
bool answer = false;
int ret;
if (!wl->nvs)
return -ENODEV;
if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) {
wl1271_warning("FEM index from ini out of bounds");
return -EINVAL;
}
gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL);
if (!gen_parms)
return -ENOMEM;
gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM;
memcpy(&gen_parms->general_params, gp, sizeof(*gp));
if (gp->tx_bip_fem_auto_detect)
answer = true;
/* Replace REF and TCXO CLKs with the ones from platform data */
gen_parms->general_params.ref_clock = wl->ref_clock;
gen_parms->general_params.tcxo_ref_clock = wl->tcxo_clock;
ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer);
if (ret < 0) {
wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed");
goto out;
}
gp->tx_bip_fem_manufacturer =
gen_parms->general_params.tx_bip_fem_manufacturer;
if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) {
wl1271_warning("FEM index from FW out of bounds");
ret = -EINVAL;
goto out;
}
wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n",
answer ? "auto" : "manual", gp->tx_bip_fem_manufacturer);
out:
kfree(gen_parms);
return ret;
}
int wl1271_cmd_radio_parms(struct wl1271 *wl)
{
struct wl1271_nvs_file *nvs = (struct wl1271_nvs_file *)wl->nvs;
struct wl1271_radio_parms_cmd *radio_parms;
struct wl1271_ini_general_params *gp = &nvs->general_params;
int ret;
if (!wl->nvs)
return -ENODEV;
radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL);
if (!radio_parms)
return -ENOMEM;
radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM;
/* 2.4GHz parameters */
memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2,
sizeof(struct wl1271_ini_band_params_2));
memcpy(&radio_parms->dyn_params_2,
&nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params,
sizeof(struct wl1271_ini_fem_params_2));
/* 5GHz parameters */
memcpy(&radio_parms->static_params_5,
&nvs->stat_radio_params_5,
sizeof(struct wl1271_ini_band_params_5));
memcpy(&radio_parms->dyn_params_5,
&nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params,
sizeof(struct wl1271_ini_fem_params_5));
wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ",
radio_parms, sizeof(*radio_parms));
ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0);
if (ret < 0)
wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed");
kfree(radio_parms);
return ret;
}
int wl128x_cmd_radio_parms(struct wl1271 *wl)
{
struct wl128x_nvs_file *nvs = (struct wl128x_nvs_file *)wl->nvs;
struct wl128x_radio_parms_cmd *radio_parms;
struct wl128x_ini_general_params *gp = &nvs->general_params;
int ret;
if (!wl->nvs)
return -ENODEV;
radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL);
if (!radio_parms)
return -ENOMEM;
radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM;
/* 2.4GHz parameters */
memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2,
sizeof(struct wl128x_ini_band_params_2));
memcpy(&radio_parms->dyn_params_2,
&nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params,
sizeof(struct wl128x_ini_fem_params_2));
/* 5GHz parameters */
memcpy(&radio_parms->static_params_5,
&nvs->stat_radio_params_5,
sizeof(struct wl128x_ini_band_params_5));
memcpy(&radio_parms->dyn_params_5,
&nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params,
sizeof(struct wl128x_ini_fem_params_5));
radio_parms->fem_vendor_and_options = nvs->fem_vendor_and_options;
wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ",
radio_parms, sizeof(*radio_parms));
ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0);
if (ret < 0)
wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed");
kfree(radio_parms);
return ret;
}
/*
* This file is part of wl12xx
*
* Copyright (C) 1998-2009, 2011 Texas Instruments. All rights reserved.
* Copyright (C) 2009 Nokia Corporation
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#ifndef __WL12XX_CMD_H__
#define __WL12XX_CMD_H__
#include "conf.h"
#define TEST_CMD_INI_FILE_RADIO_PARAM 0x19
#define TEST_CMD_INI_FILE_GENERAL_PARAM 0x1E
struct wl1271_general_parms_cmd {
struct wl1271_cmd_header header;
struct wl1271_cmd_test_header test;
struct wl1271_ini_general_params general_params;
u8 sr_debug_table[WL1271_INI_MAX_SMART_REFLEX_PARAM];
u8 sr_sen_n_p;
u8 sr_sen_n_p_gain;
u8 sr_sen_nrn;
u8 sr_sen_prn;
u8 padding[3];
} __packed;
struct wl128x_general_parms_cmd {
struct wl1271_cmd_header header;
struct wl1271_cmd_test_header test;
struct wl128x_ini_general_params general_params;
u8 sr_debug_table[WL1271_INI_MAX_SMART_REFLEX_PARAM];
u8 sr_sen_n_p;
u8 sr_sen_n_p_gain;
u8 sr_sen_nrn;
u8 sr_sen_prn;
u8 padding[3];
} __packed;
struct wl1271_radio_parms_cmd {
struct wl1271_cmd_header header;
struct wl1271_cmd_test_header test;
/* Static radio parameters */
struct wl1271_ini_band_params_2 static_params_2;
struct wl1271_ini_band_params_5 static_params_5;
/* Dynamic radio parameters */
struct wl1271_ini_fem_params_2 dyn_params_2;
u8 padding2;
struct wl1271_ini_fem_params_5 dyn_params_5;
u8 padding3[2];
} __packed;
struct wl128x_radio_parms_cmd {
struct wl1271_cmd_header header;
struct wl1271_cmd_test_header test;
/* Static radio parameters */
struct wl128x_ini_band_params_2 static_params_2;
struct wl128x_ini_band_params_5 static_params_5;
u8 fem_vendor_and_options;
/* Dynamic radio parameters */
struct wl128x_ini_fem_params_2 dyn_params_2;
u8 padding2;
struct wl128x_ini_fem_params_5 dyn_params_5;
} __packed;
#define TEST_CMD_INI_FILE_RF_EXTENDED_PARAM 0x26
struct wl1271_ext_radio_parms_cmd {
struct wl1271_cmd_header header;
struct wl1271_cmd_test_header test;
u8 tx_per_channel_power_compensation_2[CONF_TX_PWR_COMPENSATION_LEN_2];
u8 tx_per_channel_power_compensation_5[CONF_TX_PWR_COMPENSATION_LEN_5];
u8 padding[3];
} __packed;
int wl1271_cmd_general_parms(struct wl1271 *wl);
int wl128x_cmd_general_parms(struct wl1271 *wl);
int wl1271_cmd_radio_parms(struct wl1271 *wl);
int wl128x_cmd_radio_parms(struct wl1271 *wl);
int wl1271_cmd_ext_radio_parms(struct wl1271 *wl);
#endif /* __WL12XX_CMD_H__ */
/*
* This file is part of wl12xx
*
* Copyright (C) 2011 Texas Instruments Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#ifndef __WL12XX_CONF_H__
#define __WL12XX_CONF_H__
/* these are number of channels on the band divided by two, rounded up */
#define CONF_TX_PWR_COMPENSATION_LEN_2 7
#define CONF_TX_PWR_COMPENSATION_LEN_5 18
struct wl12xx_conf_rf {
/*
* Per channel power compensation for 2.4GHz
*
* Range: s8
*/
u8 tx_per_channel_power_compensation_2[CONF_TX_PWR_COMPENSATION_LEN_2];
/*
* Per channel power compensation for 5GHz
*
* Range: s8
*/
u8 tx_per_channel_power_compensation_5[CONF_TX_PWR_COMPENSATION_LEN_5];
};
struct wl12xx_priv_conf {
struct wl12xx_conf_rf rf;
struct conf_memory_settings mem_wl127x;
};
#endif /* __WL12XX_CONF_H__ */
/*
* This file is part of wl1271
*
* Copyright (C) 2008-2010 Nokia Corporation
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/err.h>
#include <linux/wl12xx.h>
#include "../wlcore/wlcore.h"
#include "../wlcore/debug.h"
#include "../wlcore/io.h"
#include "../wlcore/acx.h"
#include "../wlcore/tx.h"
#include "../wlcore/rx.h"
#include "../wlcore/io.h"
#include "../wlcore/boot.h"
#include "wl12xx.h"
#include "reg.h"
#include "cmd.h"
#include "acx.h"
static struct wlcore_conf wl12xx_conf = {
.sg = {
.params = {
[CONF_SG_ACL_BT_MASTER_MIN_BR] = 10,
[CONF_SG_ACL_BT_MASTER_MAX_BR] = 180,
[CONF_SG_ACL_BT_SLAVE_MIN_BR] = 10,
[CONF_SG_ACL_BT_SLAVE_MAX_BR] = 180,
[CONF_SG_ACL_BT_MASTER_MIN_EDR] = 10,
[CONF_SG_ACL_BT_MASTER_MAX_EDR] = 80,
[CONF_SG_ACL_BT_SLAVE_MIN_EDR] = 10,
[CONF_SG_ACL_BT_SLAVE_MAX_EDR] = 80,
[CONF_SG_ACL_WLAN_PS_MASTER_BR] = 8,
[CONF_SG_ACL_WLAN_PS_SLAVE_BR] = 8,
[CONF_SG_ACL_WLAN_PS_MASTER_EDR] = 20,
[CONF_SG_ACL_WLAN_PS_SLAVE_EDR] = 20,
[CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR] = 20,
[CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR] = 35,
[CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR] = 16,
[CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR] = 35,
[CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR] = 32,
[CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR] = 50,
[CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR] = 28,
[CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR] = 50,
[CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR] = 10,
[CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR] = 20,
[CONF_SG_ACL_PASSIVE_SCAN_BT_BR] = 75,
[CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR] = 15,
[CONF_SG_ACL_PASSIVE_SCAN_BT_EDR] = 27,
[CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR] = 17,
/* active scan params */
[CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
[CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
[CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
/* passive scan params */
[CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR] = 800,
[CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR] = 200,
[CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
/* passive scan in dual antenna params */
[CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0,
[CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN] = 0,
[CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN] = 0,
/* general params */
[CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1,
[CONF_SG_ANTENNA_CONFIGURATION] = 0,
[CONF_SG_BEACON_MISS_PERCENT] = 60,
[CONF_SG_DHCP_TIME] = 5000,
[CONF_SG_RXT] = 1200,
[CONF_SG_TXT] = 1000,
[CONF_SG_ADAPTIVE_RXT_TXT] = 1,
[CONF_SG_GENERAL_USAGE_BIT_MAP] = 3,
[CONF_SG_HV3_MAX_SERVED] = 6,
[CONF_SG_PS_POLL_TIMEOUT] = 10,
[CONF_SG_UPSD_TIMEOUT] = 10,
[CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2,
[CONF_SG_STA_RX_WINDOW_AFTER_DTIM] = 5,
[CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 30,
/* AP params */
[CONF_AP_BEACON_MISS_TX] = 3,
[CONF_AP_RX_WINDOW_AFTER_BEACON] = 10,
[CONF_AP_BEACON_WINDOW_INTERVAL] = 2,
[CONF_AP_CONNECTION_PROTECTION_TIME] = 0,
[CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25,
[CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25,
/* CTS Diluting params */
[CONF_SG_CTS_DILUTED_BAD_RX_PACKETS_TH] = 0,
[CONF_SG_CTS_CHOP_IN_DUAL_ANT_SCO_MASTER] = 0,
},
.state = CONF_SG_PROTECTIVE,
},
.rx = {
.rx_msdu_life_time = 512000,
.packet_detection_threshold = 0,
.ps_poll_timeout = 15,
.upsd_timeout = 15,
.rts_threshold = IEEE80211_MAX_RTS_THRESHOLD,
.rx_cca_threshold = 0,
.irq_blk_threshold = 0xFFFF,
.irq_pkt_threshold = 0,
.irq_timeout = 600,
.queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
},
.tx = {
.tx_energy_detection = 0,
.sta_rc_conf = {
.enabled_rates = 0,
.short_retry_limit = 10,
.long_retry_limit = 10,
.aflags = 0,
},
.ac_conf_count = 4,
.ac_conf = {
[CONF_TX_AC_BE] = {
.ac = CONF_TX_AC_BE,
.cw_min = 15,
.cw_max = 63,
.aifsn = 3,
.tx_op_limit = 0,
},
[CONF_TX_AC_BK] = {
.ac = CONF_TX_AC_BK,
.cw_min = 15,
.cw_max = 63,
.aifsn = 7,
.tx_op_limit = 0,
},
[CONF_TX_AC_VI] = {
.ac = CONF_TX_AC_VI,
.cw_min = 15,
.cw_max = 63,
.aifsn = CONF_TX_AIFS_PIFS,
.tx_op_limit = 3008,
},
[CONF_TX_AC_VO] = {
.ac = CONF_TX_AC_VO,
.cw_min = 15,
.cw_max = 63,
.aifsn = CONF_TX_AIFS_PIFS,
.tx_op_limit = 1504,
},
},
.max_tx_retries = 100,
.ap_aging_period = 300,
.tid_conf_count = 4,
.tid_conf = {
[CONF_TX_AC_BE] = {
.queue_id = CONF_TX_AC_BE,
.channel_type = CONF_CHANNEL_TYPE_EDCF,
.tsid = CONF_TX_AC_BE,
.ps_scheme = CONF_PS_SCHEME_LEGACY,
.ack_policy = CONF_ACK_POLICY_LEGACY,
.apsd_conf = {0, 0},
},
[CONF_TX_AC_BK] = {
.queue_id = CONF_TX_AC_BK,
.channel_type = CONF_CHANNEL_TYPE_EDCF,
.tsid = CONF_TX_AC_BK,
.ps_scheme = CONF_PS_SCHEME_LEGACY,
.ack_policy = CONF_ACK_POLICY_LEGACY,
.apsd_conf = {0, 0},
},
[CONF_TX_AC_VI] = {
.queue_id = CONF_TX_AC_VI,
.channel_type = CONF_CHANNEL_TYPE_EDCF,
.tsid = CONF_TX_AC_VI,
.ps_scheme = CONF_PS_SCHEME_LEGACY,
.ack_policy = CONF_ACK_POLICY_LEGACY,
.apsd_conf = {0, 0},
},
[CONF_TX_AC_VO] = {
.queue_id = CONF_TX_AC_VO,
.channel_type = CONF_CHANNEL_TYPE_EDCF,
.tsid = CONF_TX_AC_VO,
.ps_scheme = CONF_PS_SCHEME_LEGACY,
.ack_policy = CONF_ACK_POLICY_LEGACY,
.apsd_conf = {0, 0},
},
},
.frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
.tx_compl_timeout = 700,
.tx_compl_threshold = 4,
.basic_rate = CONF_HW_BIT_RATE_1MBPS,
.basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
.tmpl_short_retry_limit = 10,
.tmpl_long_retry_limit = 10,
.tx_watchdog_timeout = 5000,
},
.conn = {
.wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
.listen_interval = 1,
.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 = {
[0] = {
.ie = WLAN_EID_CHANNEL_SWITCH,
.rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
},
[1] = {
.ie = WLAN_EID_HT_OPERATION,
.rule = CONF_BCN_RULE_PASS_ON_CHANGE,
},
},
.synch_fail_thold = 10,
.bss_lose_timeout = 100,
.beacon_rx_timeout = 10000,
.broadcast_timeout = 20000,
.rx_broadcast_in_ps = 1,
.ps_poll_threshold = 10,
.bet_enable = CONF_BET_MODE_ENABLE,
.bet_max_consecutive = 50,
.psm_entry_retries = 8,
.psm_exit_retries = 16,
.psm_entry_nullfunc_retries = 3,
.dynamic_ps_timeout = 40,
.forced_ps = false,
.keep_alive_interval = 55000,
.max_listen_interval = 20,
},
.itrim = {
.enable = false,
.timeout = 50000,
},
.pm_config = {
.host_clk_settling_time = 5000,
.host_fast_wakeup_support = false
},
.roam_trigger = {
.trigger_pacing = 1,
.avg_weight_rssi_beacon = 20,
.avg_weight_rssi_data = 10,
.avg_weight_snr_beacon = 20,
.avg_weight_snr_data = 10,
},
.scan = {
.min_dwell_time_active = 7500,
.max_dwell_time_active = 30000,
.min_dwell_time_passive = 100000,
.max_dwell_time_passive = 100000,
.num_probe_reqs = 2,
.split_scan_timeout = 50000,
},
.sched_scan = {
/*
* Values are in TU/1000 but since sched scan FW command
* params are in TUs rounding up may occur.
*/
.base_dwell_time = 7500,
.max_dwell_time_delta = 22500,
/* based on 250bits per probe @1Mbps */
.dwell_time_delta_per_probe = 2000,
/* based on 250bits per probe @6Mbps (plus a bit more) */
.dwell_time_delta_per_probe_5 = 350,
.dwell_time_passive = 100000,
.dwell_time_dfs = 150000,
.num_probe_reqs = 2,
.rssi_threshold = -90,
.snr_threshold = 0,
},
.ht = {
.rx_ba_win_size = 8,
.tx_ba_win_size = 64,
.inactivity_timeout = 10000,
.tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP,
},
/*
* Memory config for wl127x chips is given in the
* wl12xx_default_priv_conf struct. The below configuration is
* for wl128x chips.
*/
.mem = {
.num_stations = 1,
.ssid_profiles = 1,
.rx_block_num = 40,
.tx_min_block_num = 40,
.dynamic_memory = 1,
.min_req_tx_blocks = 45,
.min_req_rx_blocks = 22,
.tx_min = 27,
},
.fm_coex = {
.enable = true,
.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 */
.coex_pll_stabilization_time = 0xffffffff, /* default */
.ldo_stabilization_time = 0xffff, /* default */
.fm_disturbed_band_margin = 0xff, /* default */
.swallow_clk_diff = 0xff, /* default */
},
.rx_streaming = {
.duration = 150,
.queues = 0x1,
.interval = 20,
.always = 0,
},
.fwlog = {
.mode = WL12XX_FWLOG_ON_DEMAND,
.mem_blocks = 2,
.severity = 0,
.timestamp = WL12XX_FWLOG_TIMESTAMP_DISABLED,
.output = WL12XX_FWLOG_OUTPUT_HOST,
.threshold = 0,
},
.rate = {
.rate_retry_score = 32000,
.per_add = 8192,
.per_th1 = 2048,
.per_th2 = 4096,
.max_per = 8100,
.inverse_curiosity_factor = 5,
.tx_fail_low_th = 4,
.tx_fail_high_th = 10,
.per_alpha_shift = 4,
.per_add_shift = 13,
.per_beta1_shift = 10,
.per_beta2_shift = 8,
.rate_check_up = 2,
.rate_check_down = 12,
.rate_retry_policy = {
0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00,
},
},
.hangover = {
.recover_time = 0,
.hangover_period = 20,
.dynamic_mode = 1,
.early_termination_mode = 1,
.max_period = 20,
.min_period = 1,
.increase_delta = 1,
.decrease_delta = 2,
.quiet_time = 4,
.increase_time = 1,
.window_size = 16,
},
};
static struct wl12xx_priv_conf wl12xx_default_priv_conf = {
.rf = {
.tx_per_channel_power_compensation_2 = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
},
.tx_per_channel_power_compensation_5 = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
},
},
.mem_wl127x = {
.num_stations = 1,
.ssid_profiles = 1,
.rx_block_num = 70,
.tx_min_block_num = 40,
.dynamic_memory = 1,
.min_req_tx_blocks = 100,
.min_req_rx_blocks = 22,
.tx_min = 27,
},
};
#define WL12XX_TX_HW_BLOCK_SPARE_DEFAULT 1
#define WL12XX_TX_HW_BLOCK_GEM_SPARE 2
#define WL12XX_TX_HW_BLOCK_SIZE 252
static const u8 wl12xx_rate_to_idx_2ghz[] = {
/* MCS rates are used only with 11n */
7, /* WL12XX_CONF_HW_RXTX_RATE_MCS7_SGI */
7, /* WL12XX_CONF_HW_RXTX_RATE_MCS7 */
6, /* WL12XX_CONF_HW_RXTX_RATE_MCS6 */
5, /* WL12XX_CONF_HW_RXTX_RATE_MCS5 */
4, /* WL12XX_CONF_HW_RXTX_RATE_MCS4 */
3, /* WL12XX_CONF_HW_RXTX_RATE_MCS3 */
2, /* WL12XX_CONF_HW_RXTX_RATE_MCS2 */
1, /* WL12XX_CONF_HW_RXTX_RATE_MCS1 */
0, /* WL12XX_CONF_HW_RXTX_RATE_MCS0 */
11, /* WL12XX_CONF_HW_RXTX_RATE_54 */
10, /* WL12XX_CONF_HW_RXTX_RATE_48 */
9, /* WL12XX_CONF_HW_RXTX_RATE_36 */
8, /* WL12XX_CONF_HW_RXTX_RATE_24 */
/* TI-specific rate */
CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL12XX_CONF_HW_RXTX_RATE_22 */
7, /* WL12XX_CONF_HW_RXTX_RATE_18 */
6, /* WL12XX_CONF_HW_RXTX_RATE_12 */
3, /* WL12XX_CONF_HW_RXTX_RATE_11 */
5, /* WL12XX_CONF_HW_RXTX_RATE_9 */
4, /* WL12XX_CONF_HW_RXTX_RATE_6 */
2, /* WL12XX_CONF_HW_RXTX_RATE_5_5 */
1, /* WL12XX_CONF_HW_RXTX_RATE_2 */
0 /* WL12XX_CONF_HW_RXTX_RATE_1 */
};
static const u8 wl12xx_rate_to_idx_5ghz[] = {
/* MCS rates are used only with 11n */
7, /* WL12XX_CONF_HW_RXTX_RATE_MCS7_SGI */
7, /* WL12XX_CONF_HW_RXTX_RATE_MCS7 */
6, /* WL12XX_CONF_HW_RXTX_RATE_MCS6 */
5, /* WL12XX_CONF_HW_RXTX_RATE_MCS5 */
4, /* WL12XX_CONF_HW_RXTX_RATE_MCS4 */
3, /* WL12XX_CONF_HW_RXTX_RATE_MCS3 */
2, /* WL12XX_CONF_HW_RXTX_RATE_MCS2 */
1, /* WL12XX_CONF_HW_RXTX_RATE_MCS1 */
0, /* WL12XX_CONF_HW_RXTX_RATE_MCS0 */
7, /* WL12XX_CONF_HW_RXTX_RATE_54 */
6, /* WL12XX_CONF_HW_RXTX_RATE_48 */
5, /* WL12XX_CONF_HW_RXTX_RATE_36 */
4, /* WL12XX_CONF_HW_RXTX_RATE_24 */
/* TI-specific rate */
CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL12XX_CONF_HW_RXTX_RATE_22 */
3, /* WL12XX_CONF_HW_RXTX_RATE_18 */
2, /* WL12XX_CONF_HW_RXTX_RATE_12 */
CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL12XX_CONF_HW_RXTX_RATE_11 */
1, /* WL12XX_CONF_HW_RXTX_RATE_9 */
0, /* WL12XX_CONF_HW_RXTX_RATE_6 */
CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL12XX_CONF_HW_RXTX_RATE_5_5 */
CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL12XX_CONF_HW_RXTX_RATE_2 */
CONF_HW_RXTX_RATE_UNSUPPORTED /* WL12XX_CONF_HW_RXTX_RATE_1 */
};
static const u8 *wl12xx_band_rate_to_idx[] = {
[IEEE80211_BAND_2GHZ] = wl12xx_rate_to_idx_2ghz,
[IEEE80211_BAND_5GHZ] = wl12xx_rate_to_idx_5ghz
};
enum wl12xx_hw_rates {
WL12XX_CONF_HW_RXTX_RATE_MCS7_SGI = 0,
WL12XX_CONF_HW_RXTX_RATE_MCS7,
WL12XX_CONF_HW_RXTX_RATE_MCS6,
WL12XX_CONF_HW_RXTX_RATE_MCS5,
WL12XX_CONF_HW_RXTX_RATE_MCS4,
WL12XX_CONF_HW_RXTX_RATE_MCS3,
WL12XX_CONF_HW_RXTX_RATE_MCS2,
WL12XX_CONF_HW_RXTX_RATE_MCS1,
WL12XX_CONF_HW_RXTX_RATE_MCS0,
WL12XX_CONF_HW_RXTX_RATE_54,
WL12XX_CONF_HW_RXTX_RATE_48,
WL12XX_CONF_HW_RXTX_RATE_36,
WL12XX_CONF_HW_RXTX_RATE_24,
WL12XX_CONF_HW_RXTX_RATE_22,
WL12XX_CONF_HW_RXTX_RATE_18,
WL12XX_CONF_HW_RXTX_RATE_12,
WL12XX_CONF_HW_RXTX_RATE_11,
WL12XX_CONF_HW_RXTX_RATE_9,
WL12XX_CONF_HW_RXTX_RATE_6,
WL12XX_CONF_HW_RXTX_RATE_5_5,
WL12XX_CONF_HW_RXTX_RATE_2,
WL12XX_CONF_HW_RXTX_RATE_1,
WL12XX_CONF_HW_RXTX_RATE_MAX,
};
static struct wlcore_partition_set wl12xx_ptable[PART_TABLE_LEN] = {
[PART_DOWN] = {
.mem = {
.start = 0x00000000,
.size = 0x000177c0
},
.reg = {
.start = REGISTERS_BASE,
.size = 0x00008800
},
.mem2 = {
.start = 0x00000000,
.size = 0x00000000
},
.mem3 = {
.start = 0x00000000,
.size = 0x00000000
},
},
[PART_BOOT] = { /* in wl12xx we can use a mix of work and down
* partition here */
.mem = {
.start = 0x00040000,
.size = 0x00014fc0
},
.reg = {
.start = REGISTERS_BASE,
.size = 0x00008800
},
.mem2 = {
.start = 0x00000000,
.size = 0x00000000
},
.mem3 = {
.start = 0x00000000,
.size = 0x00000000
},
},
[PART_WORK] = {
.mem = {
.start = 0x00040000,
.size = 0x00014fc0
},
.reg = {
.start = REGISTERS_BASE,
.size = 0x0000a000
},
.mem2 = {
.start = 0x003004f8,
.size = 0x00000004
},
.mem3 = {
.start = 0x00040404,
.size = 0x00000000
},
},
[PART_DRPW] = {
.mem = {
.start = 0x00040000,
.size = 0x00014fc0
},
.reg = {
.start = DRPW_BASE,
.size = 0x00006000
},
.mem2 = {
.start = 0x00000000,
.size = 0x00000000
},
.mem3 = {
.start = 0x00000000,
.size = 0x00000000
}
}
};
static const int wl12xx_rtable[REG_TABLE_LEN] = {
[REG_ECPU_CONTROL] = WL12XX_REG_ECPU_CONTROL,
[REG_INTERRUPT_NO_CLEAR] = WL12XX_REG_INTERRUPT_NO_CLEAR,
[REG_INTERRUPT_ACK] = WL12XX_REG_INTERRUPT_ACK,
[REG_COMMAND_MAILBOX_PTR] = WL12XX_REG_COMMAND_MAILBOX_PTR,
[REG_EVENT_MAILBOX_PTR] = WL12XX_REG_EVENT_MAILBOX_PTR,
[REG_INTERRUPT_TRIG] = WL12XX_REG_INTERRUPT_TRIG,
[REG_INTERRUPT_MASK] = WL12XX_REG_INTERRUPT_MASK,
[REG_PC_ON_RECOVERY] = WL12XX_SCR_PAD4,
[REG_CHIP_ID_B] = WL12XX_CHIP_ID_B,
[REG_CMD_MBOX_ADDRESS] = WL12XX_CMD_MBOX_ADDRESS,
/* data access memory addresses, used with partition translation */
[REG_SLV_MEM_DATA] = WL1271_SLV_MEM_DATA,
[REG_SLV_REG_DATA] = WL1271_SLV_REG_DATA,
/* raw data access memory addresses */
[REG_RAW_FW_STATUS_ADDR] = FW_STATUS_ADDR,
};
/* 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 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"
static void wl127x_prepare_read(struct wl1271 *wl, u32 rx_desc, u32 len)
{
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;
/*
* Choose the block we want to read
* For aggregated packets, only the first memory block
* should be retrieved. The FW takes care of the rest.
*/
u32 mem_block = rx_desc & RX_MEM_BLOCK_MASK;
rx_mem_addr.addr = (mem_block << 8) +
le32_to_cpu(wl_mem_map->packet_memory_pool_start);
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);
}
}
static int wl12xx_identify_chip(struct wl1271 *wl)
{
int ret = 0;
switch (wl->chip.id) {
case CHIP_ID_1271_PG10:
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->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,
sizeof(wl->conf.mem));
/* read data preparation is only needed by wl127x */
wl->ops->prepare_read = wl127x_prepare_read;
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->plt_fw_name = WL127X_PLT_FW_NAME;
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,
sizeof(wl->conf.mem));
/* read data preparation is only needed by wl127x */
wl->ops->prepare_read = wl127x_prepare_read;
break;
case CHIP_ID_1283_PG20:
wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
wl->chip.id);
wl->plt_fw_name = WL128X_PLT_FW_NAME;
wl->sr_fw_name = WL128X_FW_NAME_SINGLE;
wl->mr_fw_name = WL128X_FW_NAME_MULTI;
break;
case CHIP_ID_1283_PG10:
default:
wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
ret = -ENODEV;
goto out;
}
out:
return ret;
}
static void wl12xx_top_reg_write(struct wl1271 *wl, int addr, u16 val)
{
/* write address >> 1 + 0x30000 to OCP_POR_CTR */
addr = (addr >> 1) + 0x30000;
wl1271_write32(wl, WL12XX_OCP_POR_CTR, addr);
/* write value to OCP_POR_WDATA */
wl1271_write32(wl, WL12XX_OCP_DATA_WRITE, val);
/* write 1 to OCP_CMD */
wl1271_write32(wl, WL12XX_OCP_CMD, OCP_CMD_WRITE);
}
static u16 wl12xx_top_reg_read(struct wl1271 *wl, int addr)
{
u32 val;
int timeout = OCP_CMD_LOOP;
/* write address >> 1 + 0x30000 to OCP_POR_CTR */
addr = (addr >> 1) + 0x30000;
wl1271_write32(wl, WL12XX_OCP_POR_CTR, addr);
/* write 2 to OCP_CMD */
wl1271_write32(wl, WL12XX_OCP_CMD, OCP_CMD_READ);
/* poll for data ready */
do {
val = wl1271_read32(wl, WL12XX_OCP_DATA_READ);
} while (!(val & OCP_READY_MASK) && --timeout);
if (!timeout) {
wl1271_warning("Top register access timed out.");
return 0xffff;
}
/* check data status and return if OK */
if ((val & OCP_STATUS_MASK) == OCP_STATUS_OK)
return val & 0xffff;
else {
wl1271_warning("Top register access returned error.");
return 0xffff;
}
}
static int wl128x_switch_tcxo_to_fref(struct wl1271 *wl)
{
u16 spare_reg;
/* Mask bits [2] & [8:4] in the sys_clk_cfg register */
spare_reg = wl12xx_top_reg_read(wl, WL_SPARE_REG);
if (spare_reg == 0xFFFF)
return -EFAULT;
spare_reg |= (BIT(3) | BIT(5) | BIT(6));
wl12xx_top_reg_write(wl, WL_SPARE_REG, spare_reg);
/* 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);
/* Delay execution for 15msec, to let the HW settle */
mdelay(15);
return 0;
}
static bool wl128x_is_tcxo_valid(struct wl1271 *wl)
{
u16 tcxo_detection;
tcxo_detection = wl12xx_top_reg_read(wl, TCXO_CLK_DETECT_REG);
if (tcxo_detection & TCXO_DET_FAILED)
return false;
return true;
}
static bool wl128x_is_fref_valid(struct wl1271 *wl)
{
u16 fref_detection;
fref_detection = wl12xx_top_reg_read(wl, FREF_CLK_DETECT_REG);
if (fref_detection & FREF_CLK_DETECT_FAIL)
return false;
return true;
}
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);
return 0;
}
static int wl128x_configure_mcs_pll(struct wl1271 *wl, int clk)
{
u16 spare_reg;
u16 pll_config;
u8 input_freq;
/* Mask bits [3:1] in the sys_clk_cfg register */
spare_reg = wl12xx_top_reg_read(wl, WL_SPARE_REG);
if (spare_reg == 0xFFFF)
return -EFAULT;
spare_reg |= BIT(2);
wl12xx_top_reg_write(wl, WL_SPARE_REG, spare_reg);
/* Handle special cases of the TCXO clock */
if (wl->tcxo_clock == WL12XX_TCXOCLOCK_16_8 ||
wl->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);
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);
return 0;
}
/*
* WL128x has two clocks input - TCXO and FREF.
* TCXO is the main clock of the device, while FREF is used to sync
* between the GPS and the cellular modem.
* In cases where TCXO is 32.736MHz or 16.368MHz, the FREF will be used
* as the WLAN/BT main clock.
*/
static int wl128x_boot_clk(struct wl1271 *wl, int *selected_clock)
{
u16 sys_clk_cfg;
/* 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 (!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);
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 (!wl128x_switch_tcxo_to_fref(wl))
return -EINVAL;
goto fref_clk;
}
/* TCXO clock is selected */
if (!wl128x_is_tcxo_valid(wl))
return -EINVAL;
*selected_clock = wl->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;
config_mcs_pll:
return wl128x_configure_mcs_pll(wl, *selected_clock);
}
static int wl127x_boot_clk(struct wl1271 *wl)
{
u32 pause;
u32 clk;
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)
/* 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)
/* ref clk: 26/52 */
clk = 0x5;
else
return -EINVAL;
if (wl->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);
val &= FREF_CLK_TYPE_BITS;
wl12xx_top_reg_write(wl, OCP_REG_CLK_TYPE, val);
/* Set clock pull mode (no pull) */
val = wl12xx_top_reg_read(wl, OCP_REG_CLK_PULL);
val |= NO_PULL;
wl12xx_top_reg_write(wl, OCP_REG_CLK_PULL, val);
} else {
u16 val;
/* Set clock polarity */
val = wl12xx_top_reg_read(wl, OCP_REG_CLK_POLARITY);
val &= FREF_CLK_POLARITY_BITS;
val |= CLK_REQ_OUTN_SEL;
wl12xx_top_reg_write(wl, OCP_REG_CLK_POLARITY, val);
}
wl1271_write32(wl, WL12XX_PLL_PARAMETERS, clk);
pause = wl1271_read32(wl, WL12XX_PLL_PARAMETERS);
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);
return 0;
}
static int wl1271_boot_soft_reset(struct wl1271 *wl)
{
unsigned long timeout;
u32 boot_data;
/* perform soft reset */
wl1271_write32(wl, WL12XX_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT);
/* 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);
wl1271_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data);
if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0)
break;
if (time_after(jiffies, timeout)) {
/* 1.2 check pWhalBus->uSelfClearTime if the
* timeout was reached */
wl1271_error("soft reset timeout");
return -1;
}
udelay(SOFT_RESET_STALL_TIME);
}
/* disable Rx/Tx */
wl1271_write32(wl, WL12XX_ENABLE, 0x0);
/* disable auto calibration on start*/
wl1271_write32(wl, WL12XX_SPARE_A2, 0xffff);
return 0;
}
static int wl12xx_pre_boot(struct wl1271 *wl)
{
int ret = 0;
u32 clk;
int selected_clock = -1;
if (wl->chip.id == CHIP_ID_1283_PG20) {
ret = wl128x_boot_clk(wl, &selected_clock);
if (ret < 0)
goto out;
} else {
ret = wl127x_boot_clk(wl);
if (ret < 0)
goto out;
}
/* Continue the ELP wake up sequence */
wl1271_write32(wl, WL12XX_WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL);
udelay(500);
wlcore_set_partition(wl, &wl->ptable[PART_DRPW]);
/* 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);
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;
wl1271_write32(wl, WL12XX_DRPW_SCRATCH_START, clk);
wlcore_set_partition(wl, &wl->ptable[PART_WORK]);
/* Disable interrupts */
wlcore_write_reg(wl, REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
ret = wl1271_boot_soft_reset(wl);
if (ret < 0)
goto out;
out:
return ret;
}
static void wl12xx_pre_upload(struct wl1271 *wl)
{
u32 tmp;
/* 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);
tmp = wlcore_read_reg(wl, REG_CHIP_ID_B);
wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp);
/* 6. read the EEPROM parameters */
tmp = wl1271_read32(wl, WL12XX_SCR_PAD2);
/* 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;
polarity = wl12xx_top_reg_read(wl, OCP_REG_POLARITY);
/* We use HIGH polarity, so unset the LOW bit */
polarity &= ~POLARITY_LOW;
wl12xx_top_reg_write(wl, OCP_REG_POLARITY, polarity);
wlcore_write_reg(wl, REG_INTERRUPT_MASK, WL1271_ACX_ALL_EVENTS_VECTOR);
wlcore_enable_interrupts(wl);
wlcore_write_reg(wl, REG_INTERRUPT_MASK,
WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
wl1271_write32(wl, WL12XX_HI_CFG, HI_CFG_DEF_VAL);
}
static int wl12xx_boot(struct wl1271 *wl)
{
int ret;
ret = wl12xx_pre_boot(wl);
if (ret < 0)
goto out;
ret = wlcore_boot_upload_nvs(wl);
if (ret < 0)
goto out;
wl12xx_pre_upload(wl);
ret = wlcore_boot_upload_firmware(wl);
if (ret < 0)
goto out;
ret = wlcore_boot_run_firmware(wl);
if (ret < 0)
goto out;
wl12xx_enable_interrupts(wl);
out:
return ret;
}
static void 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);
}
static void wl12xx_ack_event(struct wl1271 *wl)
{
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)
{
u32 blk_size = WL12XX_TX_HW_BLOCK_SIZE;
u32 align_len = wlcore_calc_packet_alignment(wl, len);
return (align_len + blk_size - 1) / blk_size + spare_blks;
}
static void
wl12xx_set_tx_desc_blocks(struct wl1271 *wl, struct wl1271_tx_hw_descr *desc,
u32 blks, u32 spare_blks)
{
if (wl->chip.id == CHIP_ID_1283_PG20) {
desc->wl128x_mem.total_mem_blocks = blks;
} else {
desc->wl127x_mem.extra_blocks = spare_blks;
desc->wl127x_mem.total_mem_blocks = blks;
}
}
static void
wl12xx_set_tx_desc_data_len(struct wl1271 *wl, struct wl1271_tx_hw_descr *desc,
struct sk_buff *skb)
{
u32 aligned_len = wlcore_calc_packet_alignment(wl, skb->len);
if (wl->chip.id == CHIP_ID_1283_PG20) {
desc->wl128x_mem.extra_bytes = aligned_len - skb->len;
desc->length = cpu_to_le16(aligned_len >> 2);
wl1271_debug(DEBUG_TX,
"tx_fill_hdr: hlid: %d len: %d life: %d mem: %d extra: %d",
desc->hlid,
le16_to_cpu(desc->length),
le16_to_cpu(desc->life_time),
desc->wl128x_mem.total_mem_blocks,
desc->wl128x_mem.extra_bytes);
} else {
/* calculate number of padding bytes */
int pad = aligned_len - skb->len;
desc->tx_attr |=
cpu_to_le16(pad << TX_HW_ATTR_OFST_LAST_WORD_PAD);
/* Store the aligned length in terms of words */
desc->length = cpu_to_le16(aligned_len >> 2);
wl1271_debug(DEBUG_TX,
"tx_fill_hdr: pad: %d hlid: %d len: %d life: %d mem: %d",
pad, desc->hlid,
le16_to_cpu(desc->length),
le16_to_cpu(desc->life_time),
desc->wl127x_mem.total_mem_blocks);
}
}
static enum wl_rx_buf_align
wl12xx_get_rx_buf_align(struct wl1271 *wl, u32 rx_desc)
{
if (rx_desc & RX_BUF_UNALIGNED_PAYLOAD)
return WLCORE_RX_BUF_UNALIGNED;
return WLCORE_RX_BUF_ALIGNED;
}
static u32 wl12xx_get_rx_packet_len(struct wl1271 *wl, void *rx_data,
u32 data_len)
{
struct wl1271_rx_descriptor *desc = rx_data;
/* invalid packet */
if (data_len < sizeof(*desc) ||
data_len < sizeof(*desc) + desc->pad_len)
return 0;
return data_len - sizeof(*desc) - desc->pad_len;
}
static void wl12xx_tx_delayed_compl(struct wl1271 *wl)
{
if (wl->fw_status->tx_results_counter == (wl->tx_results_count & 0xff))
return;
wl1271_tx_complete(wl);
}
static int wl12xx_hw_init(struct wl1271 *wl)
{
int ret;
if (wl->chip.id == CHIP_ID_1283_PG20) {
u32 host_cfg_bitmap = HOST_IF_CFG_RX_FIFO_ENABLE;
ret = wl128x_cmd_general_parms(wl);
if (ret < 0)
goto out;
ret = wl128x_cmd_radio_parms(wl);
if (ret < 0)
goto out;
if (wl->quirks & WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN)
/* Enable SDIO padding */
host_cfg_bitmap |= HOST_IF_CFG_TX_PAD_TO_SDIO_BLK;
/* Must be before wl1271_acx_init_mem_config() */
ret = wl1271_acx_host_if_cfg_bitmap(wl, host_cfg_bitmap);
if (ret < 0)
goto out;
} else {
ret = wl1271_cmd_general_parms(wl);
if (ret < 0)
goto out;
ret = wl1271_cmd_radio_parms(wl);
if (ret < 0)
goto out;
ret = wl1271_cmd_ext_radio_parms(wl);
if (ret < 0)
goto out;
}
out:
return ret;
}
static u32 wl12xx_sta_get_ap_rate_mask(struct wl1271 *wl,
struct wl12xx_vif *wlvif)
{
return wlvif->rate_set;
}
static int wl12xx_identify_fw(struct wl1271 *wl)
{
unsigned int *fw_ver = wl->chip.fw_ver;
/* Only new station firmwares support routing fw logs to the host */
if ((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) &&
(fw_ver[FW_VER_MINOR] < FW_VER_MINOR_FWLOG_STA_MIN))
wl->quirks |= WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED;
/* This feature is not yet supported for AP mode */
if (fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_AP)
wl->quirks |= WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED;
return 0;
}
static void wl12xx_conf_init(struct wl1271 *wl)
{
struct wl12xx_priv *priv = wl->priv;
/* apply driver default configuration */
memcpy(&wl->conf, &wl12xx_conf, sizeof(wl12xx_conf));
/* apply default private configuration */
memcpy(&priv->conf, &wl12xx_default_priv_conf, sizeof(priv->conf));
}
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_get_fuse_mac(struct wl1271 *wl)
{
u32 mac1, mac2;
wlcore_set_partition(wl, &wl->ptable[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;
wlcore_set_partition(wl, &wl->ptable[PART_DOWN]);
}
static s8 wl12xx_get_pg_ver(struct wl1271 *wl)
{
u32 die_info;
if (wl->chip.id == CHIP_ID_1283_PG20)
die_info = wl12xx_top_reg_read(wl, WL128X_REG_FUSE_DATA_2_1);
else
die_info = wl12xx_top_reg_read(wl, WL127X_REG_FUSE_DATA_2_1);
return (s8) (die_info & PG_VER_MASK) >> PG_VER_OFFSET;
}
static void wl12xx_get_mac(struct wl1271 *wl)
{
if (wl12xx_mac_in_fuse(wl))
wl12xx_get_fuse_mac(wl);
}
static struct wlcore_ops wl12xx_ops = {
.identify_chip = wl12xx_identify_chip,
.identify_fw = wl12xx_identify_fw,
.boot = wl12xx_boot,
.trigger_cmd = wl12xx_trigger_cmd,
.ack_event = wl12xx_ack_event,
.calc_tx_blocks = wl12xx_calc_tx_blocks,
.set_tx_desc_blocks = wl12xx_set_tx_desc_blocks,
.set_tx_desc_data_len = wl12xx_set_tx_desc_data_len,
.get_rx_buf_align = wl12xx_get_rx_buf_align,
.get_rx_packet_len = wl12xx_get_rx_packet_len,
.tx_immediate_compl = NULL,
.tx_delayed_compl = wl12xx_tx_delayed_compl,
.hw_init = wl12xx_hw_init,
.init_vif = NULL,
.sta_get_ap_rate_mask = wl12xx_sta_get_ap_rate_mask,
.get_pg_ver = wl12xx_get_pg_ver,
.get_mac = wl12xx_get_mac,
};
static struct ieee80211_sta_ht_cap wl12xx_ht_cap = {
.cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 |
(1 << IEEE80211_HT_CAP_RX_STBC_SHIFT),
.ht_supported = true,
.ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K,
.ampdu_density = IEEE80211_HT_MPDU_DENSITY_8,
.mcs = {
.rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
.rx_highest = cpu_to_le16(72),
.tx_params = IEEE80211_HT_MCS_TX_DEFINED,
},
};
static int __devinit wl12xx_probe(struct platform_device *pdev)
{
struct wl1271 *wl;
struct ieee80211_hw *hw;
struct wl12xx_priv *priv;
hw = wlcore_alloc_hw(sizeof(*priv));
if (IS_ERR(hw)) {
wl1271_error("can't allocate hw");
return PTR_ERR(hw);
}
wl = hw->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->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));
wl12xx_conf_init(wl);
return wlcore_probe(wl, pdev);
}
static const struct platform_device_id wl12xx_id_table[] __devinitconst = {
{ "wl12xx", 0 },
{ } /* Terminating Entry */
};
MODULE_DEVICE_TABLE(platform, wl12xx_id_table);
static struct platform_driver wl12xx_driver = {
.probe = wl12xx_probe,
.remove = __devexit_p(wlcore_remove),
.id_table = wl12xx_id_table,
.driver = {
.name = "wl12xx_driver",
.owner = THIS_MODULE,
}
};
static int __init wl12xx_init(void)
{
return platform_driver_register(&wl12xx_driver);
}
module_init(wl12xx_init);
static void __exit wl12xx_exit(void)
{
platform_driver_unregister(&wl12xx_driver);
}
module_exit(wl12xx_exit);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
MODULE_FIRMWARE(WL127X_FW_NAME_SINGLE);
MODULE_FIRMWARE(WL127X_FW_NAME_MULTI);
MODULE_FIRMWARE(WL127X_PLT_FW_NAME);
MODULE_FIRMWARE(WL128X_FW_NAME_SINGLE);
MODULE_FIRMWARE(WL128X_FW_NAME_MULTI);
MODULE_FIRMWARE(WL128X_PLT_FW_NAME);
...@@ -33,16 +33,8 @@ ...@@ -33,16 +33,8 @@
#define REGISTERS_DOWN_SIZE 0x00008800 #define REGISTERS_DOWN_SIZE 0x00008800
#define REGISTERS_WORK_SIZE 0x0000b000 #define REGISTERS_WORK_SIZE 0x0000b000
#define HW_ACCESS_ELP_CTRL_REG_ADDR 0x1FFFC
#define FW_STATUS_ADDR (0x14FC0 + 0xA000) #define FW_STATUS_ADDR (0x14FC0 + 0xA000)
/* ELP register commands */
#define ELPCTRL_WAKE_UP 0x1
#define ELPCTRL_WAKE_UP_WLAN_READY 0x5
#define ELPCTRL_SLEEP 0x0
/* ELP WLAN_READY bit */
#define ELPCTRL_WLAN_READY 0x2
/*=============================================== /*===============================================
Host Software Reset - 32bit RW Host Software Reset - 32bit RW
------------------------------------------ ------------------------------------------
...@@ -57,14 +49,14 @@ ...@@ -57,14 +49,14 @@
(not self-clearing), the Wlan hardware (not self-clearing), the Wlan hardware
exits the software reset state. exits the software reset state.
===============================================*/ ===============================================*/
#define ACX_REG_SLV_SOFT_RESET (REGISTERS_BASE + 0x0000) #define WL12XX_SLV_SOFT_RESET (REGISTERS_BASE + 0x0000)
#define WL1271_SLV_REG_DATA (REGISTERS_BASE + 0x0008) #define WL1271_SLV_REG_DATA (REGISTERS_BASE + 0x0008)
#define WL1271_SLV_REG_ADATA (REGISTERS_BASE + 0x000c) #define WL1271_SLV_REG_ADATA (REGISTERS_BASE + 0x000c)
#define WL1271_SLV_MEM_DATA (REGISTERS_BASE + 0x0018) #define WL1271_SLV_MEM_DATA (REGISTERS_BASE + 0x0018)
#define ACX_REG_INTERRUPT_TRIG (REGISTERS_BASE + 0x0474) #define WL12XX_REG_INTERRUPT_TRIG (REGISTERS_BASE + 0x0474)
#define ACX_REG_INTERRUPT_TRIG_H (REGISTERS_BASE + 0x0478) #define WL12XX_REG_INTERRUPT_TRIG_H (REGISTERS_BASE + 0x0478)
/*============================================= /*=============================================
Host Interrupt Mask Register - 32bit (RW) Host Interrupt Mask Register - 32bit (RW)
...@@ -94,7 +86,7 @@ ...@@ -94,7 +86,7 @@
21- - 21- -
Default: 0x0001 Default: 0x0001
*==============================================*/ *==============================================*/
#define ACX_REG_INTERRUPT_MASK (REGISTERS_BASE + 0x04DC) #define WL12XX_REG_INTERRUPT_MASK (REGISTERS_BASE + 0x04DC)
/*============================================= /*=============================================
Host Interrupt Mask Set 16bit, (Write only) Host Interrupt Mask Set 16bit, (Write only)
...@@ -125,7 +117,7 @@ ...@@ -125,7 +117,7 @@
Reading this register doesn't Reading this register doesn't
effect its content. effect its content.
=============================================*/ =============================================*/
#define ACX_REG_INTERRUPT_NO_CLEAR (REGISTERS_BASE + 0x04E8) #define WL12XX_REG_INTERRUPT_NO_CLEAR (REGISTERS_BASE + 0x04E8)
/*============================================= /*=============================================
Host Interrupt Status Clear on Read Register Host Interrupt Status Clear on Read Register
...@@ -148,9 +140,9 @@ ...@@ -148,9 +140,9 @@
HINT_STS_ND registers, thus making the HINT_STS_ND registers, thus making the
assotiated interrupt inactive. (0-no effect) assotiated interrupt inactive. (0-no effect)
==============================================*/ ==============================================*/
#define ACX_REG_INTERRUPT_ACK (REGISTERS_BASE + 0x04F0) #define WL12XX_REG_INTERRUPT_ACK (REGISTERS_BASE + 0x04F0)
#define RX_DRIVER_COUNTER_ADDRESS (REGISTERS_BASE + 0x0538) #define WL12XX_REG_RX_DRIVER_COUNTER (REGISTERS_BASE + 0x0538)
/* Device Configuration registers*/ /* Device Configuration registers*/
#define SOR_CFG (REGISTERS_BASE + 0x0800) #define SOR_CFG (REGISTERS_BASE + 0x0800)
...@@ -175,9 +167,9 @@ ...@@ -175,9 +167,9 @@
1 halt eCPU 1 halt eCPU
0 enable eCPU 0 enable eCPU
===============================================*/ ===============================================*/
#define ACX_REG_ECPU_CONTROL (REGISTERS_BASE + 0x0804) #define WL12XX_REG_ECPU_CONTROL (REGISTERS_BASE + 0x0804)
#define HI_CFG (REGISTERS_BASE + 0x0808) #define WL12XX_HI_CFG (REGISTERS_BASE + 0x0808)
/*=============================================== /*===============================================
EEPROM Burst Read Start - 32bit RW EEPROM Burst Read Start - 32bit RW
...@@ -196,72 +188,67 @@ ...@@ -196,72 +188,67 @@
*================================================*/ *================================================*/
#define ACX_REG_EE_START (REGISTERS_BASE + 0x080C) #define ACX_REG_EE_START (REGISTERS_BASE + 0x080C)
#define OCP_POR_CTR (REGISTERS_BASE + 0x09B4) #define WL12XX_OCP_POR_CTR (REGISTERS_BASE + 0x09B4)
#define OCP_DATA_WRITE (REGISTERS_BASE + 0x09B8) #define WL12XX_OCP_DATA_WRITE (REGISTERS_BASE + 0x09B8)
#define OCP_DATA_READ (REGISTERS_BASE + 0x09BC) #define WL12XX_OCP_DATA_READ (REGISTERS_BASE + 0x09BC)
#define OCP_CMD (REGISTERS_BASE + 0x09C0) #define WL12XX_OCP_CMD (REGISTERS_BASE + 0x09C0)
#define WL1271_HOST_WR_ACCESS (REGISTERS_BASE + 0x09F8)
#define CHIP_ID_B (REGISTERS_BASE + 0x5674) #define WL12XX_HOST_WR_ACCESS (REGISTERS_BASE + 0x09F8)
#define CHIP_ID_1271_PG10 (0x4030101) #define WL12XX_CHIP_ID_B (REGISTERS_BASE + 0x5674)
#define CHIP_ID_1271_PG20 (0x4030111)
#define CHIP_ID_1283_PG10 (0x05030101)
#define CHIP_ID_1283_PG20 (0x05030111)
#define ENABLE (REGISTERS_BASE + 0x5450) #define WL12XX_ENABLE (REGISTERS_BASE + 0x5450)
/* Power Management registers */ /* Power Management registers */
#define ELP_CFG_MODE (REGISTERS_BASE + 0x5804) #define WL12XX_ELP_CFG_MODE (REGISTERS_BASE + 0x5804)
#define ELP_CMD (REGISTERS_BASE + 0x5808) #define WL12XX_ELP_CMD (REGISTERS_BASE + 0x5808)
#define PLL_CAL_TIME (REGISTERS_BASE + 0x5810) #define WL12XX_PLL_CAL_TIME (REGISTERS_BASE + 0x5810)
#define CLK_REQ_TIME (REGISTERS_BASE + 0x5814) #define WL12XX_CLK_REQ_TIME (REGISTERS_BASE + 0x5814)
#define CLK_BUF_TIME (REGISTERS_BASE + 0x5818) #define WL12XX_CLK_BUF_TIME (REGISTERS_BASE + 0x5818)
#define CFG_PLL_SYNC_CNT (REGISTERS_BASE + 0x5820) #define WL12XX_CFG_PLL_SYNC_CNT (REGISTERS_BASE + 0x5820)
/* Scratch Pad registers*/ /* Scratch Pad registers*/
#define SCR_PAD0 (REGISTERS_BASE + 0x5608) #define WL12XX_SCR_PAD0 (REGISTERS_BASE + 0x5608)
#define SCR_PAD1 (REGISTERS_BASE + 0x560C) #define WL12XX_SCR_PAD1 (REGISTERS_BASE + 0x560C)
#define SCR_PAD2 (REGISTERS_BASE + 0x5610) #define WL12XX_SCR_PAD2 (REGISTERS_BASE + 0x5610)
#define SCR_PAD3 (REGISTERS_BASE + 0x5614) #define WL12XX_SCR_PAD3 (REGISTERS_BASE + 0x5614)
#define SCR_PAD4 (REGISTERS_BASE + 0x5618) #define WL12XX_SCR_PAD4 (REGISTERS_BASE + 0x5618)
#define SCR_PAD4_SET (REGISTERS_BASE + 0x561C) #define WL12XX_SCR_PAD4_SET (REGISTERS_BASE + 0x561C)
#define SCR_PAD4_CLR (REGISTERS_BASE + 0x5620) #define WL12XX_SCR_PAD4_CLR (REGISTERS_BASE + 0x5620)
#define SCR_PAD5 (REGISTERS_BASE + 0x5624) #define WL12XX_SCR_PAD5 (REGISTERS_BASE + 0x5624)
#define SCR_PAD5_SET (REGISTERS_BASE + 0x5628) #define WL12XX_SCR_PAD5_SET (REGISTERS_BASE + 0x5628)
#define SCR_PAD5_CLR (REGISTERS_BASE + 0x562C) #define WL12XX_SCR_PAD5_CLR (REGISTERS_BASE + 0x562C)
#define SCR_PAD6 (REGISTERS_BASE + 0x5630) #define WL12XX_SCR_PAD6 (REGISTERS_BASE + 0x5630)
#define SCR_PAD7 (REGISTERS_BASE + 0x5634) #define WL12XX_SCR_PAD7 (REGISTERS_BASE + 0x5634)
#define SCR_PAD8 (REGISTERS_BASE + 0x5638) #define WL12XX_SCR_PAD8 (REGISTERS_BASE + 0x5638)
#define SCR_PAD9 (REGISTERS_BASE + 0x563C) #define WL12XX_SCR_PAD9 (REGISTERS_BASE + 0x563C)
/* Spare registers*/ /* Spare registers*/
#define SPARE_A1 (REGISTERS_BASE + 0x0994) #define WL12XX_SPARE_A1 (REGISTERS_BASE + 0x0994)
#define SPARE_A2 (REGISTERS_BASE + 0x0998) #define WL12XX_SPARE_A2 (REGISTERS_BASE + 0x0998)
#define SPARE_A3 (REGISTERS_BASE + 0x099C) #define WL12XX_SPARE_A3 (REGISTERS_BASE + 0x099C)
#define SPARE_A4 (REGISTERS_BASE + 0x09A0) #define WL12XX_SPARE_A4 (REGISTERS_BASE + 0x09A0)
#define SPARE_A5 (REGISTERS_BASE + 0x09A4) #define WL12XX_SPARE_A5 (REGISTERS_BASE + 0x09A4)
#define SPARE_A6 (REGISTERS_BASE + 0x09A8) #define WL12XX_SPARE_A6 (REGISTERS_BASE + 0x09A8)
#define SPARE_A7 (REGISTERS_BASE + 0x09AC) #define WL12XX_SPARE_A7 (REGISTERS_BASE + 0x09AC)
#define SPARE_A8 (REGISTERS_BASE + 0x09B0) #define WL12XX_SPARE_A8 (REGISTERS_BASE + 0x09B0)
#define SPARE_B1 (REGISTERS_BASE + 0x5420) #define WL12XX_SPARE_B1 (REGISTERS_BASE + 0x5420)
#define SPARE_B2 (REGISTERS_BASE + 0x5424) #define WL12XX_SPARE_B2 (REGISTERS_BASE + 0x5424)
#define SPARE_B3 (REGISTERS_BASE + 0x5428) #define WL12XX_SPARE_B3 (REGISTERS_BASE + 0x5428)
#define SPARE_B4 (REGISTERS_BASE + 0x542C) #define WL12XX_SPARE_B4 (REGISTERS_BASE + 0x542C)
#define SPARE_B5 (REGISTERS_BASE + 0x5430) #define WL12XX_SPARE_B5 (REGISTERS_BASE + 0x5430)
#define SPARE_B6 (REGISTERS_BASE + 0x5434) #define WL12XX_SPARE_B6 (REGISTERS_BASE + 0x5434)
#define SPARE_B7 (REGISTERS_BASE + 0x5438) #define WL12XX_SPARE_B7 (REGISTERS_BASE + 0x5438)
#define SPARE_B8 (REGISTERS_BASE + 0x543C) #define WL12XX_SPARE_B8 (REGISTERS_BASE + 0x543C)
#define PLL_PARAMETERS (REGISTERS_BASE + 0x6040) #define WL12XX_PLL_PARAMETERS (REGISTERS_BASE + 0x6040)
#define WU_COUNTER_PAUSE (REGISTERS_BASE + 0x6008) #define WL12XX_WU_COUNTER_PAUSE (REGISTERS_BASE + 0x6008)
#define WELP_ARM_COMMAND (REGISTERS_BASE + 0x6100) #define WL12XX_WELP_ARM_COMMAND (REGISTERS_BASE + 0x6100)
#define DRPW_SCRATCH_START (DRPW_BASE + 0x002C) #define WL12XX_DRPW_SCRATCH_START (DRPW_BASE + 0x002C)
#define WL12XX_CMD_MBOX_ADDRESS 0x407B4
#define ACX_SLV_SOFT_RESET_BIT BIT(1)
#define ACX_REG_EEPROM_START_BIT BIT(1) #define ACX_REG_EEPROM_START_BIT BIT(1)
/* Command/Information Mailbox Pointers */ /* Command/Information Mailbox Pointers */
...@@ -279,7 +266,7 @@ ...@@ -279,7 +266,7 @@
the host receives the Init Complete interrupt from the host receives the Init Complete interrupt from
the Wlan hardware. the Wlan hardware.
===============================================*/ ===============================================*/
#define REG_COMMAND_MAILBOX_PTR (SCR_PAD0) #define WL12XX_REG_COMMAND_MAILBOX_PTR (WL12XX_SCR_PAD0)
/*=============================================== /*===============================================
Information Mailbox Pointer - 32bit RW Information Mailbox Pointer - 32bit RW
...@@ -294,7 +281,7 @@ ...@@ -294,7 +281,7 @@
until after the host receives the Init Complete interrupt from until after the host receives the Init Complete interrupt from
the Wlan hardware. the Wlan hardware.
===============================================*/ ===============================================*/
#define REG_EVENT_MAILBOX_PTR (SCR_PAD1) #define WL12XX_REG_EVENT_MAILBOX_PTR (WL12XX_SCR_PAD1)
/*=============================================== /*===============================================
EEPROM Read/Write Request 32bit RW EEPROM Read/Write Request 32bit RW
...@@ -365,26 +352,6 @@ ...@@ -365,26 +352,6 @@
#define ACX_CONT_WIND_MIN_MASK 0x0000007f #define ACX_CONT_WIND_MIN_MASK 0x0000007f
#define ACX_CONT_WIND_MAX 0x03ff0000 #define ACX_CONT_WIND_MAX 0x03ff0000
/*===============================================
HI_CFG Interface Configuration Register Values
------------------------------------------
===============================================*/
#define HI_CFG_UART_ENABLE 0x00000004
#define HI_CFG_RST232_ENABLE 0x00000008
#define HI_CFG_CLOCK_REQ_SELECT 0x00000010
#define HI_CFG_HOST_INT_ENABLE 0x00000020
#define HI_CFG_VLYNQ_OUTPUT_ENABLE 0x00000040
#define HI_CFG_HOST_INT_ACTIVE_LOW 0x00000080
#define HI_CFG_UART_TX_OUT_GPIO_15 0x00000100
#define HI_CFG_UART_TX_OUT_GPIO_14 0x00000200
#define HI_CFG_UART_TX_OUT_GPIO_7 0x00000400
#define HI_CFG_DEF_VAL \
(HI_CFG_UART_ENABLE | \
HI_CFG_RST232_ENABLE | \
HI_CFG_CLOCK_REQ_SELECT | \
HI_CFG_HOST_INT_ENABLE)
#define REF_FREQ_19_2 0 #define REF_FREQ_19_2 0
#define REF_FREQ_26_0 1 #define REF_FREQ_26_0 1
#define REF_FREQ_38_4 2 #define REF_FREQ_38_4 2
...@@ -400,38 +367,19 @@ ...@@ -400,38 +367,19 @@
#define LUT_PARAM_BB_PLL_LOOP_FILTER 5 #define LUT_PARAM_BB_PLL_LOOP_FILTER 5
#define LUT_PARAM_NUM 6 #define LUT_PARAM_NUM 6
#define ACX_EEPROMLESS_IND_REG (SCR_PAD4) #define WL12XX_EEPROMLESS_IND (WL12XX_SCR_PAD4)
#define USE_EEPROM 0 #define USE_EEPROM 0
#define SOFT_RESET_MAX_TIME 1000000
#define SOFT_RESET_STALL_TIME 1000
#define NVS_DATA_BUNDARY_ALIGNMENT 4 #define NVS_DATA_BUNDARY_ALIGNMENT 4
/* Firmware image load chunk size */
#define CHUNK_SIZE 16384
/* Firmware image header size */ /* Firmware image header size */
#define FW_HDR_SIZE 8 #define FW_HDR_SIZE 8
#define ECPU_CONTROL_HALT 0x00000101
/****************************************************************************** /******************************************************************************
CHANNELS, BAND & REG DOMAINS definitions CHANNELS, BAND & REG DOMAINS definitions
******************************************************************************/ ******************************************************************************/
enum {
RADIO_BAND_2_4GHZ = 0, /* 2.4 Ghz band */
RADIO_BAND_5GHZ = 1, /* 5 Ghz band */
RADIO_BAND_JAPAN_4_9_GHZ = 2,
DEFAULT_BAND = RADIO_BAND_2_4GHZ,
INVALID_BAND = 0xFE,
MAX_RADIO_BANDS = 0xFF
};
#define SHORT_PREAMBLE_BIT BIT(0) /* CCK or Barker depending on the rate */ #define SHORT_PREAMBLE_BIT BIT(0) /* CCK or Barker depending on the rate */
#define OFDM_RATE_BIT BIT(6) #define OFDM_RATE_BIT BIT(6)
#define PBCC_RATE_BIT BIT(7) #define PBCC_RATE_BIT BIT(7)
...@@ -465,14 +413,82 @@ b12-b0 - Supported Rate indicator bits as defined below. ...@@ -465,14 +413,82 @@ b12-b0 - Supported Rate indicator bits as defined below.
******************************************************************************/ ******************************************************************************/
#define OCP_CMD_LOOP 32
#define OCP_CMD_WRITE 0x1
#define OCP_CMD_READ 0x2
#define OCP_READY_MASK BIT(18)
#define OCP_STATUS_MASK (BIT(16) | BIT(17))
#define OCP_STATUS_NO_RESP 0x00000
#define OCP_STATUS_OK 0x10000
#define OCP_STATUS_REQ_FAILED 0x20000
#define OCP_STATUS_RESP_ERROR 0x30000
#define OCP_REG_POLARITY 0x0064
#define OCP_REG_CLK_TYPE 0x0448
#define OCP_REG_CLK_POLARITY 0x0cb2
#define OCP_REG_CLK_PULL 0x0cb4
#define POLARITY_LOW BIT(1)
#define NO_PULL (BIT(14) | BIT(15))
#define FREF_CLK_TYPE_BITS 0xfffffe7f
#define CLK_REQ_PRCM 0x100
#define FREF_CLK_POLARITY_BITS 0xfffff8ff
#define CLK_REQ_OUTN_SEL 0x700
#define WU_COUNTER_PAUSE_VAL 0x3FF
/* PLL configuration algorithm for wl128x */
#define SYS_CLK_CFG_REG 0x2200
/* Bit[0] - 0-TCXO, 1-FREF */
#define MCS_PLL_CLK_SEL_FREF BIT(0)
/* Bit[3:2] - 01-TCXO, 10-FREF */
#define WL_CLK_REQ_TYPE_FREF BIT(3)
#define WL_CLK_REQ_TYPE_PG2 (BIT(3) | BIT(2))
/* Bit[4] - 0-TCXO, 1-FREF */
#define PRCM_CM_EN_MUX_WLAN_FREF BIT(4)
#define TCXO_ILOAD_INT_REG 0x2264
#define TCXO_CLK_DETECT_REG 0x2266
#define TCXO_DET_FAILED BIT(4)
#define FREF_ILOAD_INT_REG 0x2084
#define FREF_CLK_DETECT_REG 0x2086
#define FREF_CLK_DETECT_FAIL BIT(4)
/* Use this reg for masking during driver access */
#define WL_SPARE_REG 0x2320
#define WL_SPARE_VAL BIT(2)
/* Bit[6:5:3] - mask wl write SYS_CLK_CFG[8:5:2:4] */
#define WL_SPARE_MASK_8526 (BIT(6) | BIT(5) | BIT(3))
#define PLL_LOCK_COUNTERS_REG 0xD8C
#define PLL_LOCK_COUNTERS_COEX 0x0F
#define PLL_LOCK_COUNTERS_MCS 0xF0
#define MCS_PLL_OVERRIDE_REG 0xD90
#define MCS_PLL_CONFIG_REG 0xD92
#define MCS_SEL_IN_FREQ_MASK 0x0070
#define MCS_SEL_IN_FREQ_SHIFT 4
#define MCS_PLL_CONFIG_REG_VAL 0x73
#define MCS_PLL_ENABLE_HP (BIT(0) | BIT(1))
#define MCS_PLL_M_REG 0xD94
#define MCS_PLL_N_REG 0xD96
#define MCS_PLL_M_REG_VAL 0xC8
#define MCS_PLL_N_REG_VAL 0x07
#define SDIO_IO_DS 0xd14
/* SDIO/wSPI DS configuration values */
enum {
HCI_IO_DS_8MA = 0,
HCI_IO_DS_4MA = 1, /* default */
HCI_IO_DS_6MA = 2,
HCI_IO_DS_2MA = 3,
};
/************************************************************************* /* end PLL configuration algorithm for wl128x */
Interrupt Trigger Register (Host -> WiLink)
**************************************************************************/
/* Hardware to Embedded CPU Interrupts - first 32-bit register set */
/* /*
* Host Command Interrupt. Setting this bit masks * Host Command Interrupt. Setting this bit masks
...@@ -480,7 +496,7 @@ b12-b0 - Supported Rate indicator bits as defined below. ...@@ -480,7 +496,7 @@ b12-b0 - Supported Rate indicator bits as defined below.
* the FW that it has sent a command * the FW that it has sent a command
* to the Wlan hardware Command Mailbox. * to the Wlan hardware Command Mailbox.
*/ */
#define INTR_TRIG_CMD BIT(0) #define WL12XX_INTR_TRIG_CMD BIT(0)
/* /*
* Host Event Acknowlegde Interrupt. The host * Host Event Acknowlegde Interrupt. The host
...@@ -488,42 +504,27 @@ b12-b0 - Supported Rate indicator bits as defined below. ...@@ -488,42 +504,27 @@ b12-b0 - Supported Rate indicator bits as defined below.
* the unsolicited information from the event * the unsolicited information from the event
* mailbox. * mailbox.
*/ */
#define INTR_TRIG_EVENT_ACK BIT(1) #define WL12XX_INTR_TRIG_EVENT_ACK BIT(1)
/*
* The host sets this bit to inform the Wlan
* FW that a TX packet is in the XFER
* Buffer #0.
*/
#define INTR_TRIG_TX_PROC0 BIT(2)
/*
* The host sets this bit to inform the FW
* that it read a packet from RX XFER
* Buffer #0.
*/
#define INTR_TRIG_RX_PROC0 BIT(3)
#define INTR_TRIG_DEBUG_ACK BIT(4)
#define INTR_TRIG_STATE_CHANGED BIT(5) /*===============================================
HI_CFG Interface Configuration Register Values
------------------------------------------
/* Hardware to Embedded CPU Interrupts - second 32-bit register set */ ===============================================*/
#define HI_CFG_UART_ENABLE 0x00000004
/* #define HI_CFG_RST232_ENABLE 0x00000008
* The host sets this bit to inform the FW #define HI_CFG_CLOCK_REQ_SELECT 0x00000010
* that it read a packet from RX XFER #define HI_CFG_HOST_INT_ENABLE 0x00000020
* Buffer #1. #define HI_CFG_VLYNQ_OUTPUT_ENABLE 0x00000040
*/ #define HI_CFG_HOST_INT_ACTIVE_LOW 0x00000080
#define INTR_TRIG_RX_PROC1 BIT(17) #define HI_CFG_UART_TX_OUT_GPIO_15 0x00000100
#define HI_CFG_UART_TX_OUT_GPIO_14 0x00000200
#define HI_CFG_UART_TX_OUT_GPIO_7 0x00000400
/* #define HI_CFG_DEF_VAL \
* The host sets this bit to inform the Wlan (HI_CFG_UART_ENABLE | \
* hardware that a TX packet is in the XFER HI_CFG_RST232_ENABLE | \
* Buffer #1. HI_CFG_CLOCK_REQ_SELECT | \
*/ HI_CFG_HOST_INT_ENABLE)
#define INTR_TRIG_TX_PROC1 BIT(18)
#define WL127X_REG_FUSE_DATA_2_1 0x050a #define WL127X_REG_FUSE_DATA_2_1 0x050a
#define WL128X_REG_FUSE_DATA_2_1 0x2152 #define WL128X_REG_FUSE_DATA_2_1 0x2152
......
/*
* This file is part of wl12xx
*
* Copyright (C) 2011 Texas Instruments Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#ifndef __WL12XX_PRIV_H__
#define __WL12XX_PRIV_H__
#include "conf.h"
struct wl12xx_priv {
struct wl12xx_priv_conf conf;
};
#endif /* __WL12XX_PRIV_H__ */
config WLCORE
tristate "TI wlcore support"
depends on WL_TI && GENERIC_HARDIRQS
depends on INET
select FW_LOADER
---help---
This module contains the main code for TI WLAN chips. It abstracts
hardware-specific differences among different chipset families.
Each chipset family needs to implement its own lower-level module
that will depend on this module for the common code.
If you choose to build a module, it will be called wlcore. Say N if
unsure.
config WLCORE_SPI
tristate "TI wlcore SPI support"
depends on WLCORE && SPI_MASTER
select CRC7
---help---
This module adds support for the SPI interface of adapters using
TI WLAN chipsets. Select this if your platform is using
the SPI bus.
If you choose to build a module, it'll be called wlcore_spi.
Say N if unsure.
config WLCORE_SDIO
tristate "TI wlcore SDIO support"
depends on WLCORE && MMC
---help---
This module adds support for the SDIO interface of adapters using
TI WLAN chipsets. Select this if your platform is using
the SDIO bus.
If you choose to build a module, it'll be called wlcore_sdio.
Say N if unsure.
config WL12XX_PLATFORM_DATA
bool
depends on WLCORE_SDIO != n || WL1251_SDIO != n
default y
wl12xx-objs = main.o cmd.o io.o event.o tx.o rx.o ps.o acx.o \ wlcore-objs = main.o cmd.o io.o event.o tx.o rx.o ps.o acx.o \
boot.o init.o debugfs.o scan.o boot.o init.o debugfs.o scan.o
wl12xx_spi-objs = spi.o wlcore_spi-objs = spi.o
wl12xx_sdio-objs = sdio.o wlcore_sdio-objs = sdio.o
wl12xx-$(CONFIG_NL80211_TESTMODE) += testmode.o wlcore-$(CONFIG_NL80211_TESTMODE) += testmode.o
obj-$(CONFIG_WL12XX) += wl12xx.o obj-$(CONFIG_WLCORE) += wlcore.o
obj-$(CONFIG_WL12XX_SPI) += wl12xx_spi.o obj-$(CONFIG_WLCORE_SPI) += wlcore_spi.o
obj-$(CONFIG_WL12XX_SDIO) += wl12xx_sdio.o obj-$(CONFIG_WLCORE_SDIO) += wlcore_sdio.o
# small builtin driver bit # small builtin driver bit
obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx_platform_data.o obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx_platform_data.o
......
...@@ -28,11 +28,11 @@ ...@@ -28,11 +28,11 @@
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/slab.h> #include <linux/slab.h>
#include "wl12xx.h" #include "wlcore.h"
#include "debug.h" #include "debug.h"
#include "wl12xx_80211.h" #include "wl12xx_80211.h"
#include "reg.h"
#include "ps.h" #include "ps.h"
#include "hw_ops.h"
int wl1271_acx_wake_up_conditions(struct wl1271 *wl, struct wl12xx_vif *wlvif, int wl1271_acx_wake_up_conditions(struct wl1271 *wl, struct wl12xx_vif *wlvif,
u8 wake_up_event, u8 listen_interval) u8 wake_up_event, u8 listen_interval)
...@@ -757,7 +757,10 @@ int wl1271_acx_sta_rate_policies(struct wl1271 *wl, struct wl12xx_vif *wlvif) ...@@ -757,7 +757,10 @@ int wl1271_acx_sta_rate_policies(struct wl1271 *wl, struct wl12xx_vif *wlvif)
/* configure one AP supported rate class */ /* configure one AP supported rate class */
acx->rate_policy_idx = cpu_to_le32(wlvif->sta.ap_rate_idx); acx->rate_policy_idx = cpu_to_le32(wlvif->sta.ap_rate_idx);
acx->rate_policy.enabled_rates = cpu_to_le32(wlvif->rate_set);
/* the AP policy is HW specific */
acx->rate_policy.enabled_rates =
cpu_to_le32(wlcore_hw_sta_get_ap_rate_mask(wl, wlvif));
acx->rate_policy.short_retry_limit = c->short_retry_limit; acx->rate_policy.short_retry_limit = c->short_retry_limit;
acx->rate_policy.long_retry_limit = c->long_retry_limit; acx->rate_policy.long_retry_limit = c->long_retry_limit;
acx->rate_policy.aflags = c->aflags; acx->rate_policy.aflags = c->aflags;
...@@ -969,17 +972,14 @@ int wl12xx_acx_mem_cfg(struct wl1271 *wl) ...@@ -969,17 +972,14 @@ int wl12xx_acx_mem_cfg(struct wl1271 *wl)
goto out; goto out;
} }
if (wl->chip.id == CHIP_ID_1283_PG20) mem = &wl->conf.mem;
mem = &wl->conf.mem_wl128x;
else
mem = &wl->conf.mem_wl127x;
/* memory config */ /* memory config */
mem_conf->num_stations = mem->num_stations; mem_conf->num_stations = mem->num_stations;
mem_conf->rx_mem_block_num = mem->rx_block_num; mem_conf->rx_mem_block_num = mem->rx_block_num;
mem_conf->tx_min_mem_block_num = mem->tx_min_block_num; mem_conf->tx_min_mem_block_num = mem->tx_min_block_num;
mem_conf->num_ssid_profiles = mem->ssid_profiles; mem_conf->num_ssid_profiles = mem->ssid_profiles;
mem_conf->total_tx_descriptors = cpu_to_le32(ACX_TX_DESCRIPTORS); mem_conf->total_tx_descriptors = cpu_to_le32(wl->num_tx_desc);
mem_conf->dyn_mem_enable = mem->dynamic_memory; mem_conf->dyn_mem_enable = mem->dynamic_memory;
mem_conf->tx_free_req = mem->min_req_tx_blocks; mem_conf->tx_free_req = mem->min_req_tx_blocks;
mem_conf->rx_free_req = mem->min_req_rx_blocks; mem_conf->rx_free_req = mem->min_req_rx_blocks;
...@@ -998,32 +998,6 @@ int wl12xx_acx_mem_cfg(struct wl1271 *wl) ...@@ -998,32 +998,6 @@ int wl12xx_acx_mem_cfg(struct wl1271 *wl)
return ret; return ret;
} }
int wl1271_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap)
{
struct wl1271_acx_host_config_bitmap *bitmap_conf;
int ret;
bitmap_conf = kzalloc(sizeof(*bitmap_conf), GFP_KERNEL);
if (!bitmap_conf) {
ret = -ENOMEM;
goto out;
}
bitmap_conf->host_cfg_bitmap = cpu_to_le32(host_cfg_bitmap);
ret = wl1271_cmd_configure(wl, ACX_HOST_IF_CFG_BITMAP,
bitmap_conf, sizeof(*bitmap_conf));
if (ret < 0) {
wl1271_warning("wl1271 bitmap config opt failed: %d", ret);
goto out;
}
out:
kfree(bitmap_conf);
return ret;
}
int wl1271_acx_init_mem_config(struct wl1271 *wl) int wl1271_acx_init_mem_config(struct wl1271 *wl)
{ {
int ret; int ret;
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
#ifndef __ACX_H__ #ifndef __ACX_H__
#define __ACX_H__ #define __ACX_H__
#include "wl12xx.h" #include "wlcore.h"
#include "cmd.h" #include "cmd.h"
/************************************************************************* /*************************************************************************
...@@ -824,16 +824,11 @@ struct wl1271_acx_keep_alive_config { ...@@ -824,16 +824,11 @@ struct wl1271_acx_keep_alive_config {
__le32 period; __le32 period;
} __packed; } __packed;
/* TODO: maybe this needs to be moved somewhere else? */
#define HOST_IF_CFG_RX_FIFO_ENABLE BIT(0) #define HOST_IF_CFG_RX_FIFO_ENABLE BIT(0)
#define HOST_IF_CFG_TX_EXTRA_BLKS_SWAP BIT(1) #define HOST_IF_CFG_TX_EXTRA_BLKS_SWAP BIT(1)
#define HOST_IF_CFG_TX_PAD_TO_SDIO_BLK BIT(3) #define HOST_IF_CFG_TX_PAD_TO_SDIO_BLK BIT(3)
struct wl1271_acx_host_config_bitmap {
struct acx_header header;
__le32 host_cfg_bitmap;
} __packed;
enum { enum {
WL1271_ACX_TRIG_TYPE_LEVEL = 0, WL1271_ACX_TRIG_TYPE_LEVEL = 0,
WL1271_ACX_TRIG_TYPE_EDGE, WL1271_ACX_TRIG_TYPE_EDGE,
...@@ -1274,7 +1269,6 @@ int wl1271_acx_frag_threshold(struct wl1271 *wl, u32 frag_threshold); ...@@ -1274,7 +1269,6 @@ int wl1271_acx_frag_threshold(struct wl1271 *wl, u32 frag_threshold);
int wl1271_acx_tx_config_options(struct wl1271 *wl); int wl1271_acx_tx_config_options(struct wl1271 *wl);
int wl12xx_acx_mem_cfg(struct wl1271 *wl); int wl12xx_acx_mem_cfg(struct wl1271 *wl);
int wl1271_acx_init_mem_config(struct wl1271 *wl); int wl1271_acx_init_mem_config(struct wl1271 *wl);
int wl1271_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap);
int wl1271_acx_init_rx_interrupt(struct wl1271 *wl); int wl1271_acx_init_rx_interrupt(struct wl1271 *wl);
int wl1271_acx_smart_reflex(struct wl1271 *wl); int wl1271_acx_smart_reflex(struct wl1271 *wl);
int wl1271_acx_bet_enable(struct wl1271 *wl, struct wl12xx_vif *wlvif, int wl1271_acx_bet_enable(struct wl1271 *wl, struct wl12xx_vif *wlvif,
......
...@@ -27,42 +27,25 @@ ...@@ -27,42 +27,25 @@
#include "debug.h" #include "debug.h"
#include "acx.h" #include "acx.h"
#include "reg.h"
#include "boot.h" #include "boot.h"
#include "io.h" #include "io.h"
#include "event.h" #include "event.h"
#include "rx.h" #include "rx.h"
#include "hw_ops.h"
static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag) static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag)
{ {
u32 cpu_ctrl; u32 cpu_ctrl;
/* 10.5.0 run the firmware (I) */ /* 10.5.0 run the firmware (I) */
cpu_ctrl = wl1271_read32(wl, ACX_REG_ECPU_CONTROL); cpu_ctrl = wlcore_read_reg(wl, REG_ECPU_CONTROL);
/* 10.5.1 run the firmware (II) */ /* 10.5.1 run the firmware (II) */
cpu_ctrl |= flag; cpu_ctrl |= flag;
wl1271_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl); wlcore_write_reg(wl, REG_ECPU_CONTROL, cpu_ctrl);
} }
static unsigned int wl12xx_get_fw_ver_quirks(struct wl1271 *wl) static int wlcore_parse_fw_ver(struct wl1271 *wl)
{
unsigned int quirks = 0;
unsigned int *fw_ver = wl->chip.fw_ver;
/* Only new station firmwares support routing fw logs to the host */
if ((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) &&
(fw_ver[FW_VER_MINOR] < FW_VER_MINOR_FWLOG_STA_MIN))
quirks |= WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED;
/* This feature is not yet supported for AP mode */
if (fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_AP)
quirks |= WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED;
return quirks;
}
static void wl1271_parse_fw_ver(struct wl1271 *wl)
{ {
int ret; int ret;
...@@ -74,33 +57,49 @@ static void wl1271_parse_fw_ver(struct wl1271 *wl) ...@@ -74,33 +57,49 @@ static void wl1271_parse_fw_ver(struct wl1271 *wl)
if (ret != 5) { if (ret != 5) {
wl1271_warning("fw version incorrect value"); wl1271_warning("fw version incorrect value");
memset(wl->chip.fw_ver, 0, sizeof(wl->chip.fw_ver)); memset(wl->chip.fw_ver, 0, sizeof(wl->chip.fw_ver));
return; return -EINVAL;
} }
/* Check if any quirks are needed with older fw versions */ ret = wlcore_identify_fw(wl);
wl->quirks |= wl12xx_get_fw_ver_quirks(wl); if (ret < 0)
return ret;
return 0;
} }
static void wl1271_boot_fw_version(struct wl1271 *wl) static int wlcore_boot_fw_version(struct wl1271 *wl)
{ {
struct wl1271_static_data static_data; struct wl1271_static_data *static_data;
int ret;
wl1271_read(wl, wl->cmd_box_addr, &static_data, sizeof(static_data), static_data = kmalloc(sizeof(*static_data), GFP_DMA);
if (!static_data) {
wl1271_error("Couldn't allocate memory for static data!");
return -ENOMEM;
}
wl1271_read(wl, wl->cmd_box_addr, static_data, sizeof(*static_data),
false); false);
strncpy(wl->chip.fw_ver_str, static_data.fw_version, strncpy(wl->chip.fw_ver_str, static_data->fw_version,
sizeof(wl->chip.fw_ver_str)); sizeof(wl->chip.fw_ver_str));
kfree(static_data);
/* make sure the string is NULL-terminated */ /* make sure the string is NULL-terminated */
wl->chip.fw_ver_str[sizeof(wl->chip.fw_ver_str) - 1] = '\0'; wl->chip.fw_ver_str[sizeof(wl->chip.fw_ver_str) - 1] = '\0';
wl1271_parse_fw_ver(wl); ret = wlcore_parse_fw_ver(wl);
if (ret < 0)
return ret;
return 0;
} }
static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
size_t fw_data_len, u32 dest) size_t fw_data_len, u32 dest)
{ {
struct wl1271_partition_set partition; struct wlcore_partition_set partition;
int addr, chunk_num, partition_limit; int addr, chunk_num, partition_limit;
u8 *p, *chunk; u8 *p, *chunk;
...@@ -122,13 +121,13 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, ...@@ -122,13 +121,13 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
return -ENOMEM; return -ENOMEM;
} }
memcpy(&partition, &wl12xx_part_table[PART_DOWN], sizeof(partition)); memcpy(&partition, &wl->ptable[PART_DOWN], sizeof(partition));
partition.mem.start = dest; partition.mem.start = dest;
wl1271_set_partition(wl, &partition); wlcore_set_partition(wl, &partition);
/* 10.1 set partition limit and chunk num */ /* 10.1 set partition limit and chunk num */
chunk_num = 0; chunk_num = 0;
partition_limit = wl12xx_part_table[PART_DOWN].mem.size; partition_limit = wl->ptable[PART_DOWN].mem.size;
while (chunk_num < fw_data_len / CHUNK_SIZE) { while (chunk_num < fw_data_len / CHUNK_SIZE) {
/* 10.2 update partition, if needed */ /* 10.2 update partition, if needed */
...@@ -136,9 +135,9 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, ...@@ -136,9 +135,9 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
if (addr > partition_limit) { if (addr > partition_limit) {
addr = dest + chunk_num * CHUNK_SIZE; addr = dest + chunk_num * CHUNK_SIZE;
partition_limit = chunk_num * CHUNK_SIZE + partition_limit = chunk_num * CHUNK_SIZE +
wl12xx_part_table[PART_DOWN].mem.size; wl->ptable[PART_DOWN].mem.size;
partition.mem.start = addr; partition.mem.start = addr;
wl1271_set_partition(wl, &partition); wlcore_set_partition(wl, &partition);
} }
/* 10.3 upload the chunk */ /* 10.3 upload the chunk */
...@@ -164,7 +163,7 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, ...@@ -164,7 +163,7 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
return 0; return 0;
} }
static int wl1271_boot_upload_firmware(struct wl1271 *wl) int wlcore_boot_upload_firmware(struct wl1271 *wl)
{ {
u32 chunks, addr, len; u32 chunks, addr, len;
int ret = 0; int ret = 0;
...@@ -196,8 +195,9 @@ static int wl1271_boot_upload_firmware(struct wl1271 *wl) ...@@ -196,8 +195,9 @@ static int wl1271_boot_upload_firmware(struct wl1271 *wl)
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(wlcore_boot_upload_firmware);
static int wl1271_boot_upload_nvs(struct wl1271 *wl) int wlcore_boot_upload_nvs(struct wl1271 *wl)
{ {
size_t nvs_len, burst_len; size_t nvs_len, burst_len;
int i; int i;
...@@ -207,27 +207,7 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) ...@@ -207,27 +207,7 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
if (wl->nvs == NULL) if (wl->nvs == NULL)
return -ENODEV; return -ENODEV;
if (wl->chip.id == CHIP_ID_1283_PG20) { if (wl->quirks & WLCORE_QUIRK_LEGACY_NVS) {
struct wl128x_nvs_file *nvs = (struct wl128x_nvs_file *)wl->nvs;
if (wl->nvs_len == sizeof(struct wl128x_nvs_file)) {
if (nvs->general_params.dual_mode_select)
wl->enable_11a = true;
} else {
wl1271_error("nvs size is not as expected: %zu != %zu",
wl->nvs_len,
sizeof(struct wl128x_nvs_file));
kfree(wl->nvs);
wl->nvs = NULL;
wl->nvs_len = 0;
return -EILSEQ;
}
/* only the first part of the NVS needs to be uploaded */
nvs_len = sizeof(nvs->nvs);
nvs_ptr = (u8 *)nvs->nvs;
} else {
struct wl1271_nvs_file *nvs = struct wl1271_nvs_file *nvs =
(struct wl1271_nvs_file *)wl->nvs; (struct wl1271_nvs_file *)wl->nvs;
/* /*
...@@ -255,6 +235,25 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) ...@@ -255,6 +235,25 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
/* only the first part of the NVS needs to be uploaded */ /* only the first part of the NVS needs to be uploaded */
nvs_len = sizeof(nvs->nvs); nvs_len = sizeof(nvs->nvs);
nvs_ptr = (u8 *) nvs->nvs; nvs_ptr = (u8 *) nvs->nvs;
} else {
struct wl128x_nvs_file *nvs = (struct wl128x_nvs_file *)wl->nvs;
if (wl->nvs_len == sizeof(struct wl128x_nvs_file)) {
if (nvs->general_params.dual_mode_select)
wl->enable_11a = true;
} else {
wl1271_error("nvs size is not as expected: %zu != %zu",
wl->nvs_len,
sizeof(struct wl128x_nvs_file));
kfree(wl->nvs);
wl->nvs = NULL;
wl->nvs_len = 0;
return -EILSEQ;
}
/* only the first part of the NVS needs to be uploaded */
nvs_len = sizeof(nvs->nvs);
nvs_ptr = (u8 *)nvs->nvs;
} }
/* update current MAC address to NVS */ /* update current MAC address to NVS */
...@@ -281,9 +280,10 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) ...@@ -281,9 +280,10 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
/* /*
* Due to our new wl1271_translate_reg_addr function, * Due to our new wl1271_translate_reg_addr function,
* we need to add the REGISTER_BASE to the destination * we need to add the register partition start address
* to the destination
*/ */
dest_addr += REGISTERS_BASE; dest_addr += wl->curr_part.reg.start;
/* We move our pointer to the data */ /* We move our pointer to the data */
nvs_ptr += 3; nvs_ptr += 3;
...@@ -324,7 +324,7 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) ...@@ -324,7 +324,7 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
nvs_len -= nvs_ptr - (u8 *)wl->nvs; nvs_len -= nvs_ptr - (u8 *)wl->nvs;
/* Now we must set the partition correctly */ /* Now we must set the partition correctly */
wl1271_set_partition(wl, &wl12xx_part_table[PART_WORK]); wlcore_set_partition(wl, &wl->ptable[PART_WORK]);
/* Copy the NVS tables to a new block to ensure alignment */ /* Copy the NVS tables to a new block to ensure alignment */
nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL); nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL);
...@@ -332,7 +332,8 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) ...@@ -332,7 +332,8 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
return -ENOMEM; return -ENOMEM;
/* And finally we upload the NVS tables */ /* And finally we upload the NVS tables */
wl1271_write(wl, CMD_MBOX_ADDRESS, nvs_aligned, nvs_len, false); wlcore_write_data(wl, REG_CMD_MBOX_ADDRESS,
nvs_aligned, nvs_len, false);
kfree(nvs_aligned); kfree(nvs_aligned);
return 0; return 0;
...@@ -341,58 +342,19 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) ...@@ -341,58 +342,19 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
wl1271_error("nvs data is malformed"); wl1271_error("nvs data is malformed");
return -EILSEQ; return -EILSEQ;
} }
EXPORT_SYMBOL_GPL(wlcore_boot_upload_nvs);
static void wl1271_boot_enable_interrupts(struct wl1271 *wl) int wlcore_boot_run_firmware(struct wl1271 *wl)
{
wl1271_enable_interrupts(wl);
wl1271_write32(wl, ACX_REG_INTERRUPT_MASK,
WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
wl1271_write32(wl, HI_CFG, HI_CFG_DEF_VAL);
}
static int wl1271_boot_soft_reset(struct wl1271 *wl)
{
unsigned long timeout;
u32 boot_data;
/* perform soft reset */
wl1271_write32(wl, ACX_REG_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT);
/* SOFT_RESET is self clearing */
timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME);
while (1) {
boot_data = wl1271_read32(wl, ACX_REG_SLV_SOFT_RESET);
wl1271_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data);
if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0)
break;
if (time_after(jiffies, timeout)) {
/* 1.2 check pWhalBus->uSelfClearTime if the
* timeout was reached */
wl1271_error("soft reset timeout");
return -1;
}
udelay(SOFT_RESET_STALL_TIME);
}
/* disable Rx/Tx */
wl1271_write32(wl, ENABLE, 0x0);
/* disable auto calibration on start*/
wl1271_write32(wl, SPARE_A2, 0xffff);
return 0;
}
static int wl1271_boot_run_firmware(struct wl1271 *wl)
{ {
int loop, ret; int loop, ret;
u32 chip_id, intr; u32 chip_id, intr;
/* Make sure we have the boot partition */
wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
wl1271_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT); wl1271_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT);
chip_id = wl1271_read32(wl, CHIP_ID_B); chip_id = wlcore_read_reg(wl, REG_CHIP_ID_B);
wl1271_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id); wl1271_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id);
...@@ -405,7 +367,7 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl) ...@@ -405,7 +367,7 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
loop = 0; loop = 0;
while (loop++ < INIT_LOOP) { while (loop++ < INIT_LOOP) {
udelay(INIT_LOOP_DELAY); udelay(INIT_LOOP_DELAY);
intr = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); intr = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR);
if (intr == 0xffffffff) { if (intr == 0xffffffff) {
wl1271_error("error reading hardware complete " wl1271_error("error reading hardware complete "
...@@ -414,7 +376,7 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl) ...@@ -414,7 +376,7 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
} }
/* check that ACX_INTR_INIT_COMPLETE is enabled */ /* check that ACX_INTR_INIT_COMPLETE is enabled */
else if (intr & WL1271_ACX_INTR_INIT_COMPLETE) { else if (intr & WL1271_ACX_INTR_INIT_COMPLETE) {
wl1271_write32(wl, ACX_REG_INTERRUPT_ACK, wlcore_write_reg(wl, REG_INTERRUPT_ACK,
WL1271_ACX_INTR_INIT_COMPLETE); WL1271_ACX_INTR_INIT_COMPLETE);
break; break;
} }
...@@ -427,18 +389,22 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl) ...@@ -427,18 +389,22 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
} }
/* get hardware config command mail box */ /* get hardware config command mail box */
wl->cmd_box_addr = wl1271_read32(wl, REG_COMMAND_MAILBOX_PTR); wl->cmd_box_addr = wlcore_read_reg(wl, REG_COMMAND_MAILBOX_PTR);
/* get hardware config event mail box */ wl1271_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x", wl->cmd_box_addr);
wl->event_box_addr = wl1271_read32(wl, REG_EVENT_MAILBOX_PTR);
/* set the working partition to its "running" mode offset */ /* get hardware config event mail box */
wl1271_set_partition(wl, &wl12xx_part_table[PART_WORK]); wl->mbox_ptr[0] = wlcore_read_reg(wl, REG_EVENT_MAILBOX_PTR);
wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox);
wl1271_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x", wl1271_debug(DEBUG_MAILBOX, "MBOX ptrs: 0x%x 0x%x",
wl->cmd_box_addr, wl->event_box_addr); wl->mbox_ptr[0], wl->mbox_ptr[1]);
wl1271_boot_fw_version(wl); ret = wlcore_boot_fw_version(wl);
if (ret < 0) {
wl1271_error("couldn't boot firmware");
return ret;
}
/* /*
* in case of full asynchronous mode the firmware event must be * in case of full asynchronous mode the firmware event must be
...@@ -468,319 +434,10 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl) ...@@ -468,319 +434,10 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
return ret; return ret;
} }
wl1271_event_mbox_config(wl); /* set the working partition to its "running" mode offset */
wlcore_set_partition(wl, &wl->ptable[PART_WORK]);
/* firmware startup completed */ /* firmware startup completed */
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(wlcore_boot_run_firmware);
static int wl1271_boot_write_irq_polarity(struct wl1271 *wl)
{
u32 polarity;
polarity = wl1271_top_reg_read(wl, OCP_REG_POLARITY);
/* We use HIGH polarity, so unset the LOW bit */
polarity &= ~POLARITY_LOW;
wl1271_top_reg_write(wl, OCP_REG_POLARITY, polarity);
return 0;
}
static int wl128x_switch_tcxo_to_fref(struct wl1271 *wl)
{
u16 spare_reg;
/* Mask bits [2] & [8:4] in the sys_clk_cfg register */
spare_reg = wl1271_top_reg_read(wl, WL_SPARE_REG);
if (spare_reg == 0xFFFF)
return -EFAULT;
spare_reg |= (BIT(3) | BIT(5) | BIT(6));
wl1271_top_reg_write(wl, WL_SPARE_REG, spare_reg);
/* Enable FREF_CLK_REQ & mux MCS and coex PLLs to FREF */
wl1271_top_reg_write(wl, SYS_CLK_CFG_REG,
WL_CLK_REQ_TYPE_PG2 | MCS_PLL_CLK_SEL_FREF);
/* Delay execution for 15msec, to let the HW settle */
mdelay(15);
return 0;
}
static bool wl128x_is_tcxo_valid(struct wl1271 *wl)
{
u16 tcxo_detection;
tcxo_detection = wl1271_top_reg_read(wl, TCXO_CLK_DETECT_REG);
if (tcxo_detection & TCXO_DET_FAILED)
return false;
return true;
}
static bool wl128x_is_fref_valid(struct wl1271 *wl)
{
u16 fref_detection;
fref_detection = wl1271_top_reg_read(wl, FREF_CLK_DETECT_REG);
if (fref_detection & FREF_CLK_DETECT_FAIL)
return false;
return true;
}
static int wl128x_manually_configure_mcs_pll(struct wl1271 *wl)
{
wl1271_top_reg_write(wl, MCS_PLL_M_REG, MCS_PLL_M_REG_VAL);
wl1271_top_reg_write(wl, MCS_PLL_N_REG, MCS_PLL_N_REG_VAL);
wl1271_top_reg_write(wl, MCS_PLL_CONFIG_REG, MCS_PLL_CONFIG_REG_VAL);
return 0;
}
static int wl128x_configure_mcs_pll(struct wl1271 *wl, int clk)
{
u16 spare_reg;
u16 pll_config;
u8 input_freq;
/* Mask bits [3:1] in the sys_clk_cfg register */
spare_reg = wl1271_top_reg_read(wl, WL_SPARE_REG);
if (spare_reg == 0xFFFF)
return -EFAULT;
spare_reg |= BIT(2);
wl1271_top_reg_write(wl, WL_SPARE_REG, spare_reg);
/* Handle special cases of the TCXO clock */
if (wl->tcxo_clock == WL12XX_TCXOCLOCK_16_8 ||
wl->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 = wl1271_top_reg_read(wl, MCS_PLL_CONFIG_REG);
if (pll_config == 0xFFFF)
return -EFAULT;
pll_config |= (input_freq << MCS_SEL_IN_FREQ_SHIFT);
pll_config |= MCS_PLL_ENABLE_HP;
wl1271_top_reg_write(wl, MCS_PLL_CONFIG_REG, pll_config);
return 0;
}
/*
* WL128x has two clocks input - TCXO and FREF.
* TCXO is the main clock of the device, while FREF is used to sync
* between the GPS and the cellular modem.
* In cases where TCXO is 32.736MHz or 16.368MHz, the FREF will be used
* as the WLAN/BT main clock.
*/
static int wl128x_boot_clk(struct wl1271 *wl, int *selected_clock)
{
u16 sys_clk_cfg;
/* 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 (!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 = wl1271_top_reg_read(wl, SYS_CLK_CFG_REG);
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 (!wl128x_switch_tcxo_to_fref(wl))
return -EINVAL;
goto fref_clk;
}
/* TCXO clock is selected */
if (!wl128x_is_tcxo_valid(wl))
return -EINVAL;
*selected_clock = wl->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;
config_mcs_pll:
return wl128x_configure_mcs_pll(wl, *selected_clock);
}
static int wl127x_boot_clk(struct wl1271 *wl)
{
u32 pause;
u32 clk;
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 ||
wl->ref_clock == CONF_REF_CLK_38_4_E ||
wl->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)
/* ref clk: 26/52 */
clk = 0x5;
else
return -EINVAL;
if (wl->ref_clock != CONF_REF_CLK_19_2_E) {
u16 val;
/* Set clock type (open drain) */
val = wl1271_top_reg_read(wl, OCP_REG_CLK_TYPE);
val &= FREF_CLK_TYPE_BITS;
wl1271_top_reg_write(wl, OCP_REG_CLK_TYPE, val);
/* Set clock pull mode (no pull) */
val = wl1271_top_reg_read(wl, OCP_REG_CLK_PULL);
val |= NO_PULL;
wl1271_top_reg_write(wl, OCP_REG_CLK_PULL, val);
} else {
u16 val;
/* Set clock polarity */
val = wl1271_top_reg_read(wl, OCP_REG_CLK_POLARITY);
val &= FREF_CLK_POLARITY_BITS;
val |= CLK_REQ_OUTN_SEL;
wl1271_top_reg_write(wl, OCP_REG_CLK_POLARITY, val);
}
wl1271_write32(wl, PLL_PARAMETERS, clk);
pause = wl1271_read32(wl, PLL_PARAMETERS);
wl1271_debug(DEBUG_BOOT, "pause1 0x%x", pause);
pause &= ~(WU_COUNTER_PAUSE_VAL);
pause |= WU_COUNTER_PAUSE_VAL;
wl1271_write32(wl, WU_COUNTER_PAUSE, pause);
return 0;
}
/* uploads NVS and firmware */
int wl1271_load_firmware(struct wl1271 *wl)
{
int ret = 0;
u32 tmp, clk;
int selected_clock = -1;
if (wl->chip.id == CHIP_ID_1283_PG20) {
ret = wl128x_boot_clk(wl, &selected_clock);
if (ret < 0)
goto out;
} else {
ret = wl127x_boot_clk(wl);
if (ret < 0)
goto out;
}
/* Continue the ELP wake up sequence */
wl1271_write32(wl, WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL);
udelay(500);
wl1271_set_partition(wl, &wl12xx_part_table[PART_DRPW]);
/* 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 */
wl1271_debug(DEBUG_BOOT, "DRPW_SCRATCH_START %08x", DRPW_SCRATCH_START);
clk = wl1271_read32(wl, DRPW_SCRATCH_START);
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;
}
wl1271_write32(wl, DRPW_SCRATCH_START, clk);
wl1271_set_partition(wl, &wl12xx_part_table[PART_WORK]);
/* Disable interrupts */
wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
ret = wl1271_boot_soft_reset(wl);
if (ret < 0)
goto out;
/* 2. start processing NVS file */
ret = wl1271_boot_upload_nvs(wl);
if (ret < 0)
goto out;
/* 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, ACX_EEPROMLESS_IND_REG, ACX_EEPROMLESS_IND_REG);
tmp = wl1271_read32(wl, CHIP_ID_B);
wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp);
/* 6. read the EEPROM parameters */
tmp = wl1271_read32(wl, SCR_PAD2);
/* WL1271: The reference driver skips steps 7 to 10 (jumps directly
* to upload_fw) */
if (wl->chip.id == CHIP_ID_1283_PG20)
wl1271_top_reg_write(wl, SDIO_IO_DS, wl->conf.hci_io_ds);
ret = wl1271_boot_upload_firmware(wl);
if (ret < 0)
goto out;
out:
return ret;
}
EXPORT_SYMBOL_GPL(wl1271_load_firmware);
int wl1271_boot(struct wl1271 *wl)
{
int ret;
/* upload NVS and firmware */
ret = wl1271_load_firmware(wl);
if (ret)
return ret;
/* 10.5 start firmware */
ret = wl1271_boot_run_firmware(wl);
if (ret < 0)
goto out;
ret = wl1271_boot_write_irq_polarity(wl);
if (ret < 0)
goto out;
wl1271_write32(wl, ACX_REG_INTERRUPT_MASK,
WL1271_ACX_ALL_EVENTS_VECTOR);
/* Enable firmware interrupts now */
wl1271_boot_enable_interrupts(wl);
wl1271_event_mbox_config(wl);
out:
return ret;
}
/*
* This file is part of wl1271
*
* Copyright (C) 2008-2009 Nokia Corporation
*
* Contact: Luciano Coelho <luciano.coelho@nokia.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#ifndef __BOOT_H__
#define __BOOT_H__
#include "wlcore.h"
int wlcore_boot_upload_firmware(struct wl1271 *wl);
int wlcore_boot_upload_nvs(struct wl1271 *wl);
int wlcore_boot_run_firmware(struct wl1271 *wl);
#define WL1271_NO_SUBBANDS 8
#define WL1271_NO_POWER_LEVELS 4
#define WL1271_FW_VERSION_MAX_LEN 20
struct wl1271_static_data {
u8 mac_address[ETH_ALEN];
u8 padding[2];
u8 fw_version[WL1271_FW_VERSION_MAX_LEN];
u32 hw_version;
u8 tx_power_table[WL1271_NO_SUBBANDS][WL1271_NO_POWER_LEVELS];
};
/* number of times we try to read the INIT interrupt */
#define INIT_LOOP 20000
/* delay between retries */
#define INIT_LOOP_DELAY 50
#define WU_COUNTER_PAUSE_VAL 0x3FF
#define WELP_ARM_COMMAND_VAL 0x4
#endif
...@@ -28,9 +28,8 @@ ...@@ -28,9 +28,8 @@
#include <linux/ieee80211.h> #include <linux/ieee80211.h>
#include <linux/slab.h> #include <linux/slab.h>
#include "wl12xx.h" #include "wlcore.h"
#include "debug.h" #include "debug.h"
#include "reg.h"
#include "io.h" #include "io.h"
#include "acx.h" #include "acx.h"
#include "wl12xx_80211.h" #include "wl12xx_80211.h"
...@@ -67,11 +66,15 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, ...@@ -67,11 +66,15 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
wl1271_write(wl, wl->cmd_box_addr, buf, len, false); wl1271_write(wl, wl->cmd_box_addr, buf, len, false);
wl1271_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD); /*
* TODO: we just need this because one bit is in a different
* place. Is there any better way?
*/
wl->ops->trigger_cmd(wl, wl->cmd_box_addr, buf, len);
timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT); timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT);
intr = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); intr = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR);
while (!(intr & WL1271_ACX_INTR_CMD_COMPLETE)) { while (!(intr & WL1271_ACX_INTR_CMD_COMPLETE)) {
if (time_after(jiffies, timeout)) { if (time_after(jiffies, timeout)) {
wl1271_error("command complete timeout"); wl1271_error("command complete timeout");
...@@ -85,7 +88,7 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, ...@@ -85,7 +88,7 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
else else
msleep(1); msleep(1);
intr = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); intr = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR);
} }
/* read back the status code of the command */ /* read back the status code of the command */
...@@ -100,8 +103,7 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, ...@@ -100,8 +103,7 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
goto fail; goto fail;
} }
wl1271_write32(wl, ACX_REG_INTERRUPT_ACK, wlcore_write_reg(wl, REG_INTERRUPT_ACK, WL1271_ACX_INTR_CMD_COMPLETE);
WL1271_ACX_INTR_CMD_COMPLETE);
return 0; return 0;
fail: fail:
...@@ -110,240 +112,18 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, ...@@ -110,240 +112,18 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
return ret; return ret;
} }
int wl1271_cmd_general_parms(struct wl1271 *wl)
{
struct wl1271_general_parms_cmd *gen_parms;
struct wl1271_ini_general_params *gp =
&((struct wl1271_nvs_file *)wl->nvs)->general_params;
bool answer = false;
int ret;
if (!wl->nvs)
return -ENODEV;
if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) {
wl1271_warning("FEM index from INI out of bounds");
return -EINVAL;
}
gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL);
if (!gen_parms)
return -ENOMEM;
gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM;
memcpy(&gen_parms->general_params, gp, sizeof(*gp));
if (gp->tx_bip_fem_auto_detect)
answer = true;
/* Override the REF CLK from the NVS with the one from platform data */
gen_parms->general_params.ref_clock = wl->ref_clock;
ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer);
if (ret < 0) {
wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed");
goto out;
}
gp->tx_bip_fem_manufacturer =
gen_parms->general_params.tx_bip_fem_manufacturer;
if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) {
wl1271_warning("FEM index from FW out of bounds");
ret = -EINVAL;
goto out;
}
wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n",
answer ? "auto" : "manual", gp->tx_bip_fem_manufacturer);
out:
kfree(gen_parms);
return ret;
}
int wl128x_cmd_general_parms(struct wl1271 *wl)
{
struct wl128x_general_parms_cmd *gen_parms;
struct wl128x_ini_general_params *gp =
&((struct wl128x_nvs_file *)wl->nvs)->general_params;
bool answer = false;
int ret;
if (!wl->nvs)
return -ENODEV;
if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) {
wl1271_warning("FEM index from ini out of bounds");
return -EINVAL;
}
gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL);
if (!gen_parms)
return -ENOMEM;
gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM;
memcpy(&gen_parms->general_params, gp, sizeof(*gp));
if (gp->tx_bip_fem_auto_detect)
answer = true;
/* Replace REF and TCXO CLKs with the ones from platform data */
gen_parms->general_params.ref_clock = wl->ref_clock;
gen_parms->general_params.tcxo_ref_clock = wl->tcxo_clock;
ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer);
if (ret < 0) {
wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed");
goto out;
}
gp->tx_bip_fem_manufacturer =
gen_parms->general_params.tx_bip_fem_manufacturer;
if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) {
wl1271_warning("FEM index from FW out of bounds");
ret = -EINVAL;
goto out;
}
wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n",
answer ? "auto" : "manual", gp->tx_bip_fem_manufacturer);
out:
kfree(gen_parms);
return ret;
}
int wl1271_cmd_radio_parms(struct wl1271 *wl)
{
struct wl1271_nvs_file *nvs = (struct wl1271_nvs_file *)wl->nvs;
struct wl1271_radio_parms_cmd *radio_parms;
struct wl1271_ini_general_params *gp = &nvs->general_params;
int ret;
if (!wl->nvs)
return -ENODEV;
radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL);
if (!radio_parms)
return -ENOMEM;
radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM;
/* 2.4GHz parameters */
memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2,
sizeof(struct wl1271_ini_band_params_2));
memcpy(&radio_parms->dyn_params_2,
&nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params,
sizeof(struct wl1271_ini_fem_params_2));
/* 5GHz parameters */
memcpy(&radio_parms->static_params_5,
&nvs->stat_radio_params_5,
sizeof(struct wl1271_ini_band_params_5));
memcpy(&radio_parms->dyn_params_5,
&nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params,
sizeof(struct wl1271_ini_fem_params_5));
wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ",
radio_parms, sizeof(*radio_parms));
ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0);
if (ret < 0)
wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed");
kfree(radio_parms);
return ret;
}
int wl128x_cmd_radio_parms(struct wl1271 *wl)
{
struct wl128x_nvs_file *nvs = (struct wl128x_nvs_file *)wl->nvs;
struct wl128x_radio_parms_cmd *radio_parms;
struct wl128x_ini_general_params *gp = &nvs->general_params;
int ret;
if (!wl->nvs)
return -ENODEV;
radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL);
if (!radio_parms)
return -ENOMEM;
radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM;
/* 2.4GHz parameters */
memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2,
sizeof(struct wl128x_ini_band_params_2));
memcpy(&radio_parms->dyn_params_2,
&nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params,
sizeof(struct wl128x_ini_fem_params_2));
/* 5GHz parameters */
memcpy(&radio_parms->static_params_5,
&nvs->stat_radio_params_5,
sizeof(struct wl128x_ini_band_params_5));
memcpy(&radio_parms->dyn_params_5,
&nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params,
sizeof(struct wl128x_ini_fem_params_5));
radio_parms->fem_vendor_and_options = nvs->fem_vendor_and_options;
wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ",
radio_parms, sizeof(*radio_parms));
ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0);
if (ret < 0)
wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed");
kfree(radio_parms);
return ret;
}
int wl1271_cmd_ext_radio_parms(struct wl1271 *wl)
{
struct wl1271_ext_radio_parms_cmd *ext_radio_parms;
struct conf_rf_settings *rf = &wl->conf.rf;
int ret;
if (!wl->nvs)
return -ENODEV;
ext_radio_parms = kzalloc(sizeof(*ext_radio_parms), GFP_KERNEL);
if (!ext_radio_parms)
return -ENOMEM;
ext_radio_parms->test.id = TEST_CMD_INI_FILE_RF_EXTENDED_PARAM;
memcpy(ext_radio_parms->tx_per_channel_power_compensation_2,
rf->tx_per_channel_power_compensation_2,
CONF_TX_PWR_COMPENSATION_LEN_2);
memcpy(ext_radio_parms->tx_per_channel_power_compensation_5,
rf->tx_per_channel_power_compensation_5,
CONF_TX_PWR_COMPENSATION_LEN_5);
wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_EXT_RADIO_PARAM: ",
ext_radio_parms, sizeof(*ext_radio_parms));
ret = wl1271_cmd_test(wl, ext_radio_parms, sizeof(*ext_radio_parms), 0);
if (ret < 0)
wl1271_warning("TEST_CMD_INI_FILE_RF_EXTENDED_PARAM failed");
kfree(ext_radio_parms);
return ret;
}
/* /*
* Poll the mailbox event field until any of the bits in the mask is set or a * Poll the mailbox event field until any of the bits in the mask is set or a
* timeout occurs (WL1271_EVENT_TIMEOUT in msecs) * timeout occurs (WL1271_EVENT_TIMEOUT in msecs)
*/ */
static int wl1271_cmd_wait_for_event_or_timeout(struct wl1271 *wl, u32 mask) static int wl1271_cmd_wait_for_event_or_timeout(struct wl1271 *wl, u32 mask)
{ {
u32 events_vector, event; u32 *events_vector;
u32 event;
unsigned long timeout; unsigned long timeout;
int ret = 0;
events_vector = kmalloc(sizeof(*events_vector), GFP_DMA);
timeout = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT); timeout = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT);
...@@ -351,21 +131,24 @@ static int wl1271_cmd_wait_for_event_or_timeout(struct wl1271 *wl, u32 mask) ...@@ -351,21 +131,24 @@ static int wl1271_cmd_wait_for_event_or_timeout(struct wl1271 *wl, u32 mask)
if (time_after(jiffies, timeout)) { if (time_after(jiffies, timeout)) {
wl1271_debug(DEBUG_CMD, "timeout waiting for event %d", wl1271_debug(DEBUG_CMD, "timeout waiting for event %d",
(int)mask); (int)mask);
return -ETIMEDOUT; ret = -ETIMEDOUT;
goto out;
} }
msleep(1); msleep(1);
/* read from both event fields */ /* read from both event fields */
wl1271_read(wl, wl->mbox_ptr[0], &events_vector, wl1271_read(wl, wl->mbox_ptr[0], events_vector,
sizeof(events_vector), false); sizeof(*events_vector), false);
event = events_vector & mask; event = *events_vector & mask;
wl1271_read(wl, wl->mbox_ptr[1], &events_vector, wl1271_read(wl, wl->mbox_ptr[1], events_vector,
sizeof(events_vector), false); sizeof(*events_vector), false);
event |= events_vector & mask; event |= *events_vector & mask;
} while (!event); } while (!event);
return 0; out:
kfree(events_vector);
return ret;
} }
static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask) static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask)
...@@ -522,7 +305,7 @@ static int wl12xx_cmd_role_start_dev(struct wl1271 *wl, ...@@ -522,7 +305,7 @@ static int wl12xx_cmd_role_start_dev(struct wl1271 *wl,
cmd->role_id = wlvif->dev_role_id; cmd->role_id = wlvif->dev_role_id;
if (wlvif->band == IEEE80211_BAND_5GHZ) if (wlvif->band == IEEE80211_BAND_5GHZ)
cmd->band = WL12XX_BAND_5GHZ; cmd->band = WLCORE_BAND_5GHZ;
cmd->channel = wlvif->channel; cmd->channel = wlvif->channel;
if (wlvif->dev_hlid == WL12XX_INVALID_LINK_ID) { if (wlvif->dev_hlid == WL12XX_INVALID_LINK_ID) {
...@@ -613,7 +396,7 @@ int wl12xx_cmd_role_start_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif) ...@@ -613,7 +396,7 @@ int wl12xx_cmd_role_start_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif)
cmd->role_id = wlvif->role_id; cmd->role_id = wlvif->role_id;
if (wlvif->band == IEEE80211_BAND_5GHZ) if (wlvif->band == IEEE80211_BAND_5GHZ)
cmd->band = WL12XX_BAND_5GHZ; cmd->band = WLCORE_BAND_5GHZ;
cmd->channel = wlvif->channel; cmd->channel = wlvif->channel;
cmd->sta.basic_rate_set = cpu_to_le32(wlvif->basic_rate_set); cmd->sta.basic_rate_set = cpu_to_le32(wlvif->basic_rate_set);
cmd->sta.beacon_interval = cpu_to_le16(wlvif->beacon_int); cmd->sta.beacon_interval = cpu_to_le16(wlvif->beacon_int);
...@@ -750,14 +533,14 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif) ...@@ -750,14 +533,14 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif)
switch (wlvif->band) { switch (wlvif->band) {
case IEEE80211_BAND_2GHZ: case IEEE80211_BAND_2GHZ:
cmd->band = RADIO_BAND_2_4GHZ; cmd->band = WLCORE_BAND_2_4GHZ;
break; break;
case IEEE80211_BAND_5GHZ: case IEEE80211_BAND_5GHZ:
cmd->band = RADIO_BAND_5GHZ; cmd->band = WLCORE_BAND_5GHZ;
break; break;
default: default:
wl1271_warning("ap start - unknown band: %d", (int)wlvif->band); wl1271_warning("ap start - unknown band: %d", (int)wlvif->band);
cmd->band = RADIO_BAND_2_4GHZ; cmd->band = WLCORE_BAND_2_4GHZ;
break; break;
} }
...@@ -830,7 +613,7 @@ int wl12xx_cmd_role_start_ibss(struct wl1271 *wl, struct wl12xx_vif *wlvif) ...@@ -830,7 +613,7 @@ int wl12xx_cmd_role_start_ibss(struct wl1271 *wl, struct wl12xx_vif *wlvif)
cmd->role_id = wlvif->role_id; cmd->role_id = wlvif->role_id;
if (wlvif->band == IEEE80211_BAND_5GHZ) if (wlvif->band == IEEE80211_BAND_5GHZ)
cmd->band = WL12XX_BAND_5GHZ; cmd->band = WLCORE_BAND_5GHZ;
cmd->channel = wlvif->channel; cmd->channel = wlvif->channel;
cmd->ibss.basic_rate_set = cpu_to_le32(wlvif->basic_rate_set); cmd->ibss.basic_rate_set = cpu_to_le32(wlvif->basic_rate_set);
cmd->ibss.beacon_interval = cpu_to_le16(wlvif->beacon_int); cmd->ibss.beacon_interval = cpu_to_le16(wlvif->beacon_int);
...@@ -904,6 +687,7 @@ int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer) ...@@ -904,6 +687,7 @@ int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer)
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(wl1271_cmd_test);
/** /**
* read acx from firmware * read acx from firmware
...@@ -960,6 +744,7 @@ int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len) ...@@ -960,6 +744,7 @@ int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len)
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(wl1271_cmd_configure);
int wl1271_cmd_data_path(struct wl1271 *wl, bool enable) int wl1271_cmd_data_path(struct wl1271 *wl, bool enable)
{ {
...@@ -1730,10 +1515,10 @@ static int wl12xx_cmd_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, ...@@ -1730,10 +1515,10 @@ static int wl12xx_cmd_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif,
cmd->channel = wlvif->channel; cmd->channel = wlvif->channel;
switch (wlvif->band) { switch (wlvif->band) {
case IEEE80211_BAND_2GHZ: case IEEE80211_BAND_2GHZ:
cmd->band = RADIO_BAND_2_4GHZ; cmd->band = WLCORE_BAND_2_4GHZ;
break; break;
case IEEE80211_BAND_5GHZ: case IEEE80211_BAND_5GHZ:
cmd->band = RADIO_BAND_5GHZ; cmd->band = WLCORE_BAND_5GHZ;
break; break;
default: default:
wl1271_error("roc - unknown band: %d", (int)wlvif->band); wl1271_error("roc - unknown band: %d", (int)wlvif->band);
......
...@@ -25,17 +25,12 @@ ...@@ -25,17 +25,12 @@
#ifndef __CMD_H__ #ifndef __CMD_H__
#define __CMD_H__ #define __CMD_H__
#include "wl12xx.h" #include "wlcore.h"
struct acx_header; struct acx_header;
int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
size_t res_len); size_t res_len);
int wl1271_cmd_general_parms(struct wl1271 *wl);
int wl128x_cmd_general_parms(struct wl1271 *wl);
int wl1271_cmd_radio_parms(struct wl1271 *wl);
int wl128x_cmd_radio_parms(struct wl1271 *wl);
int wl1271_cmd_ext_radio_parms(struct wl1271 *wl);
int wl12xx_cmd_role_enable(struct wl1271 *wl, u8 *addr, u8 role_type, int wl12xx_cmd_role_enable(struct wl1271 *wl, u8 *addr, u8 role_type,
u8 *role_id); u8 *role_id);
int wl12xx_cmd_role_disable(struct wl1271 *wl, u8 *role_id); int wl12xx_cmd_role_disable(struct wl1271 *wl, u8 *role_id);
...@@ -262,13 +257,13 @@ struct wl12xx_cmd_role_disable { ...@@ -262,13 +257,13 @@ struct wl12xx_cmd_role_disable {
u8 padding[3]; u8 padding[3];
} __packed; } __packed;
enum wl12xx_band { enum wlcore_band {
WL12XX_BAND_2_4GHZ = 0, WLCORE_BAND_2_4GHZ = 0,
WL12XX_BAND_5GHZ = 1, WLCORE_BAND_5GHZ = 1,
WL12XX_BAND_JAPAN_4_9_GHZ = 2, WLCORE_BAND_JAPAN_4_9_GHZ = 2,
WL12XX_BAND_DEFAULT = WL12XX_BAND_2_4GHZ, WLCORE_BAND_DEFAULT = WLCORE_BAND_2_4GHZ,
WL12XX_BAND_INVALID = 0x7E, WLCORE_BAND_INVALID = 0x7E,
WL12XX_BAND_MAX_RADIO = 0x7F, WLCORE_BAND_MAX_RADIO = 0x7F,
}; };
struct wl12xx_cmd_role_start { struct wl12xx_cmd_role_start {
...@@ -494,83 +489,6 @@ enum wl1271_channel_tune_bands { ...@@ -494,83 +489,6 @@ enum wl1271_channel_tune_bands {
#define WL1271_PD_REFERENCE_POINT_BAND_B_G 0 #define WL1271_PD_REFERENCE_POINT_BAND_B_G 0
#define TEST_CMD_INI_FILE_RADIO_PARAM 0x19
#define TEST_CMD_INI_FILE_GENERAL_PARAM 0x1E
#define TEST_CMD_INI_FILE_RF_EXTENDED_PARAM 0x26
struct wl1271_general_parms_cmd {
struct wl1271_cmd_header header;
struct wl1271_cmd_test_header test;
struct wl1271_ini_general_params general_params;
u8 sr_debug_table[WL1271_INI_MAX_SMART_REFLEX_PARAM];
u8 sr_sen_n_p;
u8 sr_sen_n_p_gain;
u8 sr_sen_nrn;
u8 sr_sen_prn;
u8 padding[3];
} __packed;
struct wl128x_general_parms_cmd {
struct wl1271_cmd_header header;
struct wl1271_cmd_test_header test;
struct wl128x_ini_general_params general_params;
u8 sr_debug_table[WL1271_INI_MAX_SMART_REFLEX_PARAM];
u8 sr_sen_n_p;
u8 sr_sen_n_p_gain;
u8 sr_sen_nrn;
u8 sr_sen_prn;
u8 padding[3];
} __packed;
struct wl1271_radio_parms_cmd {
struct wl1271_cmd_header header;
struct wl1271_cmd_test_header test;
/* Static radio parameters */
struct wl1271_ini_band_params_2 static_params_2;
struct wl1271_ini_band_params_5 static_params_5;
/* Dynamic radio parameters */
struct wl1271_ini_fem_params_2 dyn_params_2;
u8 padding2;
struct wl1271_ini_fem_params_5 dyn_params_5;
u8 padding3[2];
} __packed;
struct wl128x_radio_parms_cmd {
struct wl1271_cmd_header header;
struct wl1271_cmd_test_header test;
/* Static radio parameters */
struct wl128x_ini_band_params_2 static_params_2;
struct wl128x_ini_band_params_5 static_params_5;
u8 fem_vendor_and_options;
/* Dynamic radio parameters */
struct wl128x_ini_fem_params_2 dyn_params_2;
u8 padding2;
struct wl128x_ini_fem_params_5 dyn_params_5;
} __packed;
struct wl1271_ext_radio_parms_cmd {
struct wl1271_cmd_header header;
struct wl1271_cmd_test_header test;
u8 tx_per_channel_power_compensation_2[CONF_TX_PWR_COMPENSATION_LEN_2];
u8 tx_per_channel_power_compensation_5[CONF_TX_PWR_COMPENSATION_LEN_5];
u8 padding[3];
} __packed;
/* /*
* There are three types of disconnections: * There are three types of disconnections:
* *
......
...@@ -65,36 +65,7 @@ enum { ...@@ -65,36 +65,7 @@ enum {
CONF_HW_RATE_INDEX_MAX = CONF_HW_RATE_INDEX_54MBPS, CONF_HW_RATE_INDEX_MAX = CONF_HW_RATE_INDEX_54MBPS,
}; };
enum { #define CONF_HW_RXTX_RATE_UNSUPPORTED 0xff
CONF_HW_RXTX_RATE_MCS7_SGI = 0,
CONF_HW_RXTX_RATE_MCS7,
CONF_HW_RXTX_RATE_MCS6,
CONF_HW_RXTX_RATE_MCS5,
CONF_HW_RXTX_RATE_MCS4,
CONF_HW_RXTX_RATE_MCS3,
CONF_HW_RXTX_RATE_MCS2,
CONF_HW_RXTX_RATE_MCS1,
CONF_HW_RXTX_RATE_MCS0,
CONF_HW_RXTX_RATE_54,
CONF_HW_RXTX_RATE_48,
CONF_HW_RXTX_RATE_36,
CONF_HW_RXTX_RATE_24,
CONF_HW_RXTX_RATE_22,
CONF_HW_RXTX_RATE_18,
CONF_HW_RXTX_RATE_12,
CONF_HW_RXTX_RATE_11,
CONF_HW_RXTX_RATE_9,
CONF_HW_RXTX_RATE_6,
CONF_HW_RXTX_RATE_5_5,
CONF_HW_RXTX_RATE_2,
CONF_HW_RXTX_RATE_1,
CONF_HW_RXTX_RATE_MAX,
CONF_HW_RXTX_RATE_UNSUPPORTED = 0xff
};
/* Rates between and including these are MCS rates */
#define CONF_HW_RXTX_RATE_MCS_MIN CONF_HW_RXTX_RATE_MCS7_SGI
#define CONF_HW_RXTX_RATE_MCS_MAX CONF_HW_RXTX_RATE_MCS0
enum { enum {
CONF_SG_DISABLE = 0, CONF_SG_DISABLE = 0,
...@@ -1096,16 +1067,31 @@ struct conf_scan_settings { ...@@ -1096,16 +1067,31 @@ struct conf_scan_settings {
}; };
struct conf_sched_scan_settings { struct conf_sched_scan_settings {
/* minimum time to wait on the channel for active scans (in TUs) */ /*
u16 min_dwell_time_active; * The base time to wait on the channel for active scans (in TU/1000).
* The minimum dwell time is calculated according to this:
* min_dwell_time = base + num_of_probes_to_be_sent * delta_per_probe
* The maximum dwell time is calculated according to this:
* max_dwell_time = min_dwell_time + max_dwell_time_delta
*/
u32 base_dwell_time;
/* maximum time to wait on the channel for active scans (in TUs) */ /* The delta between the min dwell time and max dwell time for
u16 max_dwell_time_active; * active scans (in TU/1000s). The max dwell time is used by the FW once
* traffic is detected on the channel.
*/
u32 max_dwell_time_delta;
/* Delta added to min dwell time per each probe in 2.4 GHz (TU/1000) */
u32 dwell_time_delta_per_probe;
/* time to wait on the channel for passive scans (in TUs) */ /* Delta added to min dwell time per each probe in 5 GHz (TU/1000) */
u32 dwell_time_delta_per_probe_5;
/* time to wait on the channel for passive scans (in TU/1000) */
u32 dwell_time_passive; u32 dwell_time_passive;
/* time to wait on the channel for DFS scans (in TUs) */ /* time to wait on the channel for DFS scans (in TU/1000) */
u32 dwell_time_dfs; u32 dwell_time_dfs;
/* number of probe requests to send on each channel in active scans */ /* number of probe requests to send on each channel in active scans */
...@@ -1118,26 +1104,6 @@ struct conf_sched_scan_settings { ...@@ -1118,26 +1104,6 @@ struct conf_sched_scan_settings {
s8 snr_threshold; s8 snr_threshold;
}; };
/* these are number of channels on the band divided by two, rounded up */
#define CONF_TX_PWR_COMPENSATION_LEN_2 7
#define CONF_TX_PWR_COMPENSATION_LEN_5 18
struct conf_rf_settings {
/*
* Per channel power compensation for 2.4GHz
*
* Range: s8
*/
u8 tx_per_channel_power_compensation_2[CONF_TX_PWR_COMPENSATION_LEN_2];
/*
* Per channel power compensation for 5GHz
*
* Range: s8
*/
u8 tx_per_channel_power_compensation_5[CONF_TX_PWR_COMPENSATION_LEN_5];
};
struct conf_ht_setting { struct conf_ht_setting {
u8 rx_ba_win_size; u8 rx_ba_win_size;
u8 tx_ba_win_size; u8 tx_ba_win_size;
...@@ -1286,7 +1252,7 @@ struct conf_hangover_settings { ...@@ -1286,7 +1252,7 @@ struct conf_hangover_settings {
u8 window_size; u8 window_size;
}; };
struct conf_drv_settings { struct wlcore_conf {
struct conf_sg_settings sg; struct conf_sg_settings sg;
struct conf_rx_settings rx; struct conf_rx_settings rx;
struct conf_tx_settings tx; struct conf_tx_settings tx;
...@@ -1296,16 +1262,13 @@ struct conf_drv_settings { ...@@ -1296,16 +1262,13 @@ struct conf_drv_settings {
struct conf_roam_trigger_settings roam_trigger; struct conf_roam_trigger_settings roam_trigger;
struct conf_scan_settings scan; struct conf_scan_settings scan;
struct conf_sched_scan_settings sched_scan; struct conf_sched_scan_settings sched_scan;
struct conf_rf_settings rf;
struct conf_ht_setting ht; struct conf_ht_setting ht;
struct conf_memory_settings mem_wl127x; struct conf_memory_settings mem;
struct conf_memory_settings mem_wl128x;
struct conf_fm_coex fm_coex; struct conf_fm_coex fm_coex;
struct conf_rx_streaming_settings rx_streaming; struct conf_rx_streaming_settings rx_streaming;
struct conf_fwlog fwlog; struct conf_fwlog fwlog;
struct conf_rate_policy_settings rate; struct conf_rate_policy_settings rate;
struct conf_hangover_settings hangover; struct conf_hangover_settings hangover;
u8 hci_io_ds;
}; };
#endif #endif
...@@ -52,6 +52,7 @@ enum { ...@@ -52,6 +52,7 @@ enum {
DEBUG_ADHOC = BIT(16), DEBUG_ADHOC = BIT(16),
DEBUG_AP = BIT(17), DEBUG_AP = BIT(17),
DEBUG_PROBE = BIT(18), DEBUG_PROBE = BIT(18),
DEBUG_IO = BIT(19),
DEBUG_MASTER = (DEBUG_ADHOC | DEBUG_AP), DEBUG_MASTER = (DEBUG_ADHOC | DEBUG_AP),
DEBUG_ALL = ~0, DEBUG_ALL = ~0,
}; };
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/slab.h> #include <linux/slab.h>
#include "wl12xx.h" #include "wlcore.h"
#include "debug.h" #include "debug.h"
#include "acx.h" #include "acx.h"
#include "ps.h" #include "ps.h"
...@@ -653,6 +653,7 @@ static ssize_t vifs_state_read(struct file *file, char __user *user_buf, ...@@ -653,6 +653,7 @@ static ssize_t vifs_state_read(struct file *file, char __user *user_buf,
VIF_STATE_PRINT_INT(last_rssi_event); VIF_STATE_PRINT_INT(last_rssi_event);
VIF_STATE_PRINT_INT(ba_support); VIF_STATE_PRINT_INT(ba_support);
VIF_STATE_PRINT_INT(ba_allowed); VIF_STATE_PRINT_INT(ba_allowed);
VIF_STATE_PRINT_INT(is_gem);
VIF_STATE_PRINT_LLHEX(tx_security_seq); VIF_STATE_PRINT_LLHEX(tx_security_seq);
VIF_STATE_PRINT_INT(tx_security_last_seq_lsb); VIF_STATE_PRINT_INT(tx_security_last_seq_lsb);
} }
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
#ifndef __DEBUGFS_H__ #ifndef __DEBUGFS_H__
#define __DEBUGFS_H__ #define __DEBUGFS_H__
#include "wl12xx.h" #include "wlcore.h"
int wl1271_debugfs_init(struct wl1271 *wl); int wl1271_debugfs_init(struct wl1271 *wl);
void wl1271_debugfs_exit(struct wl1271 *wl); void wl1271_debugfs_exit(struct wl1271 *wl);
......
...@@ -21,9 +21,8 @@ ...@@ -21,9 +21,8 @@
* *
*/ */
#include "wl12xx.h" #include "wlcore.h"
#include "debug.h" #include "debug.h"
#include "reg.h"
#include "io.h" #include "io.h"
#include "event.h" #include "event.h"
#include "ps.h" #include "ps.h"
...@@ -98,8 +97,9 @@ static void wl1271_event_mbox_dump(struct event_mailbox *mbox) ...@@ -98,8 +97,9 @@ static void wl1271_event_mbox_dump(struct event_mailbox *mbox)
wl1271_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask); wl1271_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask);
} }
static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) static int wl1271_event_process(struct wl1271 *wl)
{ {
struct event_mailbox *mbox = wl->mbox;
struct ieee80211_vif *vif; struct ieee80211_vif *vif;
struct wl12xx_vif *wlvif; struct wl12xx_vif *wlvif;
u32 vector; u32 vector;
...@@ -196,7 +196,7 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) ...@@ -196,7 +196,7 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
bool success; bool success;
if (!test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, if (!test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS,
&wl->flags)) &wlvif->flags))
continue; continue;
success = mbox->channel_switch_status ? false : true; success = mbox->channel_switch_status ? false : true;
...@@ -278,18 +278,8 @@ int wl1271_event_unmask(struct wl1271 *wl) ...@@ -278,18 +278,8 @@ int wl1271_event_unmask(struct wl1271 *wl)
return 0; return 0;
} }
void wl1271_event_mbox_config(struct wl1271 *wl)
{
wl->mbox_ptr[0] = wl1271_read32(wl, REG_EVENT_MAILBOX_PTR);
wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox);
wl1271_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x",
wl->mbox_ptr[0], wl->mbox_ptr[1]);
}
int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num) int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num)
{ {
struct event_mailbox mbox;
int ret; int ret;
wl1271_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num); wl1271_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num);
...@@ -298,16 +288,19 @@ int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num) ...@@ -298,16 +288,19 @@ int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num)
return -EINVAL; return -EINVAL;
/* first we read the mbox descriptor */ /* first we read the mbox descriptor */
wl1271_read(wl, wl->mbox_ptr[mbox_num], &mbox, wl1271_read(wl, wl->mbox_ptr[mbox_num], wl->mbox,
sizeof(struct event_mailbox), false); sizeof(*wl->mbox), false);
/* process the descriptor */ /* process the descriptor */
ret = wl1271_event_process(wl, &mbox); ret = wl1271_event_process(wl);
if (ret < 0) if (ret < 0)
return ret; return ret;
/* then we let the firmware know it can go on...*/ /*
wl1271_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK); * TODO: we just need this because one bit is in a different
* place. Is there any better way?
*/
wl->ops->ack_event(wl);
return 0; return 0;
} }
...@@ -132,8 +132,9 @@ struct event_mailbox { ...@@ -132,8 +132,9 @@ struct event_mailbox {
u8 reserved_8[9]; u8 reserved_8[9];
} __packed; } __packed;
struct wl1271;
int wl1271_event_unmask(struct wl1271 *wl); int wl1271_event_unmask(struct wl1271 *wl);
void wl1271_event_mbox_config(struct wl1271 *wl);
int wl1271_event_handle(struct wl1271 *wl, u8 mbox); int wl1271_event_handle(struct wl1271 *wl, u8 mbox);
#endif #endif
/*
* This file is part of wlcore
*
* Copyright (C) 2011 Texas Instruments Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#ifndef __WLCORE_HW_OPS_H__
#define __WLCORE_HW_OPS_H__
#include "wlcore.h"
#include "rx.h"
static inline u32
wlcore_hw_calc_tx_blocks(struct wl1271 *wl, u32 len, u32 spare_blks)
{
if (!wl->ops->calc_tx_blocks)
BUG_ON(1);
return wl->ops->calc_tx_blocks(wl, len, spare_blks);
}
static inline void
wlcore_hw_set_tx_desc_blocks(struct wl1271 *wl, struct wl1271_tx_hw_descr *desc,
u32 blks, u32 spare_blks)
{
if (!wl->ops->set_tx_desc_blocks)
BUG_ON(1);
return wl->ops->set_tx_desc_blocks(wl, desc, blks, spare_blks);
}
static inline void
wlcore_hw_set_tx_desc_data_len(struct wl1271 *wl,
struct wl1271_tx_hw_descr *desc,
struct sk_buff *skb)
{
if (!wl->ops->set_tx_desc_data_len)
BUG_ON(1);
wl->ops->set_tx_desc_data_len(wl, desc, skb);
}
static inline enum wl_rx_buf_align
wlcore_hw_get_rx_buf_align(struct wl1271 *wl, u32 rx_desc)
{
if (!wl->ops->get_rx_buf_align)
BUG_ON(1);
return wl->ops->get_rx_buf_align(wl, rx_desc);
}
static inline void
wlcore_hw_prepare_read(struct wl1271 *wl, u32 rx_desc, u32 len)
{
if (wl->ops->prepare_read)
wl->ops->prepare_read(wl, rx_desc, len);
}
static inline u32
wlcore_hw_get_rx_packet_len(struct wl1271 *wl, void *rx_data, u32 data_len)
{
if (!wl->ops->get_rx_packet_len)
BUG_ON(1);
return wl->ops->get_rx_packet_len(wl, rx_data, data_len);
}
static inline void wlcore_hw_tx_delayed_compl(struct wl1271 *wl)
{
if (wl->ops->tx_delayed_compl)
wl->ops->tx_delayed_compl(wl);
}
static inline void wlcore_hw_tx_immediate_compl(struct wl1271 *wl)
{
if (wl->ops->tx_immediate_compl)
wl->ops->tx_immediate_compl(wl);
}
static inline int
wlcore_hw_init_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif)
{
if (wl->ops->init_vif)
return wl->ops->init_vif(wl, wlvif);
return 0;
}
static inline u32
wlcore_hw_sta_get_ap_rate_mask(struct wl1271 *wl, struct wl12xx_vif *wlvif)
{
if (!wl->ops->sta_get_ap_rate_mask)
BUG_ON(1);
return wl->ops->sta_get_ap_rate_mask(wl, wlvif);
}
static inline int wlcore_identify_fw(struct wl1271 *wl)
{
if (wl->ops->identify_fw)
return wl->ops->identify_fw(wl);
return 0;
}
#endif
...@@ -30,9 +30,9 @@ ...@@ -30,9 +30,9 @@
#include "wl12xx_80211.h" #include "wl12xx_80211.h"
#include "acx.h" #include "acx.h"
#include "cmd.h" #include "cmd.h"
#include "reg.h"
#include "tx.h" #include "tx.h"
#include "io.h" #include "io.h"
#include "hw_ops.h"
int wl1271_init_templates_config(struct wl1271 *wl) int wl1271_init_templates_config(struct wl1271 *wl)
{ {
...@@ -319,7 +319,7 @@ static int wl12xx_init_fwlog(struct wl1271 *wl) ...@@ -319,7 +319,7 @@ static int wl12xx_init_fwlog(struct wl1271 *wl)
{ {
int ret; int ret;
if (wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) if (wl->quirks & WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED)
return 0; return 0;
ret = wl12xx_cmd_config_fwlog(wl); ret = wl12xx_cmd_config_fwlog(wl);
...@@ -494,26 +494,6 @@ static int wl1271_set_ba_policies(struct wl1271 *wl, struct wl12xx_vif *wlvif) ...@@ -494,26 +494,6 @@ static int wl1271_set_ba_policies(struct wl1271 *wl, struct wl12xx_vif *wlvif)
return wl12xx_acx_set_ba_initiator_policy(wl, wlvif); return wl12xx_acx_set_ba_initiator_policy(wl, wlvif);
} }
int wl1271_chip_specific_init(struct wl1271 *wl)
{
int ret = 0;
if (wl->chip.id == CHIP_ID_1283_PG20) {
u32 host_cfg_bitmap = HOST_IF_CFG_RX_FIFO_ENABLE;
if (!(wl->quirks & WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT))
/* Enable SDIO padding */
host_cfg_bitmap |= HOST_IF_CFG_TX_PAD_TO_SDIO_BLK;
/* Must be before wl1271_acx_init_mem_config() */
ret = wl1271_acx_host_if_cfg_bitmap(wl, host_cfg_bitmap);
if (ret < 0)
goto out;
}
out:
return ret;
}
/* vif-specifc initialization */ /* vif-specifc initialization */
static int wl12xx_init_sta_role(struct wl1271 *wl, struct wl12xx_vif *wlvif) static int wl12xx_init_sta_role(struct wl1271 *wl, struct wl12xx_vif *wlvif)
{ {
...@@ -582,12 +562,19 @@ int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif) ...@@ -582,12 +562,19 @@ int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif)
if (ret < 0) if (ret < 0)
return ret; return ret;
} else if (!wl->sta_count) { } else if (!wl->sta_count) {
if (wl->quirks & WLCORE_QUIRK_NO_ELP) {
/* Configure for power always on */
ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
if (ret < 0)
return ret;
} else {
/* Configure for ELP power saving */ /* Configure for ELP power saving */
ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP); ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
if (ret < 0) if (ret < 0)
return ret; return ret;
} }
} }
}
/* Mode specific init */ /* Mode specific init */
if (is_ap) { if (is_ap) {
...@@ -652,6 +639,10 @@ int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif) ...@@ -652,6 +639,10 @@ int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif)
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = wlcore_hw_init_vif(wl, wlvif);
if (ret < 0)
return ret;
return 0; return 0;
} }
...@@ -659,27 +650,8 @@ int wl1271_hw_init(struct wl1271 *wl) ...@@ -659,27 +650,8 @@ int wl1271_hw_init(struct wl1271 *wl)
{ {
int ret; int ret;
if (wl->chip.id == CHIP_ID_1283_PG20) { /* Chip-specific hw init */
ret = wl128x_cmd_general_parms(wl); ret = wl->ops->hw_init(wl);
if (ret < 0)
return ret;
ret = wl128x_cmd_radio_parms(wl);
if (ret < 0)
return ret;
} else {
ret = wl1271_cmd_general_parms(wl);
if (ret < 0)
return ret;
ret = wl1271_cmd_radio_parms(wl);
if (ret < 0)
return ret;
ret = wl1271_cmd_ext_radio_parms(wl);
if (ret < 0)
return ret;
}
/* Chip-specific init */
ret = wl1271_chip_specific_init(wl);
if (ret < 0) if (ret < 0)
return ret; return ret;
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
#ifndef __INIT_H__ #ifndef __INIT_H__
#define __INIT_H__ #define __INIT_H__
#include "wl12xx.h" #include "wlcore.h"
int wl1271_hw_init_power_auth(struct wl1271 *wl); int wl1271_hw_init_power_auth(struct wl1271 *wl);
int wl1271_init_templates_config(struct wl1271 *wl); int wl1271_init_templates_config(struct wl1271 *wl);
......
...@@ -26,84 +26,12 @@ ...@@ -26,84 +26,12 @@
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include "wl12xx.h" #include "wlcore.h"
#include "debug.h" #include "debug.h"
#include "wl12xx_80211.h" #include "wl12xx_80211.h"
#include "io.h" #include "io.h"
#include "tx.h" #include "tx.h"
#define OCP_CMD_LOOP 32
#define OCP_CMD_WRITE 0x1
#define OCP_CMD_READ 0x2
#define OCP_READY_MASK BIT(18)
#define OCP_STATUS_MASK (BIT(16) | BIT(17))
#define OCP_STATUS_NO_RESP 0x00000
#define OCP_STATUS_OK 0x10000
#define OCP_STATUS_REQ_FAILED 0x20000
#define OCP_STATUS_RESP_ERROR 0x30000
struct wl1271_partition_set wl12xx_part_table[PART_TABLE_LEN] = {
[PART_DOWN] = {
.mem = {
.start = 0x00000000,
.size = 0x000177c0
},
.reg = {
.start = REGISTERS_BASE,
.size = 0x00008800
},
.mem2 = {
.start = 0x00000000,
.size = 0x00000000
},
.mem3 = {
.start = 0x00000000,
.size = 0x00000000
},
},
[PART_WORK] = {
.mem = {
.start = 0x00040000,
.size = 0x00014fc0
},
.reg = {
.start = REGISTERS_BASE,
.size = 0x0000a000
},
.mem2 = {
.start = 0x003004f8,
.size = 0x00000004
},
.mem3 = {
.start = 0x00040404,
.size = 0x00000000
},
},
[PART_DRPW] = {
.mem = {
.start = 0x00040000,
.size = 0x00014fc0
},
.reg = {
.start = DRPW_BASE,
.size = 0x00006000
},
.mem2 = {
.start = 0x00000000,
.size = 0x00000000
},
.mem3 = {
.start = 0x00000000,
.size = 0x00000000
}
}
};
bool wl1271_set_block_size(struct wl1271 *wl) bool wl1271_set_block_size(struct wl1271 *wl)
{ {
if (wl->if_ops->set_block_size) { if (wl->if_ops->set_block_size) {
...@@ -114,17 +42,53 @@ bool wl1271_set_block_size(struct wl1271 *wl) ...@@ -114,17 +42,53 @@ bool wl1271_set_block_size(struct wl1271 *wl)
return false; return false;
} }
void wl1271_disable_interrupts(struct wl1271 *wl) void wlcore_disable_interrupts(struct wl1271 *wl)
{ {
disable_irq(wl->irq); disable_irq(wl->irq);
} }
EXPORT_SYMBOL_GPL(wlcore_disable_interrupts);
void wl1271_enable_interrupts(struct wl1271 *wl) void wlcore_enable_interrupts(struct wl1271 *wl)
{ {
enable_irq(wl->irq); enable_irq(wl->irq);
} }
EXPORT_SYMBOL_GPL(wlcore_enable_interrupts);
int wlcore_translate_addr(struct wl1271 *wl, int addr)
{
struct wlcore_partition_set *part = &wl->curr_part;
/*
* To translate, first check to which window of addresses the
* particular address belongs. Then subtract the starting address
* of that window from the address. Then, add offset of the
* translated region.
*
* The translated regions occur next to each other in physical device
* memory, so just add the sizes of the preceding address regions to
* get the offset to the new region.
*/
if ((addr >= part->mem.start) &&
(addr < part->mem.start + part->mem.size))
return addr - part->mem.start;
else if ((addr >= part->reg.start) &&
(addr < part->reg.start + part->reg.size))
return addr - part->reg.start + part->mem.size;
else if ((addr >= part->mem2.start) &&
(addr < part->mem2.start + part->mem2.size))
return addr - part->mem2.start + part->mem.size +
part->reg.size;
else if ((addr >= part->mem3.start) &&
(addr < part->mem3.start + part->mem3.size))
return addr - part->mem3.start + part->mem.size +
part->reg.size + part->mem2.size;
WARN(1, "HW address 0x%x out of range", addr);
return 0;
}
EXPORT_SYMBOL_GPL(wlcore_translate_addr);
/* Set the SPI partitions to access the chip addresses /* Set the partitions to access the chip addresses
* *
* To simplify driver code, a fixed (virtual) memory map is defined for * To simplify driver code, a fixed (virtual) memory map is defined for
* register and memory addresses. Because in the chipset, in different stages * register and memory addresses. Because in the chipset, in different stages
...@@ -158,33 +122,43 @@ void wl1271_enable_interrupts(struct wl1271 *wl) ...@@ -158,33 +122,43 @@ void wl1271_enable_interrupts(struct wl1271 *wl)
* | | * | |
* *
*/ */
int wl1271_set_partition(struct wl1271 *wl, void wlcore_set_partition(struct wl1271 *wl,
struct wl1271_partition_set *p) const struct wlcore_partition_set *p)
{ {
/* copy partition info */ /* copy partition info */
memcpy(&wl->part, p, sizeof(*p)); memcpy(&wl->curr_part, p, sizeof(*p));
wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", wl1271_debug(DEBUG_IO, "mem_start %08X mem_size %08X",
p->mem.start, p->mem.size); p->mem.start, p->mem.size);
wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", wl1271_debug(DEBUG_IO, "reg_start %08X reg_size %08X",
p->reg.start, p->reg.size); p->reg.start, p->reg.size);
wl1271_debug(DEBUG_SPI, "mem2_start %08X mem2_size %08X", wl1271_debug(DEBUG_IO, "mem2_start %08X mem2_size %08X",
p->mem2.start, p->mem2.size); p->mem2.start, p->mem2.size);
wl1271_debug(DEBUG_SPI, "mem3_start %08X mem3_size %08X", wl1271_debug(DEBUG_IO, "mem3_start %08X mem3_size %08X",
p->mem3.start, p->mem3.size); p->mem3.start, p->mem3.size);
/* write partition info to the chipset */
wl1271_raw_write32(wl, HW_PART0_START_ADDR, p->mem.start); wl1271_raw_write32(wl, HW_PART0_START_ADDR, p->mem.start);
wl1271_raw_write32(wl, HW_PART0_SIZE_ADDR, p->mem.size); wl1271_raw_write32(wl, HW_PART0_SIZE_ADDR, p->mem.size);
wl1271_raw_write32(wl, HW_PART1_START_ADDR, p->reg.start); wl1271_raw_write32(wl, HW_PART1_START_ADDR, p->reg.start);
wl1271_raw_write32(wl, HW_PART1_SIZE_ADDR, p->reg.size); wl1271_raw_write32(wl, HW_PART1_SIZE_ADDR, p->reg.size);
wl1271_raw_write32(wl, HW_PART2_START_ADDR, p->mem2.start); wl1271_raw_write32(wl, HW_PART2_START_ADDR, p->mem2.start);
wl1271_raw_write32(wl, HW_PART2_SIZE_ADDR, p->mem2.size); wl1271_raw_write32(wl, HW_PART2_SIZE_ADDR, p->mem2.size);
/*
* We don't need the size of the last partition, as it is
* automatically calculated based on the total memory size and
* the sizes of the previous partitions.
*/
wl1271_raw_write32(wl, HW_PART3_START_ADDR, p->mem3.start); wl1271_raw_write32(wl, HW_PART3_START_ADDR, p->mem3.start);
}
EXPORT_SYMBOL_GPL(wlcore_set_partition);
return 0; void wlcore_select_partition(struct wl1271 *wl, u8 part)
{
wl1271_debug(DEBUG_IO, "setting partition %d", part);
wlcore_set_partition(wl, &wl->ptable[part]);
} }
EXPORT_SYMBOL_GPL(wl1271_set_partition); EXPORT_SYMBOL_GPL(wlcore_select_partition);
void wl1271_io_reset(struct wl1271 *wl) void wl1271_io_reset(struct wl1271 *wl)
{ {
...@@ -197,48 +171,3 @@ void wl1271_io_init(struct wl1271 *wl) ...@@ -197,48 +171,3 @@ void wl1271_io_init(struct wl1271 *wl)
if (wl->if_ops->init) if (wl->if_ops->init)
wl->if_ops->init(wl->dev); wl->if_ops->init(wl->dev);
} }
void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val)
{
/* write address >> 1 + 0x30000 to OCP_POR_CTR */
addr = (addr >> 1) + 0x30000;
wl1271_write32(wl, OCP_POR_CTR, addr);
/* write value to OCP_POR_WDATA */
wl1271_write32(wl, OCP_DATA_WRITE, val);
/* write 1 to OCP_CMD */
wl1271_write32(wl, OCP_CMD, OCP_CMD_WRITE);
}
u16 wl1271_top_reg_read(struct wl1271 *wl, int addr)
{
u32 val;
int timeout = OCP_CMD_LOOP;
/* write address >> 1 + 0x30000 to OCP_POR_CTR */
addr = (addr >> 1) + 0x30000;
wl1271_write32(wl, OCP_POR_CTR, addr);
/* write 2 to OCP_CMD */
wl1271_write32(wl, OCP_CMD, OCP_CMD_READ);
/* poll for data ready */
do {
val = wl1271_read32(wl, OCP_DATA_READ);
} while (!(val & OCP_READY_MASK) && --timeout);
if (!timeout) {
wl1271_warning("Top register access timed out.");
return 0xffff;
}
/* check data status and return if OK */
if ((val & OCP_STATUS_MASK) == OCP_STATUS_OK)
return val & 0xffff;
else {
wl1271_warning("Top register access returned error.");
return 0xffff;
}
}
...@@ -26,7 +26,6 @@ ...@@ -26,7 +26,6 @@
#define __IO_H__ #define __IO_H__
#include <linux/irqreturn.h> #include <linux/irqreturn.h>
#include "reg.h"
#define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0 #define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0
...@@ -43,15 +42,14 @@ ...@@ -43,15 +42,14 @@
#define HW_ACCESS_PRAM_MAX_RANGE 0x3c000 #define HW_ACCESS_PRAM_MAX_RANGE 0x3c000
extern struct wl1271_partition_set wl12xx_part_table[PART_TABLE_LEN];
struct wl1271; struct wl1271;
void wl1271_disable_interrupts(struct wl1271 *wl); void wlcore_disable_interrupts(struct wl1271 *wl);
void wl1271_enable_interrupts(struct wl1271 *wl); void wlcore_enable_interrupts(struct wl1271 *wl);
void wl1271_io_reset(struct wl1271 *wl); void wl1271_io_reset(struct wl1271 *wl);
void wl1271_io_init(struct wl1271 *wl); void wl1271_io_init(struct wl1271 *wl);
int wlcore_translate_addr(struct wl1271 *wl, int addr);
/* Raw target IO, address is not translated */ /* Raw target IO, address is not translated */
static inline void wl1271_raw_write(struct wl1271 *wl, int addr, void *buf, static inline void wl1271_raw_write(struct wl1271 *wl, int addr, void *buf,
...@@ -66,6 +64,18 @@ static inline void wl1271_raw_read(struct wl1271 *wl, int addr, void *buf, ...@@ -66,6 +64,18 @@ static inline void wl1271_raw_read(struct wl1271 *wl, int addr, void *buf,
wl->if_ops->read(wl->dev, addr, buf, len, fixed); wl->if_ops->read(wl->dev, addr, buf, len, fixed);
} }
static inline void wlcore_raw_read_data(struct wl1271 *wl, int reg, void *buf,
size_t len, bool fixed)
{
wl1271_raw_read(wl, wl->rtable[reg], buf, len, fixed);
}
static inline void wlcore_raw_write_data(struct wl1271 *wl, int reg, void *buf,
size_t len, bool fixed)
{
wl1271_raw_write(wl, wl->rtable[reg], buf, len, fixed);
}
static inline u32 wl1271_raw_read32(struct wl1271 *wl, int addr) static inline u32 wl1271_raw_read32(struct wl1271 *wl, int addr)
{ {
wl1271_raw_read(wl, addr, &wl->buffer_32, wl1271_raw_read(wl, addr, &wl->buffer_32,
...@@ -81,36 +91,12 @@ static inline void wl1271_raw_write32(struct wl1271 *wl, int addr, u32 val) ...@@ -81,36 +91,12 @@ static inline void wl1271_raw_write32(struct wl1271 *wl, int addr, u32 val)
sizeof(wl->buffer_32), false); sizeof(wl->buffer_32), false);
} }
/* Translated target IO */
static inline int wl1271_translate_addr(struct wl1271 *wl, int addr)
{
/*
* To translate, first check to which window of addresses the
* particular address belongs. Then subtract the starting address
* of that window from the address. Then, add offset of the
* translated region.
*
* The translated regions occur next to each other in physical device
* memory, so just add the sizes of the preceding address regions to
* get the offset to the new region.
*
* Currently, only the two first regions are addressed, and the
* assumption is that all addresses will fall into either of those
* two.
*/
if ((addr >= wl->part.reg.start) &&
(addr < wl->part.reg.start + wl->part.reg.size))
return addr - wl->part.reg.start + wl->part.mem.size;
else
return addr - wl->part.mem.start;
}
static inline void wl1271_read(struct wl1271 *wl, int addr, void *buf, static inline void wl1271_read(struct wl1271 *wl, int addr, void *buf,
size_t len, bool fixed) size_t len, bool fixed)
{ {
int physical; int physical;
physical = wl1271_translate_addr(wl, addr); physical = wlcore_translate_addr(wl, addr);
wl1271_raw_read(wl, physical, buf, len, fixed); wl1271_raw_read(wl, physical, buf, len, fixed);
} }
...@@ -120,11 +106,23 @@ static inline void wl1271_write(struct wl1271 *wl, int addr, void *buf, ...@@ -120,11 +106,23 @@ static inline void wl1271_write(struct wl1271 *wl, int addr, void *buf,
{ {
int physical; int physical;
physical = wl1271_translate_addr(wl, addr); physical = wlcore_translate_addr(wl, addr);
wl1271_raw_write(wl, physical, buf, len, fixed); wl1271_raw_write(wl, physical, buf, len, fixed);
} }
static inline void wlcore_write_data(struct wl1271 *wl, int reg, void *buf,
size_t len, bool fixed)
{
wl1271_write(wl, wl->rtable[reg], buf, len, fixed);
}
static inline void wlcore_read_data(struct wl1271 *wl, int reg, void *buf,
size_t len, bool fixed)
{
wl1271_read(wl, wl->rtable[reg], buf, len, fixed);
}
static inline void wl1271_read_hwaddr(struct wl1271 *wl, int hwaddr, static inline void wl1271_read_hwaddr(struct wl1271 *wl, int hwaddr,
void *buf, size_t len, bool fixed) void *buf, size_t len, bool fixed)
{ {
...@@ -134,19 +132,30 @@ static inline void wl1271_read_hwaddr(struct wl1271 *wl, int hwaddr, ...@@ -134,19 +132,30 @@ static inline void wl1271_read_hwaddr(struct wl1271 *wl, int hwaddr,
/* Addresses are stored internally as addresses to 32 bytes blocks */ /* Addresses are stored internally as addresses to 32 bytes blocks */
addr = hwaddr << 5; addr = hwaddr << 5;
physical = wl1271_translate_addr(wl, addr); physical = wlcore_translate_addr(wl, addr);
wl1271_raw_read(wl, physical, buf, len, fixed); wl1271_raw_read(wl, physical, buf, len, fixed);
} }
static inline u32 wl1271_read32(struct wl1271 *wl, int addr) static inline u32 wl1271_read32(struct wl1271 *wl, int addr)
{ {
return wl1271_raw_read32(wl, wl1271_translate_addr(wl, addr)); return wl1271_raw_read32(wl, wlcore_translate_addr(wl, addr));
} }
static inline void wl1271_write32(struct wl1271 *wl, int addr, u32 val) static inline void wl1271_write32(struct wl1271 *wl, int addr, u32 val)
{ {
wl1271_raw_write32(wl, wl1271_translate_addr(wl, addr), val); wl1271_raw_write32(wl, wlcore_translate_addr(wl, addr), val);
}
static inline u32 wlcore_read_reg(struct wl1271 *wl, int reg)
{
return wl1271_raw_read32(wl,
wlcore_translate_addr(wl, wl->rtable[reg]));
}
static inline void wlcore_write_reg(struct wl1271 *wl, int reg, u32 val)
{
wl1271_raw_write32(wl, wlcore_translate_addr(wl, wl->rtable[reg]), val);
} }
static inline void wl1271_power_off(struct wl1271 *wl) static inline void wl1271_power_off(struct wl1271 *wl)
...@@ -164,13 +173,8 @@ static inline int wl1271_power_on(struct wl1271 *wl) ...@@ -164,13 +173,8 @@ static inline int wl1271_power_on(struct wl1271 *wl)
return ret; return ret;
} }
void wlcore_set_partition(struct wl1271 *wl,
/* Top Register IO */ const struct wlcore_partition_set *p);
void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val);
u16 wl1271_top_reg_read(struct wl1271 *wl, int addr);
int wl1271_set_partition(struct wl1271 *wl,
struct wl1271_partition_set *p);
bool wl1271_set_block_size(struct wl1271 *wl); bool wl1271_set_block_size(struct wl1271 *wl);
...@@ -178,4 +182,6 @@ bool wl1271_set_block_size(struct wl1271 *wl); ...@@ -178,4 +182,6 @@ bool wl1271_set_block_size(struct wl1271 *wl);
int wl1271_tx_dummy_packet(struct wl1271 *wl); int wl1271_tx_dummy_packet(struct wl1271 *wl);
void wlcore_select_partition(struct wl1271 *wl, u8 part);
#endif #endif
...@@ -35,10 +35,9 @@ ...@@ -35,10 +35,9 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include "wl12xx.h" #include "wlcore.h"
#include "debug.h" #include "debug.h"
#include "wl12xx_80211.h" #include "wl12xx_80211.h"
#include "reg.h"
#include "io.h" #include "io.h"
#include "event.h" #include "event.h"
#include "tx.h" #include "tx.h"
...@@ -50,342 +49,15 @@ ...@@ -50,342 +49,15 @@
#include "boot.h" #include "boot.h"
#include "testmode.h" #include "testmode.h"
#include "scan.h" #include "scan.h"
#include "hw_ops.h"
#define WL1271_BOOT_RETRIES 3 #define WL1271_BOOT_RETRIES 3
static struct conf_drv_settings default_conf = { #define WL1271_BOOT_RETRIES 3
.sg = {
.params = {
[CONF_SG_ACL_BT_MASTER_MIN_BR] = 10,
[CONF_SG_ACL_BT_MASTER_MAX_BR] = 180,
[CONF_SG_ACL_BT_SLAVE_MIN_BR] = 10,
[CONF_SG_ACL_BT_SLAVE_MAX_BR] = 180,
[CONF_SG_ACL_BT_MASTER_MIN_EDR] = 10,
[CONF_SG_ACL_BT_MASTER_MAX_EDR] = 80,
[CONF_SG_ACL_BT_SLAVE_MIN_EDR] = 10,
[CONF_SG_ACL_BT_SLAVE_MAX_EDR] = 80,
[CONF_SG_ACL_WLAN_PS_MASTER_BR] = 8,
[CONF_SG_ACL_WLAN_PS_SLAVE_BR] = 8,
[CONF_SG_ACL_WLAN_PS_MASTER_EDR] = 20,
[CONF_SG_ACL_WLAN_PS_SLAVE_EDR] = 20,
[CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR] = 20,
[CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR] = 35,
[CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR] = 16,
[CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR] = 35,
[CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR] = 32,
[CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR] = 50,
[CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR] = 28,
[CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR] = 50,
[CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR] = 10,
[CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR] = 20,
[CONF_SG_ACL_PASSIVE_SCAN_BT_BR] = 75,
[CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR] = 15,
[CONF_SG_ACL_PASSIVE_SCAN_BT_EDR] = 27,
[CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR] = 17,
/* active scan params */
[CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
[CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
[CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
/* passive scan params */
[CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR] = 800,
[CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR] = 200,
[CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
/* passive scan in dual antenna params */
[CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0,
[CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN] = 0,
[CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN] = 0,
/* general params */
[CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1,
[CONF_SG_ANTENNA_CONFIGURATION] = 0,
[CONF_SG_BEACON_MISS_PERCENT] = 60,
[CONF_SG_DHCP_TIME] = 5000,
[CONF_SG_RXT] = 1200,
[CONF_SG_TXT] = 1000,
[CONF_SG_ADAPTIVE_RXT_TXT] = 1,
[CONF_SG_GENERAL_USAGE_BIT_MAP] = 3,
[CONF_SG_HV3_MAX_SERVED] = 6,
[CONF_SG_PS_POLL_TIMEOUT] = 10,
[CONF_SG_UPSD_TIMEOUT] = 10,
[CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2,
[CONF_SG_STA_RX_WINDOW_AFTER_DTIM] = 5,
[CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 30,
/* AP params */
[CONF_AP_BEACON_MISS_TX] = 3,
[CONF_AP_RX_WINDOW_AFTER_BEACON] = 10,
[CONF_AP_BEACON_WINDOW_INTERVAL] = 2,
[CONF_AP_CONNECTION_PROTECTION_TIME] = 0,
[CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25,
[CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25,
/* CTS Diluting params */
[CONF_SG_CTS_DILUTED_BAD_RX_PACKETS_TH] = 0,
[CONF_SG_CTS_CHOP_IN_DUAL_ANT_SCO_MASTER] = 0,
},
.state = CONF_SG_PROTECTIVE,
},
.rx = {
.rx_msdu_life_time = 512000,
.packet_detection_threshold = 0,
.ps_poll_timeout = 15,
.upsd_timeout = 15,
.rts_threshold = IEEE80211_MAX_RTS_THRESHOLD,
.rx_cca_threshold = 0,
.irq_blk_threshold = 0xFFFF,
.irq_pkt_threshold = 0,
.irq_timeout = 600,
.queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
},
.tx = {
.tx_energy_detection = 0,
.sta_rc_conf = {
.enabled_rates = 0,
.short_retry_limit = 10,
.long_retry_limit = 10,
.aflags = 0,
},
.ac_conf_count = 4,
.ac_conf = {
[CONF_TX_AC_BE] = {
.ac = CONF_TX_AC_BE,
.cw_min = 15,
.cw_max = 63,
.aifsn = 3,
.tx_op_limit = 0,
},
[CONF_TX_AC_BK] = {
.ac = CONF_TX_AC_BK,
.cw_min = 15,
.cw_max = 63,
.aifsn = 7,
.tx_op_limit = 0,
},
[CONF_TX_AC_VI] = {
.ac = CONF_TX_AC_VI,
.cw_min = 15,
.cw_max = 63,
.aifsn = CONF_TX_AIFS_PIFS,
.tx_op_limit = 3008,
},
[CONF_TX_AC_VO] = {
.ac = CONF_TX_AC_VO,
.cw_min = 15,
.cw_max = 63,
.aifsn = CONF_TX_AIFS_PIFS,
.tx_op_limit = 1504,
},
},
.max_tx_retries = 100,
.ap_aging_period = 300,
.tid_conf_count = 4,
.tid_conf = {
[CONF_TX_AC_BE] = {
.queue_id = CONF_TX_AC_BE,
.channel_type = CONF_CHANNEL_TYPE_EDCF,
.tsid = CONF_TX_AC_BE,
.ps_scheme = CONF_PS_SCHEME_LEGACY,
.ack_policy = CONF_ACK_POLICY_LEGACY,
.apsd_conf = {0, 0},
},
[CONF_TX_AC_BK] = {
.queue_id = CONF_TX_AC_BK,
.channel_type = CONF_CHANNEL_TYPE_EDCF,
.tsid = CONF_TX_AC_BK,
.ps_scheme = CONF_PS_SCHEME_LEGACY,
.ack_policy = CONF_ACK_POLICY_LEGACY,
.apsd_conf = {0, 0},
},
[CONF_TX_AC_VI] = {
.queue_id = CONF_TX_AC_VI,
.channel_type = CONF_CHANNEL_TYPE_EDCF,
.tsid = CONF_TX_AC_VI,
.ps_scheme = CONF_PS_SCHEME_LEGACY,
.ack_policy = CONF_ACK_POLICY_LEGACY,
.apsd_conf = {0, 0},
},
[CONF_TX_AC_VO] = {
.queue_id = CONF_TX_AC_VO,
.channel_type = CONF_CHANNEL_TYPE_EDCF,
.tsid = CONF_TX_AC_VO,
.ps_scheme = CONF_PS_SCHEME_LEGACY,
.ack_policy = CONF_ACK_POLICY_LEGACY,
.apsd_conf = {0, 0},
},
},
.frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
.tx_compl_timeout = 700,
.tx_compl_threshold = 4,
.basic_rate = CONF_HW_BIT_RATE_1MBPS,
.basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
.tmpl_short_retry_limit = 10,
.tmpl_long_retry_limit = 10,
.tx_watchdog_timeout = 5000,
},
.conn = {
.wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
.listen_interval = 1,
.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 = {
[0] = {
.ie = WLAN_EID_CHANNEL_SWITCH,
.rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
},
[1] = {
.ie = WLAN_EID_HT_OPERATION,
.rule = CONF_BCN_RULE_PASS_ON_CHANGE,
},
},
.synch_fail_thold = 10,
.bss_lose_timeout = 100,
.beacon_rx_timeout = 10000,
.broadcast_timeout = 20000,
.rx_broadcast_in_ps = 1,
.ps_poll_threshold = 10,
.bet_enable = CONF_BET_MODE_ENABLE,
.bet_max_consecutive = 50,
.psm_entry_retries = 8,
.psm_exit_retries = 16,
.psm_entry_nullfunc_retries = 3,
.dynamic_ps_timeout = 200,
.forced_ps = false,
.keep_alive_interval = 55000,
.max_listen_interval = 20,
},
.itrim = {
.enable = false,
.timeout = 50000,
},
.pm_config = {
.host_clk_settling_time = 5000,
.host_fast_wakeup_support = false
},
.roam_trigger = {
.trigger_pacing = 1,
.avg_weight_rssi_beacon = 20,
.avg_weight_rssi_data = 10,
.avg_weight_snr_beacon = 20,
.avg_weight_snr_data = 10,
},
.scan = {
.min_dwell_time_active = 7500,
.max_dwell_time_active = 30000,
.min_dwell_time_passive = 100000,
.max_dwell_time_passive = 100000,
.num_probe_reqs = 2,
.split_scan_timeout = 50000,
},
.sched_scan = {
/* sched_scan requires dwell times in TU instead of TU/1000 */
.min_dwell_time_active = 30,
.max_dwell_time_active = 60,
.dwell_time_passive = 100,
.dwell_time_dfs = 150,
.num_probe_reqs = 2,
.rssi_threshold = -90,
.snr_threshold = 0,
},
.rf = {
.tx_per_channel_power_compensation_2 = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
},
.tx_per_channel_power_compensation_5 = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
},
},
.ht = {
.rx_ba_win_size = 8,
.tx_ba_win_size = 64,
.inactivity_timeout = 10000,
.tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP,
},
.mem_wl127x = {
.num_stations = 1,
.ssid_profiles = 1,
.rx_block_num = 70,
.tx_min_block_num = 40,
.dynamic_memory = 1,
.min_req_tx_blocks = 100,
.min_req_rx_blocks = 22,
.tx_min = 27,
},
.mem_wl128x = {
.num_stations = 1,
.ssid_profiles = 1,
.rx_block_num = 40,
.tx_min_block_num = 40,
.dynamic_memory = 1,
.min_req_tx_blocks = 45,
.min_req_rx_blocks = 22,
.tx_min = 27,
},
.fm_coex = {
.enable = true,
.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 */
.coex_pll_stabilization_time = 0xffffffff, /* default */
.ldo_stabilization_time = 0xffff, /* default */
.fm_disturbed_band_margin = 0xff, /* default */
.swallow_clk_diff = 0xff, /* default */
},
.rx_streaming = {
.duration = 150,
.queues = 0x1,
.interval = 20,
.always = 0,
},
.fwlog = {
.mode = WL12XX_FWLOG_ON_DEMAND,
.mem_blocks = 2,
.severity = 0,
.timestamp = WL12XX_FWLOG_TIMESTAMP_DISABLED,
.output = WL12XX_FWLOG_OUTPUT_HOST,
.threshold = 0,
},
.hci_io_ds = HCI_IO_DS_6MA,
.rate = {
.rate_retry_score = 32000,
.per_add = 8192,
.per_th1 = 2048,
.per_th2 = 4096,
.max_per = 8100,
.inverse_curiosity_factor = 5,
.tx_fail_low_th = 4,
.tx_fail_high_th = 10,
.per_alpha_shift = 4,
.per_add_shift = 13,
.per_beta1_shift = 10,
.per_beta2_shift = 8,
.rate_check_up = 2,
.rate_check_down = 12,
.rate_retry_policy = {
0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00,
},
},
.hangover = {
.recover_time = 0,
.hangover_period = 20,
.dynamic_mode = 1,
.early_termination_mode = 1,
.max_period = 20,
.min_period = 1,
.increase_delta = 1,
.decrease_delta = 2,
.quiet_time = 4,
.increase_time = 1,
.window_size = 16,
},
};
static char *fwlog_param; static char *fwlog_param;
static bool bug_on_recovery; static bool bug_on_recovery;
static bool no_recovery;
static void __wl1271_op_remove_interface(struct wl1271 *wl, static void __wl1271_op_remove_interface(struct wl1271 *wl,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
...@@ -628,22 +300,8 @@ static void wl12xx_tx_watchdog_work(struct work_struct *work) ...@@ -628,22 +300,8 @@ static void wl12xx_tx_watchdog_work(struct work_struct *work)
mutex_unlock(&wl->mutex); mutex_unlock(&wl->mutex);
} }
static void wl1271_conf_init(struct wl1271 *wl) static void wlcore_adjust_conf(struct wl1271 *wl)
{ {
/*
* This function applies the default configuration to the driver. This
* function is invoked upon driver load (spi probe.)
*
* The configuration is stored in a run-time structure in order to
* facilitate for run-time adjustment of any of the parameters. Making
* changes to the configuration structure will apply the new values on
* the next interface up (wl1271_op_start.)
*/
/* apply driver default configuration */
memcpy(&wl->conf, &default_conf, sizeof(default_conf));
/* Adjust settings according to optional module parameters */ /* Adjust settings according to optional module parameters */
if (fwlog_param) { if (fwlog_param) {
if (!strcmp(fwlog_param, "continuous")) { if (!strcmp(fwlog_param, "continuous")) {
...@@ -666,28 +324,7 @@ static int wl1271_plt_init(struct wl1271 *wl) ...@@ -666,28 +324,7 @@ static int wl1271_plt_init(struct wl1271 *wl)
{ {
int ret; int ret;
if (wl->chip.id == CHIP_ID_1283_PG20) ret = wl->ops->hw_init(wl);
ret = wl128x_cmd_general_parms(wl);
else
ret = wl1271_cmd_general_parms(wl);
if (ret < 0)
return ret;
if (wl->chip.id == CHIP_ID_1283_PG20)
ret = wl128x_cmd_radio_parms(wl);
else
ret = wl1271_cmd_radio_parms(wl);
if (ret < 0)
return ret;
if (wl->chip.id != CHIP_ID_1283_PG20) {
ret = wl1271_cmd_ext_radio_parms(wl);
if (ret < 0)
return ret;
}
/* Chip-specific initializations */
ret = wl1271_chip_specific_init(wl);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -750,7 +387,7 @@ static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl, ...@@ -750,7 +387,7 @@ static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl,
static void wl12xx_irq_update_links_status(struct wl1271 *wl, static void wl12xx_irq_update_links_status(struct wl1271 *wl,
struct wl12xx_vif *wlvif, struct wl12xx_vif *wlvif,
struct wl12xx_fw_status *status) struct wl_fw_status *status)
{ {
struct wl1271_link *lnk; struct wl1271_link *lnk;
u32 cur_fw_ps_map; u32 cur_fw_ps_map;
...@@ -770,9 +407,10 @@ static void wl12xx_irq_update_links_status(struct wl1271 *wl, ...@@ -770,9 +407,10 @@ static void wl12xx_irq_update_links_status(struct wl1271 *wl,
for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, WL12XX_MAX_LINKS) { for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, WL12XX_MAX_LINKS) {
lnk = &wl->links[hlid]; lnk = &wl->links[hlid];
cnt = status->tx_lnk_free_pkts[hlid] - lnk->prev_freed_pkts; cnt = status->counters.tx_lnk_free_pkts[hlid] -
lnk->prev_freed_pkts;
lnk->prev_freed_pkts = status->tx_lnk_free_pkts[hlid]; lnk->prev_freed_pkts = status->counters.tx_lnk_free_pkts[hlid];
lnk->allocated_pkts -= cnt; lnk->allocated_pkts -= cnt;
wl12xx_irq_ps_regulate_link(wl, wlvif, hlid, wl12xx_irq_ps_regulate_link(wl, wlvif, hlid,
...@@ -781,15 +419,19 @@ static void wl12xx_irq_update_links_status(struct wl1271 *wl, ...@@ -781,15 +419,19 @@ static void wl12xx_irq_update_links_status(struct wl1271 *wl,
} }
static void wl12xx_fw_status(struct wl1271 *wl, static void wl12xx_fw_status(struct wl1271 *wl,
struct wl12xx_fw_status *status) struct wl_fw_status *status)
{ {
struct wl12xx_vif *wlvif; struct wl12xx_vif *wlvif;
struct timespec ts; struct timespec ts;
u32 old_tx_blk_count = wl->tx_blocks_available; u32 old_tx_blk_count = wl->tx_blocks_available;
int avail, freed_blocks; int avail, freed_blocks;
int i; int i;
size_t status_len;
wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false); status_len = sizeof(*status) + wl->fw_status_priv_len;
wlcore_raw_read_data(wl, REG_RAW_FW_STATUS_ADDR, status,
status_len, false);
wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, " wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
"drv_rx_counter = %d, tx_results_counter = %d)", "drv_rx_counter = %d, tx_results_counter = %d)",
...@@ -801,10 +443,10 @@ static void wl12xx_fw_status(struct wl1271 *wl, ...@@ -801,10 +443,10 @@ static void wl12xx_fw_status(struct wl1271 *wl,
for (i = 0; i < NUM_TX_QUEUES; i++) { for (i = 0; i < NUM_TX_QUEUES; i++) {
/* prevent wrap-around in freed-packets counter */ /* prevent wrap-around in freed-packets counter */
wl->tx_allocated_pkts[i] -= wl->tx_allocated_pkts[i] -=
(status->tx_released_pkts[i] - (status->counters.tx_released_pkts[i] -
wl->tx_pkts_freed[i]) & 0xff; wl->tx_pkts_freed[i]) & 0xff;
wl->tx_pkts_freed[i] = status->tx_released_pkts[i]; wl->tx_pkts_freed[i] = status->counters.tx_released_pkts[i];
} }
/* prevent wrap-around in total blocks counter */ /* prevent wrap-around in total blocks counter */
...@@ -927,6 +569,9 @@ static irqreturn_t wl1271_irq(int irq, void *cookie) ...@@ -927,6 +569,9 @@ static irqreturn_t wl1271_irq(int irq, void *cookie)
smp_mb__after_clear_bit(); smp_mb__after_clear_bit();
wl12xx_fw_status(wl, wl->fw_status); wl12xx_fw_status(wl, wl->fw_status);
wlcore_hw_tx_immediate_compl(wl);
intr = le32_to_cpu(wl->fw_status->intr); intr = le32_to_cpu(wl->fw_status->intr);
intr &= WL1271_INTR_MASK; intr &= WL1271_INTR_MASK;
if (!intr) { if (!intr) {
...@@ -963,9 +608,7 @@ static irqreturn_t wl1271_irq(int irq, void *cookie) ...@@ -963,9 +608,7 @@ static irqreturn_t wl1271_irq(int irq, void *cookie)
} }
/* check for tx results */ /* check for tx results */
if (wl->fw_status->tx_results_counter != wlcore_hw_tx_delayed_compl(wl);
(wl->tx_results_count & 0xff))
wl1271_tx_complete(wl);
/* Make sure the deferred queues don't get too long */ /* Make sure the deferred queues don't get too long */
defer_count = skb_queue_len(&wl->deferred_tx_queue) + defer_count = skb_queue_len(&wl->deferred_tx_queue) +
...@@ -1046,10 +689,7 @@ static int wl12xx_fetch_firmware(struct wl1271 *wl, bool plt) ...@@ -1046,10 +689,7 @@ static int wl12xx_fetch_firmware(struct wl1271 *wl, bool plt)
if (plt) { if (plt) {
fw_type = WL12XX_FW_TYPE_PLT; fw_type = WL12XX_FW_TYPE_PLT;
if (wl->chip.id == CHIP_ID_1283_PG20) fw_name = wl->plt_fw_name;
fw_name = WL128X_PLT_FW_NAME;
else
fw_name = WL127X_PLT_FW_NAME;
} else { } else {
/* /*
* we can't call wl12xx_get_vif_count() here because * we can't call wl12xx_get_vif_count() here because
...@@ -1057,16 +697,10 @@ static int wl12xx_fetch_firmware(struct wl1271 *wl, bool plt) ...@@ -1057,16 +697,10 @@ static int wl12xx_fetch_firmware(struct wl1271 *wl, bool plt)
*/ */
if (wl->last_vif_count > 1) { if (wl->last_vif_count > 1) {
fw_type = WL12XX_FW_TYPE_MULTI; fw_type = WL12XX_FW_TYPE_MULTI;
if (wl->chip.id == CHIP_ID_1283_PG20) fw_name = wl->mr_fw_name;
fw_name = WL128X_FW_NAME_MULTI;
else
fw_name = WL127X_FW_NAME_MULTI;
} else { } else {
fw_type = WL12XX_FW_TYPE_NORMAL; fw_type = WL12XX_FW_TYPE_NORMAL;
if (wl->chip.id == CHIP_ID_1283_PG20) fw_name = wl->sr_fw_name;
fw_name = WL128X_FW_NAME_SINGLE;
else
fw_name = WL127X_FW_NAME_SINGLE;
} }
} }
...@@ -1173,7 +807,7 @@ static void wl12xx_read_fwlog_panic(struct wl1271 *wl) ...@@ -1173,7 +807,7 @@ static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
u32 first_addr; u32 first_addr;
u8 *block; u8 *block;
if ((wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) || if ((wl->quirks & WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
(wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) || (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) ||
(wl->conf.fwlog.mem_blocks == 0)) (wl->conf.fwlog.mem_blocks == 0))
return; return;
...@@ -1239,11 +873,20 @@ static void wl1271_recovery_work(struct work_struct *work) ...@@ -1239,11 +873,20 @@ static void wl1271_recovery_work(struct work_struct *work)
wl12xx_read_fwlog_panic(wl); wl12xx_read_fwlog_panic(wl);
wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x", wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4)); wl->chip.fw_ver_str,
wlcore_read_reg(wl, REG_PC_ON_RECOVERY));
BUG_ON(bug_on_recovery && BUG_ON(bug_on_recovery &&
!test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags)); !test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags));
if (no_recovery) {
wl1271_info("No recovery (chosen on module load). Fw will remain stuck.");
clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
goto out_unlock;
}
BUG_ON(bug_on_recovery);
/* /*
* Advance security sequence number to overcome potential progress * Advance security sequence number to overcome potential progress
* in the firmware during recovery. This doens't hurt if the network is * in the firmware during recovery. This doens't hurt if the network is
...@@ -1290,10 +933,7 @@ static void wl1271_recovery_work(struct work_struct *work) ...@@ -1290,10 +933,7 @@ static void wl1271_recovery_work(struct work_struct *work)
static void wl1271_fw_wakeup(struct wl1271 *wl) static void wl1271_fw_wakeup(struct wl1271 *wl)
{ {
u32 elp_reg; wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_WAKE_UP);
elp_reg = ELPCTRL_WAKE_UP;
wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
} }
static int wl1271_setup(struct wl1271 *wl) static int wl1271_setup(struct wl1271 *wl)
...@@ -1323,7 +963,7 @@ static int wl12xx_set_power_on(struct wl1271 *wl) ...@@ -1323,7 +963,7 @@ static int wl12xx_set_power_on(struct wl1271 *wl)
wl1271_io_reset(wl); wl1271_io_reset(wl);
wl1271_io_init(wl); wl1271_io_init(wl);
wl1271_set_partition(wl, &wl12xx_part_table[PART_DOWN]); wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
/* ELP module wake up */ /* ELP module wake up */
wl1271_fw_wakeup(wl); wl1271_fw_wakeup(wl);
...@@ -1348,44 +988,18 @@ static int wl12xx_chip_wakeup(struct wl1271 *wl, bool plt) ...@@ -1348,44 +988,18 @@ static int wl12xx_chip_wakeup(struct wl1271 *wl, bool plt)
* negligible, we use the same block size for all different * negligible, we use the same block size for all different
* chip types. * chip types.
*/ */
if (!wl1271_set_block_size(wl)) if (wl1271_set_block_size(wl))
wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT; wl->quirks |= WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN;
switch (wl->chip.id) {
case CHIP_ID_1271_PG10:
wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
wl->chip.id);
ret = wl1271_setup(wl);
if (ret < 0)
goto out;
wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
break;
case CHIP_ID_1271_PG20: ret = wl->ops->identify_chip(wl);
wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
wl->chip.id);
ret = wl1271_setup(wl);
if (ret < 0) if (ret < 0)
goto out; goto out;
wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
break;
case CHIP_ID_1283_PG20: /* TODO: make sure the lower driver has set things up correctly */
wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
wl->chip.id);
ret = wl1271_setup(wl); ret = wl1271_setup(wl);
if (ret < 0) if (ret < 0)
goto out; goto out;
break;
case CHIP_ID_1283_PG10:
default:
wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
ret = -ENODEV;
goto out;
}
ret = wl12xx_fetch_firmware(wl, plt); ret = wl12xx_fetch_firmware(wl, plt);
if (ret < 0) if (ret < 0)
...@@ -1425,7 +1039,7 @@ int wl1271_plt_start(struct wl1271 *wl) ...@@ -1425,7 +1039,7 @@ int wl1271_plt_start(struct wl1271 *wl)
if (ret < 0) if (ret < 0)
goto power_off; goto power_off;
ret = wl1271_boot(wl); ret = wl->ops->boot(wl);
if (ret < 0) if (ret < 0)
goto power_off; goto power_off;
...@@ -1454,7 +1068,7 @@ int wl1271_plt_start(struct wl1271 *wl) ...@@ -1454,7 +1068,7 @@ int wl1271_plt_start(struct wl1271 *wl)
work function will not do anything.) Also, any other work function will not do anything.) Also, any other
possible concurrent operations will fail due to the possible concurrent operations will fail due to the
current state, hence the wl1271 struct should be safe. */ current state, hence the wl1271 struct should be safe. */
wl1271_disable_interrupts(wl); wlcore_disable_interrupts(wl);
wl1271_flush_deferred_work(wl); wl1271_flush_deferred_work(wl);
cancel_work_sync(&wl->netstack_work); cancel_work_sync(&wl->netstack_work);
mutex_lock(&wl->mutex); mutex_lock(&wl->mutex);
...@@ -1481,7 +1095,7 @@ int wl1271_plt_stop(struct wl1271 *wl) ...@@ -1481,7 +1095,7 @@ int wl1271_plt_stop(struct wl1271 *wl)
* Otherwise, the interrupt handler might be called and exit without * Otherwise, the interrupt handler might be called and exit without
* reading the interrupt status. * reading the interrupt status.
*/ */
wl1271_disable_interrupts(wl); wlcore_disable_interrupts(wl);
mutex_lock(&wl->mutex); mutex_lock(&wl->mutex);
if (!wl->plt) { if (!wl->plt) {
mutex_unlock(&wl->mutex); mutex_unlock(&wl->mutex);
...@@ -1491,7 +1105,7 @@ int wl1271_plt_stop(struct wl1271 *wl) ...@@ -1491,7 +1105,7 @@ int wl1271_plt_stop(struct wl1271 *wl)
* may have been disabled when op_stop was called. It will, * may have been disabled when op_stop was called. It will,
* however, balance the above call to disable_interrupts(). * however, balance the above call to disable_interrupts().
*/ */
wl1271_enable_interrupts(wl); wlcore_enable_interrupts(wl);
wl1271_error("cannot power down because not in PLT " wl1271_error("cannot power down because not in PLT "
"state: %d", wl->state); "state: %d", wl->state);
...@@ -1652,14 +1266,12 @@ static int wl1271_configure_suspend_sta(struct wl1271 *wl, ...@@ -1652,14 +1266,12 @@ static int wl1271_configure_suspend_sta(struct wl1271 *wl,
{ {
int ret = 0; int ret = 0;
mutex_lock(&wl->mutex);
if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
goto out_unlock; goto out;
ret = wl1271_ps_elp_wakeup(wl); ret = wl1271_ps_elp_wakeup(wl);
if (ret < 0) if (ret < 0)
goto out_unlock; goto out;
ret = wl1271_acx_wake_up_conditions(wl, wlvif, ret = wl1271_acx_wake_up_conditions(wl, wlvif,
wl->conf.conn.suspend_wake_up_event, wl->conf.conn.suspend_wake_up_event,
...@@ -1668,11 +1280,9 @@ static int wl1271_configure_suspend_sta(struct wl1271 *wl, ...@@ -1668,11 +1280,9 @@ static int wl1271_configure_suspend_sta(struct wl1271 *wl,
if (ret < 0) if (ret < 0)
wl1271_error("suspend: set wake up conditions failed: %d", ret); wl1271_error("suspend: set wake up conditions failed: %d", ret);
wl1271_ps_elp_sleep(wl); wl1271_ps_elp_sleep(wl);
out_unlock: out:
mutex_unlock(&wl->mutex);
return ret; return ret;
} }
...@@ -1682,20 +1292,17 @@ static int wl1271_configure_suspend_ap(struct wl1271 *wl, ...@@ -1682,20 +1292,17 @@ static int wl1271_configure_suspend_ap(struct wl1271 *wl,
{ {
int ret = 0; int ret = 0;
mutex_lock(&wl->mutex);
if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
goto out_unlock; goto out;
ret = wl1271_ps_elp_wakeup(wl); ret = wl1271_ps_elp_wakeup(wl);
if (ret < 0) if (ret < 0)
goto out_unlock; goto out;
ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true); ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
wl1271_ps_elp_sleep(wl); wl1271_ps_elp_sleep(wl);
out_unlock: out:
mutex_unlock(&wl->mutex);
return ret; return ret;
} }
...@@ -1720,10 +1327,9 @@ static void wl1271_configure_resume(struct wl1271 *wl, ...@@ -1720,10 +1327,9 @@ static void wl1271_configure_resume(struct wl1271 *wl,
if ((!is_ap) && (!is_sta)) if ((!is_ap) && (!is_sta))
return; return;
mutex_lock(&wl->mutex);
ret = wl1271_ps_elp_wakeup(wl); ret = wl1271_ps_elp_wakeup(wl);
if (ret < 0) if (ret < 0)
goto out; return;
if (is_sta) { if (is_sta) {
ret = wl1271_acx_wake_up_conditions(wl, wlvif, ret = wl1271_acx_wake_up_conditions(wl, wlvif,
...@@ -1739,8 +1345,6 @@ static void wl1271_configure_resume(struct wl1271 *wl, ...@@ -1739,8 +1345,6 @@ static void wl1271_configure_resume(struct wl1271 *wl,
} }
wl1271_ps_elp_sleep(wl); wl1271_ps_elp_sleep(wl);
out:
mutex_unlock(&wl->mutex);
} }
static int wl1271_op_suspend(struct ieee80211_hw *hw, static int wl1271_op_suspend(struct ieee80211_hw *hw,
...@@ -1755,6 +1359,7 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw, ...@@ -1755,6 +1359,7 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw,
wl1271_tx_flush(wl); wl1271_tx_flush(wl);
mutex_lock(&wl->mutex);
wl->wow_enabled = true; wl->wow_enabled = true;
wl12xx_for_each_wlvif(wl, wlvif) { wl12xx_for_each_wlvif(wl, wlvif) {
ret = wl1271_configure_suspend(wl, wlvif); ret = wl1271_configure_suspend(wl, wlvif);
...@@ -1763,6 +1368,7 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw, ...@@ -1763,6 +1368,7 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw,
return ret; return ret;
} }
} }
mutex_unlock(&wl->mutex);
/* flush any remaining work */ /* flush any remaining work */
wl1271_debug(DEBUG_MAC80211, "flushing remaining works"); wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
...@@ -1770,7 +1376,7 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw, ...@@ -1770,7 +1376,7 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw,
* disable and re-enable interrupts in order to flush * disable and re-enable interrupts in order to flush
* the threaded_irq * the threaded_irq
*/ */
wl1271_disable_interrupts(wl); wlcore_disable_interrupts(wl);
/* /*
* set suspended flag to avoid triggering a new threaded_irq * set suspended flag to avoid triggering a new threaded_irq
...@@ -1778,7 +1384,7 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw, ...@@ -1778,7 +1384,7 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw,
*/ */
set_bit(WL1271_FLAG_SUSPENDED, &wl->flags); set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
wl1271_enable_interrupts(wl); wlcore_enable_interrupts(wl);
flush_work(&wl->tx_work); flush_work(&wl->tx_work);
flush_delayed_work(&wl->elp_work); flush_delayed_work(&wl->elp_work);
...@@ -1810,12 +1416,15 @@ static int wl1271_op_resume(struct ieee80211_hw *hw) ...@@ -1810,12 +1416,15 @@ static int wl1271_op_resume(struct ieee80211_hw *hw)
wl1271_debug(DEBUG_MAC80211, wl1271_debug(DEBUG_MAC80211,
"run postponed irq_work directly"); "run postponed irq_work directly");
wl1271_irq(0, wl); wl1271_irq(0, wl);
wl1271_enable_interrupts(wl); wlcore_enable_interrupts(wl);
} }
mutex_lock(&wl->mutex);
wl12xx_for_each_wlvif(wl, wlvif) { wl12xx_for_each_wlvif(wl, wlvif) {
wl1271_configure_resume(wl, wlvif); wl1271_configure_resume(wl, wlvif);
} }
wl->wow_enabled = false; wl->wow_enabled = false;
mutex_unlock(&wl->mutex);
return 0; return 0;
} }
...@@ -1851,7 +1460,7 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) ...@@ -1851,7 +1460,7 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
* Otherwise, the interrupt handler might be called and exit without * Otherwise, the interrupt handler might be called and exit without
* reading the interrupt status. * reading the interrupt status.
*/ */
wl1271_disable_interrupts(wl); wlcore_disable_interrupts(wl);
mutex_lock(&wl->mutex); mutex_lock(&wl->mutex);
if (wl->state == WL1271_STATE_OFF) { if (wl->state == WL1271_STATE_OFF) {
mutex_unlock(&wl->mutex); mutex_unlock(&wl->mutex);
...@@ -1861,7 +1470,7 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) ...@@ -1861,7 +1470,7 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
* may have been disabled when op_stop was called. It will, * may have been disabled when op_stop was called. It will,
* however, balance the above call to disable_interrupts(). * however, balance the above call to disable_interrupts().
*/ */
wl1271_enable_interrupts(wl); wlcore_enable_interrupts(wl);
return; return;
} }
...@@ -1894,7 +1503,6 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) ...@@ -1894,7 +1503,6 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
wl->tx_results_count = 0; wl->tx_results_count = 0;
wl->tx_packets_count = 0; wl->tx_packets_count = 0;
wl->time_offset = 0; wl->time_offset = 0;
wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
wl->ap_fw_ps_map = 0; wl->ap_fw_ps_map = 0;
wl->ap_ps_map = 0; wl->ap_ps_map = 0;
wl->sched_scanning = false; wl->sched_scanning = false;
...@@ -2067,7 +1675,7 @@ static bool wl12xx_init_fw(struct wl1271 *wl) ...@@ -2067,7 +1675,7 @@ static bool wl12xx_init_fw(struct wl1271 *wl)
if (ret < 0) if (ret < 0)
goto power_off; goto power_off;
ret = wl1271_boot(wl); ret = wl->ops->boot(wl);
if (ret < 0) if (ret < 0)
goto power_off; goto power_off;
...@@ -2087,7 +1695,7 @@ static bool wl12xx_init_fw(struct wl1271 *wl) ...@@ -2087,7 +1695,7 @@ static bool wl12xx_init_fw(struct wl1271 *wl)
work function will not do anything.) Also, any other work function will not do anything.) Also, any other
possible concurrent operations will fail due to the possible concurrent operations will fail due to the
current state, hence the wl1271 struct should be safe. */ current state, hence the wl1271 struct should be safe. */
wl1271_disable_interrupts(wl); wlcore_disable_interrupts(wl);
wl1271_flush_deferred_work(wl); wl1271_flush_deferred_work(wl);
cancel_work_sync(&wl->netstack_work); cancel_work_sync(&wl->netstack_work);
mutex_lock(&wl->mutex); mutex_lock(&wl->mutex);
...@@ -2360,10 +1968,12 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, ...@@ -2360,10 +1968,12 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++) for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
wl12xx_free_rate_policy(wl, wl12xx_free_rate_policy(wl,
&wlvif->ap.ucast_rate_idx[i]); &wlvif->ap.ucast_rate_idx[i]);
wl1271_free_ap_keys(wl, wlvif);
} }
dev_kfree_skb(wlvif->probereq);
wlvif->probereq = NULL;
wl12xx_tx_reset_wlvif(wl, wlvif); wl12xx_tx_reset_wlvif(wl, wlvif);
wl1271_free_ap_keys(wl, wlvif);
if (wl->last_wlvif == wlvif) if (wl->last_wlvif == wlvif)
wl->last_wlvif = NULL; wl->last_wlvif = NULL;
list_del(&wlvif->list); list_del(&wlvif->list);
...@@ -2946,6 +2556,17 @@ static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif, ...@@ -2946,6 +2556,17 @@ static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
int ret; int ret;
bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
/*
* A role set to GEM cipher requires different Tx settings (namely
* spare blocks). Note when we are in this mode so the HW can adjust.
*/
if (key_type == KEY_GEM) {
if (action == KEY_ADD_OR_REPLACE)
wlvif->is_gem = true;
else if (action == KEY_REMOVE)
wlvif->is_gem = false;
}
if (is_ap) { if (is_ap) {
struct wl1271_station *wl_sta; struct wl1271_station *wl_sta;
u8 hlid; u8 hlid;
...@@ -2984,17 +2605,6 @@ static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif, ...@@ -2984,17 +2605,6 @@ static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
}; };
/*
* A STA set to GEM cipher requires 2 tx spare blocks.
* Return to default value when GEM cipher key is removed
*/
if (key_type == KEY_GEM) {
if (action == KEY_ADD_OR_REPLACE)
wl->tx_spare_blocks = 2;
else if (action == KEY_REMOVE)
wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
}
addr = sta ? sta->addr : bcast_addr; addr = sta ? sta->addr : bcast_addr;
if (is_zero_ether_addr(addr)) { if (is_zero_ether_addr(addr)) {
...@@ -3791,8 +3401,7 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, ...@@ -3791,8 +3401,7 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
wlvif->rssi_thold = bss_conf->cqm_rssi_thold; wlvif->rssi_thold = bss_conf->cqm_rssi_thold;
} }
if (changed & BSS_CHANGED_BSSID && if (changed & BSS_CHANGED_BSSID)
(is_ibss || bss_conf->assoc))
if (!is_zero_ether_addr(bss_conf->bssid)) { if (!is_zero_ether_addr(bss_conf->bssid)) {
ret = wl12xx_cmd_build_null_data(wl, wlvif); ret = wl12xx_cmd_build_null_data(wl, wlvif);
if (ret < 0) if (ret < 0)
...@@ -3801,9 +3410,6 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, ...@@ -3801,9 +3410,6 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
ret = wl1271_build_qos_null_data(wl, vif); ret = wl1271_build_qos_null_data(wl, vif);
if (ret < 0) if (ret < 0)
goto out; goto out;
/* Need to update the BSSID (for filtering etc) */
do_join = true;
} }
if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) { if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
...@@ -3830,6 +3436,7 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, ...@@ -3830,6 +3436,7 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
int ieoffset; int ieoffset;
wlvif->aid = bss_conf->aid; wlvif->aid = bss_conf->aid;
wlvif->beacon_int = bss_conf->beacon_int; wlvif->beacon_int = bss_conf->beacon_int;
do_join = true;
set_assoc = true; set_assoc = true;
/* /*
...@@ -4662,60 +4269,12 @@ static struct ieee80211_channel wl1271_channels[] = { ...@@ -4662,60 +4269,12 @@ static struct ieee80211_channel wl1271_channels[] = {
{ .hw_value = 14, .center_freq = 2484, .max_power = 25 }, { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
}; };
/* mapping to indexes for wl1271_rates */
static const u8 wl1271_rate_to_idx_2ghz[] = {
/* MCS rates are used only with 11n */
7, /* CONF_HW_RXTX_RATE_MCS7_SGI */
7, /* CONF_HW_RXTX_RATE_MCS7 */
6, /* CONF_HW_RXTX_RATE_MCS6 */
5, /* CONF_HW_RXTX_RATE_MCS5 */
4, /* CONF_HW_RXTX_RATE_MCS4 */
3, /* CONF_HW_RXTX_RATE_MCS3 */
2, /* CONF_HW_RXTX_RATE_MCS2 */
1, /* CONF_HW_RXTX_RATE_MCS1 */
0, /* CONF_HW_RXTX_RATE_MCS0 */
11, /* CONF_HW_RXTX_RATE_54 */
10, /* CONF_HW_RXTX_RATE_48 */
9, /* CONF_HW_RXTX_RATE_36 */
8, /* CONF_HW_RXTX_RATE_24 */
/* TI-specific rate */
CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
7, /* CONF_HW_RXTX_RATE_18 */
6, /* CONF_HW_RXTX_RATE_12 */
3, /* CONF_HW_RXTX_RATE_11 */
5, /* CONF_HW_RXTX_RATE_9 */
4, /* CONF_HW_RXTX_RATE_6 */
2, /* CONF_HW_RXTX_RATE_5_5 */
1, /* CONF_HW_RXTX_RATE_2 */
0 /* CONF_HW_RXTX_RATE_1 */
};
/* 11n STA capabilities */
#define HW_RX_HIGHEST_RATE 72
#define WL12XX_HT_CAP { \
.cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
(1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
.ht_supported = true, \
.ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
.ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
.mcs = { \
.rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
.rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
.tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
}, \
}
/* can't be const, mac80211 writes to this */ /* can't be const, mac80211 writes to this */
static struct ieee80211_supported_band wl1271_band_2ghz = { static struct ieee80211_supported_band wl1271_band_2ghz = {
.channels = wl1271_channels, .channels = wl1271_channels,
.n_channels = ARRAY_SIZE(wl1271_channels), .n_channels = ARRAY_SIZE(wl1271_channels),
.bitrates = wl1271_rates, .bitrates = wl1271_rates,
.n_bitrates = ARRAY_SIZE(wl1271_rates), .n_bitrates = ARRAY_SIZE(wl1271_rates),
.ht_cap = WL12XX_HT_CAP,
}; };
/* 5 GHz data rates for WL1273 */ /* 5 GHz data rates for WL1273 */
...@@ -4784,48 +4343,11 @@ static struct ieee80211_channel wl1271_channels_5ghz[] = { ...@@ -4784,48 +4343,11 @@ static struct ieee80211_channel wl1271_channels_5ghz[] = {
{ .hw_value = 165, .center_freq = 5825, .max_power = 25 }, { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
}; };
/* mapping to indexes for wl1271_rates_5ghz */
static const u8 wl1271_rate_to_idx_5ghz[] = {
/* MCS rates are used only with 11n */
7, /* CONF_HW_RXTX_RATE_MCS7_SGI */
7, /* CONF_HW_RXTX_RATE_MCS7 */
6, /* CONF_HW_RXTX_RATE_MCS6 */
5, /* CONF_HW_RXTX_RATE_MCS5 */
4, /* CONF_HW_RXTX_RATE_MCS4 */
3, /* CONF_HW_RXTX_RATE_MCS3 */
2, /* CONF_HW_RXTX_RATE_MCS2 */
1, /* CONF_HW_RXTX_RATE_MCS1 */
0, /* CONF_HW_RXTX_RATE_MCS0 */
7, /* CONF_HW_RXTX_RATE_54 */
6, /* CONF_HW_RXTX_RATE_48 */
5, /* CONF_HW_RXTX_RATE_36 */
4, /* CONF_HW_RXTX_RATE_24 */
/* TI-specific rate */
CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3, /* CONF_HW_RXTX_RATE_18 */
2, /* CONF_HW_RXTX_RATE_12 */
CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
1, /* CONF_HW_RXTX_RATE_9 */
0, /* CONF_HW_RXTX_RATE_6 */
CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
};
static struct ieee80211_supported_band wl1271_band_5ghz = { static struct ieee80211_supported_band wl1271_band_5ghz = {
.channels = wl1271_channels_5ghz, .channels = wl1271_channels_5ghz,
.n_channels = ARRAY_SIZE(wl1271_channels_5ghz), .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
.bitrates = wl1271_rates_5ghz, .bitrates = wl1271_rates_5ghz,
.n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz), .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
.ht_cap = WL12XX_HT_CAP,
};
static const u8 *wl1271_band_rate_to_idx[] = {
[IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
[IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
}; };
static const struct ieee80211_ops wl1271_ops = { static const struct ieee80211_ops wl1271_ops = {
...@@ -4862,18 +4384,18 @@ static const struct ieee80211_ops wl1271_ops = { ...@@ -4862,18 +4384,18 @@ static const struct ieee80211_ops wl1271_ops = {
}; };
u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band) u8 wlcore_rate_to_idx(struct wl1271 *wl, u8 rate, enum ieee80211_band band)
{ {
u8 idx; u8 idx;
BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *)); BUG_ON(band >= 2);
if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) { if (unlikely(rate >= wl->hw_tx_rate_tbl_size)) {
wl1271_error("Illegal RX rate from HW: %d", rate); wl1271_error("Illegal RX rate from HW: %d", rate);
return 0; return 0;
} }
idx = wl1271_band_rate_to_idx[band][rate]; idx = wl->band_rate_to_idx[band][rate];
if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) { if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
wl1271_error("Unsupported RX rate from HW: %d", rate); wl1271_error("Unsupported RX rate from HW: %d", rate);
return 0; return 0;
...@@ -5027,34 +4549,6 @@ static struct bin_attribute fwlog_attr = { ...@@ -5027,34 +4549,6 @@ 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, static void wl12xx_derive_mac_addresses(struct wl1271 *wl,
u32 oui, u32 nic, int n) u32 oui, u32 nic, int n)
{ {
...@@ -5080,47 +4574,23 @@ static void wl12xx_derive_mac_addresses(struct wl1271 *wl, ...@@ -5080,47 +4574,23 @@ static void wl12xx_derive_mac_addresses(struct wl1271 *wl,
wl->hw->wiphy->addresses = wl->addresses; 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;
u32 die_info;
ret = wl12xx_set_power_on(wl); ret = wl12xx_set_power_on(wl);
if (ret < 0) if (ret < 0)
goto out; goto out;
wl->chip.id = wl1271_read32(wl, CHIP_ID_B); wl->chip.id = wlcore_read_reg(wl, REG_CHIP_ID_B);
if (wl->chip.id == CHIP_ID_1283_PG20)
die_info = wl1271_top_reg_read(wl, WL128X_REG_FUSE_DATA_2_1);
else
die_info = wl1271_top_reg_read(wl, WL127X_REG_FUSE_DATA_2_1);
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_oui_addr = 0;
wl->fuse_nic_addr = 0; wl->fuse_nic_addr = 0;
} else {
wl12xx_get_fuse_mac(wl); wl->hw_pg_ver = wl->ops->get_pg_ver(wl);
}
if (wl->ops->get_mac)
wl->ops->get_mac(wl);
wl1271_power_off(wl); wl1271_power_off(wl);
out: out:
...@@ -5255,8 +4725,12 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) ...@@ -5255,8 +4725,12 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
*/ */
memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz, memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
sizeof(wl1271_band_2ghz)); sizeof(wl1271_band_2ghz));
memcpy(&wl->bands[IEEE80211_BAND_2GHZ].ht_cap, &wl->ht_cap,
sizeof(wl->ht_cap));
memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz, memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
sizeof(wl1271_band_5ghz)); sizeof(wl1271_band_5ghz));
memcpy(&wl->bands[IEEE80211_BAND_5GHZ].ht_cap, &wl->ht_cap,
sizeof(wl->ht_cap));
wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
&wl->bands[IEEE80211_BAND_2GHZ]; &wl->bands[IEEE80211_BAND_2GHZ];
...@@ -5280,14 +4754,14 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) ...@@ -5280,14 +4754,14 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
wl->hw->sta_data_size = sizeof(struct wl1271_station); wl->hw->sta_data_size = sizeof(struct wl1271_station);
wl->hw->vif_data_size = sizeof(struct wl12xx_vif); wl->hw->vif_data_size = sizeof(struct wl12xx_vif);
wl->hw->max_rx_aggregation_subframes = 8; wl->hw->max_rx_aggregation_subframes = wl->conf.ht.rx_ba_win_size;
return 0; return 0;
} }
#define WL1271_DEFAULT_CHANNEL 0 #define WL1271_DEFAULT_CHANNEL 0
static struct ieee80211_hw *wl1271_alloc_hw(void) struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size)
{ {
struct ieee80211_hw *hw; struct ieee80211_hw *hw;
struct wl1271 *wl; struct wl1271 *wl;
...@@ -5306,6 +4780,13 @@ static struct ieee80211_hw *wl1271_alloc_hw(void) ...@@ -5306,6 +4780,13 @@ static struct ieee80211_hw *wl1271_alloc_hw(void)
wl = hw->priv; wl = hw->priv;
memset(wl, 0, sizeof(*wl)); memset(wl, 0, sizeof(*wl));
wl->priv = kzalloc(priv_size, GFP_KERNEL);
if (!wl->priv) {
wl1271_error("could not alloc wl priv");
ret = -ENOMEM;
goto err_priv_alloc;
}
INIT_LIST_HEAD(&wl->wlvif_list); INIT_LIST_HEAD(&wl->wlvif_list);
wl->hw = hw; wl->hw = hw;
...@@ -5342,7 +4823,6 @@ static struct ieee80211_hw *wl1271_alloc_hw(void) ...@@ -5342,7 +4823,6 @@ static struct ieee80211_hw *wl1271_alloc_hw(void)
wl->quirks = 0; wl->quirks = 0;
wl->platform_quirks = 0; wl->platform_quirks = 0;
wl->sched_scanning = false; wl->sched_scanning = false;
wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
wl->system_hlid = WL12XX_SYSTEM_HLID; wl->system_hlid = WL12XX_SYSTEM_HLID;
wl->active_sta_count = 0; wl->active_sta_count = 0;
wl->fwlog_size = 0; wl->fwlog_size = 0;
...@@ -5352,7 +4832,7 @@ static struct ieee80211_hw *wl1271_alloc_hw(void) ...@@ -5352,7 +4832,7 @@ static struct ieee80211_hw *wl1271_alloc_hw(void)
__set_bit(WL12XX_SYSTEM_HLID, wl->links_map); __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map)); memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
for (i = 0; i < ACX_TX_DESCRIPTORS; i++) for (i = 0; i < wl->num_tx_desc; i++)
wl->tx_frames[i] = NULL; wl->tx_frames[i] = NULL;
spin_lock_init(&wl->wl_lock); spin_lock_init(&wl->wl_lock);
...@@ -5361,9 +4841,6 @@ static struct ieee80211_hw *wl1271_alloc_hw(void) ...@@ -5361,9 +4841,6 @@ static struct ieee80211_hw *wl1271_alloc_hw(void)
wl->fw_type = WL12XX_FW_TYPE_NONE; wl->fw_type = WL12XX_FW_TYPE_NONE;
mutex_init(&wl->mutex); mutex_init(&wl->mutex);
/* Apply default driver configuration. */
wl1271_conf_init(wl);
order = get_order(WL1271_AGGR_BUFFER_SIZE); order = get_order(WL1271_AGGR_BUFFER_SIZE);
wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order); wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
if (!wl->aggr_buf) { if (!wl->aggr_buf) {
...@@ -5384,8 +4861,17 @@ static struct ieee80211_hw *wl1271_alloc_hw(void) ...@@ -5384,8 +4861,17 @@ static struct ieee80211_hw *wl1271_alloc_hw(void)
goto err_dummy_packet; goto err_dummy_packet;
} }
wl->mbox = kmalloc(sizeof(*wl->mbox), GFP_DMA);
if (!wl->mbox) {
ret = -ENOMEM;
goto err_fwlog;
}
return hw; return hw;
err_fwlog:
free_page((unsigned long)wl->fwlog);
err_dummy_packet: err_dummy_packet:
dev_kfree_skb(wl->dummy_packet); dev_kfree_skb(wl->dummy_packet);
...@@ -5397,14 +4883,18 @@ static struct ieee80211_hw *wl1271_alloc_hw(void) ...@@ -5397,14 +4883,18 @@ static struct ieee80211_hw *wl1271_alloc_hw(void)
err_hw: err_hw:
wl1271_debugfs_exit(wl); wl1271_debugfs_exit(wl);
kfree(wl->priv);
err_priv_alloc:
ieee80211_free_hw(hw); ieee80211_free_hw(hw);
err_hw_alloc: err_hw_alloc:
return ERR_PTR(ret); return ERR_PTR(ret);
} }
EXPORT_SYMBOL_GPL(wlcore_alloc_hw);
static int wl1271_free_hw(struct wl1271 *wl) int wlcore_free_hw(struct wl1271 *wl)
{ {
/* Unblock any fwlog readers */ /* Unblock any fwlog readers */
mutex_lock(&wl->mutex); mutex_lock(&wl->mutex);
...@@ -5434,10 +4924,12 @@ static int wl1271_free_hw(struct wl1271 *wl) ...@@ -5434,10 +4924,12 @@ static int wl1271_free_hw(struct wl1271 *wl)
kfree(wl->tx_res_if); kfree(wl->tx_res_if);
destroy_workqueue(wl->freezable_wq); destroy_workqueue(wl->freezable_wq);
kfree(wl->priv);
ieee80211_free_hw(wl->hw); ieee80211_free_hw(wl->hw);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(wlcore_free_hw);
static irqreturn_t wl12xx_hardirq(int irq, void *cookie) static irqreturn_t wl12xx_hardirq(int irq, void *cookie)
{ {
...@@ -5468,22 +4960,22 @@ static irqreturn_t wl12xx_hardirq(int irq, void *cookie) ...@@ -5468,22 +4960,22 @@ static irqreturn_t wl12xx_hardirq(int irq, void *cookie)
return IRQ_WAKE_THREAD; return IRQ_WAKE_THREAD;
} }
static int __devinit wl12xx_probe(struct platform_device *pdev) int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev)
{ {
struct wl12xx_platform_data *pdata = pdev->dev.platform_data; struct wl12xx_platform_data *pdata = pdev->dev.platform_data;
struct ieee80211_hw *hw;
struct wl1271 *wl;
unsigned long irqflags; unsigned long irqflags;
int ret = -ENODEV; int ret;
hw = wl1271_alloc_hw(); if (!wl->ops || !wl->ptable) {
if (IS_ERR(hw)) { ret = -EINVAL;
wl1271_error("can't allocate hw"); goto out_free_hw;
ret = PTR_ERR(hw);
goto out;
} }
wl = hw->priv; BUG_ON(wl->num_tx_desc > WLCORE_MAX_TX_DESCRIPTORS);
/* adjust some runtime configuration parameters */
wlcore_adjust_conf(wl);
wl->irq = platform_get_irq(pdev, 0); wl->irq = platform_get_irq(pdev, 0);
wl->ref_clock = pdata->board_ref_clock; wl->ref_clock = pdata->board_ref_clock;
wl->tcxo_clock = pdata->board_tcxo_clock; wl->tcxo_clock = pdata->board_tcxo_clock;
...@@ -5512,7 +5004,7 @@ static int __devinit wl12xx_probe(struct platform_device *pdev) ...@@ -5512,7 +5004,7 @@ static int __devinit wl12xx_probe(struct platform_device *pdev)
wl->irq_wake_enabled = true; wl->irq_wake_enabled = true;
device_init_wakeup(wl->dev, 1); device_init_wakeup(wl->dev, 1);
if (pdata->pwr_in_suspend) if (pdata->pwr_in_suspend)
hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY; wl->hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
} }
disable_irq(wl->irq); disable_irq(wl->irq);
...@@ -5546,7 +5038,7 @@ static int __devinit wl12xx_probe(struct platform_device *pdev) ...@@ -5546,7 +5038,7 @@ static int __devinit wl12xx_probe(struct platform_device *pdev)
goto out_hw_pg_ver; goto out_hw_pg_ver;
} }
return 0; goto out;
out_hw_pg_ver: out_hw_pg_ver:
device_remove_file(wl->dev, &dev_attr_hw_pg_ver); device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
...@@ -5558,13 +5050,14 @@ static int __devinit wl12xx_probe(struct platform_device *pdev) ...@@ -5558,13 +5050,14 @@ static int __devinit wl12xx_probe(struct platform_device *pdev)
free_irq(wl->irq, wl); free_irq(wl->irq, wl);
out_free_hw: out_free_hw:
wl1271_free_hw(wl); wlcore_free_hw(wl);
out: out:
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(wlcore_probe);
static int __devexit wl12xx_remove(struct platform_device *pdev) int __devexit wlcore_remove(struct platform_device *pdev)
{ {
struct wl1271 *wl = platform_get_drvdata(pdev); struct wl1271 *wl = platform_get_drvdata(pdev);
...@@ -5574,38 +5067,11 @@ static int __devexit wl12xx_remove(struct platform_device *pdev) ...@@ -5574,38 +5067,11 @@ static int __devexit wl12xx_remove(struct platform_device *pdev)
} }
wl1271_unregister_hw(wl); wl1271_unregister_hw(wl);
free_irq(wl->irq, wl); free_irq(wl->irq, wl);
wl1271_free_hw(wl); wlcore_free_hw(wl);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(wlcore_remove);
static const struct platform_device_id wl12xx_id_table[] __devinitconst = {
{ "wl12xx", 0 },
{ } /* Terminating Entry */
};
MODULE_DEVICE_TABLE(platform, wl12xx_id_table);
static struct platform_driver wl12xx_driver = {
.probe = wl12xx_probe,
.remove = __devexit_p(wl12xx_remove),
.id_table = wl12xx_id_table,
.driver = {
.name = "wl12xx_driver",
.owner = THIS_MODULE,
}
};
static int __init wl12xx_init(void)
{
return platform_driver_register(&wl12xx_driver);
}
module_init(wl12xx_init);
static void __exit wl12xx_exit(void)
{
platform_driver_unregister(&wl12xx_driver);
}
module_exit(wl12xx_exit);
u32 wl12xx_debug_level = DEBUG_NONE; u32 wl12xx_debug_level = DEBUG_NONE;
EXPORT_SYMBOL_GPL(wl12xx_debug_level); EXPORT_SYMBOL_GPL(wl12xx_debug_level);
...@@ -5619,6 +5085,9 @@ MODULE_PARM_DESC(fwlog, ...@@ -5619,6 +5085,9 @@ MODULE_PARM_DESC(fwlog,
module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR); module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery"); MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
module_param(no_recovery, bool, S_IRUSR | S_IWUSR);
MODULE_PARM_DESC(no_recovery, "Prevent HW recovery. FW will remain stuck.");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>"); MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>"); MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
...@@ -21,7 +21,6 @@ ...@@ -21,7 +21,6 @@
* *
*/ */
#include "reg.h"
#include "ps.h" #include "ps.h"
#include "io.h" #include "io.h"
#include "tx.h" #include "tx.h"
...@@ -62,7 +61,7 @@ void wl1271_elp_work(struct work_struct *work) ...@@ -62,7 +61,7 @@ void wl1271_elp_work(struct work_struct *work)
} }
wl1271_debug(DEBUG_PSM, "chip to elp"); wl1271_debug(DEBUG_PSM, "chip to elp");
wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP); wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_SLEEP);
set_bit(WL1271_FLAG_IN_ELP, &wl->flags); set_bit(WL1271_FLAG_IN_ELP, &wl->flags);
out: out:
...@@ -74,6 +73,9 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl) ...@@ -74,6 +73,9 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl)
{ {
struct wl12xx_vif *wlvif; struct wl12xx_vif *wlvif;
if (wl->quirks & WLCORE_QUIRK_NO_ELP)
return;
/* we shouldn't get consecutive sleep requests */ /* we shouldn't get consecutive sleep requests */
if (WARN_ON(test_and_set_bit(WL1271_FLAG_ELP_REQUESTED, &wl->flags))) if (WARN_ON(test_and_set_bit(WL1271_FLAG_ELP_REQUESTED, &wl->flags)))
return; return;
...@@ -125,7 +127,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl) ...@@ -125,7 +127,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl)
wl->elp_compl = &compl; wl->elp_compl = &compl;
spin_unlock_irqrestore(&wl->wl_lock, flags); spin_unlock_irqrestore(&wl->wl_lock, flags);
wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP); wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_WAKE_UP);
if (!pending) { if (!pending) {
ret = wait_for_completion_timeout( ret = wait_for_completion_timeout(
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
#ifndef __PS_H__ #ifndef __PS_H__
#define __PS_H__ #define __PS_H__
#include "wl12xx.h" #include "wlcore.h"
#include "acx.h" #include "acx.h"
int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
......
...@@ -24,34 +24,36 @@ ...@@ -24,34 +24,36 @@
#include <linux/gfp.h> #include <linux/gfp.h>
#include <linux/sched.h> #include <linux/sched.h>
#include "wl12xx.h" #include "wlcore.h"
#include "debug.h" #include "debug.h"
#include "acx.h" #include "acx.h"
#include "reg.h"
#include "rx.h" #include "rx.h"
#include "tx.h" #include "tx.h"
#include "io.h" #include "io.h"
#include "hw_ops.h"
static u8 wl12xx_rx_get_mem_block(struct wl12xx_fw_status *status, /*
u32 drv_rx_counter) * TODO: this is here just for now, it must be removed when the data
{ * operations are in place.
return le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]) & */
RX_MEM_BLOCK_MASK; #include "../wl12xx/reg.h"
}
static u32 wl12xx_rx_get_buf_size(struct wl12xx_fw_status *status, static u32 wlcore_rx_get_buf_size(struct wl1271 *wl,
u32 drv_rx_counter) u32 rx_pkt_desc)
{ {
return (le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]) & if (wl->quirks & WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN)
RX_BUF_SIZE_MASK) >> RX_BUF_SIZE_SHIFT_DIV; return (rx_pkt_desc & ALIGNED_RX_BUF_SIZE_MASK) >>
ALIGNED_RX_BUF_SIZE_SHIFT;
return (rx_pkt_desc & RX_BUF_SIZE_MASK) >> RX_BUF_SIZE_SHIFT_DIV;
} }
static bool wl12xx_rx_get_unaligned(struct wl12xx_fw_status *status, static u32 wlcore_rx_get_align_buf_size(struct wl1271 *wl, u32 pkt_len)
u32 drv_rx_counter)
{ {
/* Convert the value to bool */ if (wl->quirks & WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN)
return !!(le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]) & return ALIGN(pkt_len, WL12XX_BUS_BLOCK_SIZE);
RX_BUF_UNALIGNED_PAYLOAD);
return pkt_len;
} }
static void wl1271_rx_status(struct wl1271 *wl, static void wl1271_rx_status(struct wl1271 *wl,
...@@ -66,10 +68,10 @@ static void wl1271_rx_status(struct wl1271 *wl, ...@@ -66,10 +68,10 @@ static void wl1271_rx_status(struct wl1271 *wl,
else else
status->band = IEEE80211_BAND_5GHZ; status->band = IEEE80211_BAND_5GHZ;
status->rate_idx = wl1271_rate_to_idx(desc->rate, status->band); status->rate_idx = wlcore_rate_to_idx(wl, desc->rate, status->band);
/* 11n support */ /* 11n support */
if (desc->rate <= CONF_HW_RXTX_RATE_MCS0) if (desc->rate <= wl->hw_min_ht_rate)
status->flag |= RX_FLAG_HT; status->flag |= RX_FLAG_HT;
status->signal = desc->rssi; status->signal = desc->rssi;
...@@ -98,7 +100,7 @@ static void wl1271_rx_status(struct wl1271 *wl, ...@@ -98,7 +100,7 @@ static void wl1271_rx_status(struct wl1271 *wl,
} }
static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
bool unaligned, u8 *hlid) enum wl_rx_buf_align rx_align, u8 *hlid)
{ {
struct wl1271_rx_descriptor *desc; struct wl1271_rx_descriptor *desc;
struct sk_buff *skb; struct sk_buff *skb;
...@@ -106,8 +108,9 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, ...@@ -106,8 +108,9 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
u8 *buf; u8 *buf;
u8 beacon = 0; u8 beacon = 0;
u8 is_data = 0; u8 is_data = 0;
u8 reserved = unaligned ? NET_IP_ALIGN : 0; u8 reserved = 0;
u16 seq_num; u16 seq_num;
u32 pkt_data_len;
/* /*
* In PLT mode we seem to get frames and mac80211 warns about them, * In PLT mode we seem to get frames and mac80211 warns about them,
...@@ -116,6 +119,16 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, ...@@ -116,6 +119,16 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
if (unlikely(wl->plt)) if (unlikely(wl->plt))
return -EINVAL; return -EINVAL;
pkt_data_len = wlcore_hw_get_rx_packet_len(wl, data, length);
if (!pkt_data_len) {
wl1271_error("Invalid packet arrived from HW. length %d",
length);
return -EINVAL;
}
if (rx_align == WLCORE_RX_BUF_UNALIGNED)
reserved = NET_IP_ALIGN;
/* the data read starts with the descriptor */ /* the data read starts with the descriptor */
desc = (struct wl1271_rx_descriptor *) data; desc = (struct wl1271_rx_descriptor *) data;
...@@ -142,8 +155,8 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, ...@@ -142,8 +155,8 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
return -EINVAL; return -EINVAL;
} }
/* skb length not included rx descriptor */ /* skb length not including rx descriptor */
skb = __dev_alloc_skb(length + reserved - sizeof(*desc), GFP_KERNEL); skb = __dev_alloc_skb(pkt_data_len + reserved, GFP_KERNEL);
if (!skb) { if (!skb) {
wl1271_error("Couldn't allocate RX frame"); wl1271_error("Couldn't allocate RX frame");
return -ENOMEM; return -ENOMEM;
...@@ -152,7 +165,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, ...@@ -152,7 +165,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
/* reserve the unaligned payload(if any) */ /* reserve the unaligned payload(if any) */
skb_reserve(skb, reserved); skb_reserve(skb, reserved);
buf = skb_put(skb, length - sizeof(*desc)); buf = skb_put(skb, pkt_data_len);
/* /*
* Copy packets from aggregation buffer to the skbs without rx * Copy packets from aggregation buffer to the skbs without rx
...@@ -160,7 +173,10 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, ...@@ -160,7 +173,10 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
* packets copy the packets in offset of 2 bytes guarantee IP header * packets copy the packets in offset of 2 bytes guarantee IP header
* payload aligned to 4 bytes. * payload aligned to 4 bytes.
*/ */
memcpy(buf, data + sizeof(*desc), length - sizeof(*desc)); memcpy(buf, data + sizeof(*desc), pkt_data_len);
if (rx_align == WLCORE_RX_BUF_PADDED)
skb_pull(skb, NET_IP_ALIGN);
*hlid = desc->hlid; *hlid = desc->hlid;
hdr = (struct ieee80211_hdr *)skb->data; hdr = (struct ieee80211_hdr *)skb->data;
...@@ -177,36 +193,35 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, ...@@ -177,36 +193,35 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
beacon ? "beacon" : "", beacon ? "beacon" : "",
seq_num, *hlid); seq_num, *hlid);
skb_trim(skb, skb->len - desc->pad_len);
skb_queue_tail(&wl->deferred_rx_queue, skb); skb_queue_tail(&wl->deferred_rx_queue, skb);
queue_work(wl->freezable_wq, &wl->netstack_work); queue_work(wl->freezable_wq, &wl->netstack_work);
return is_data; return is_data;
} }
void wl12xx_rx(struct wl1271 *wl, struct wl12xx_fw_status *status) void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status *status)
{ {
struct wl1271_acx_mem_map *wl_mem_map = wl->target_mem_map;
unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0}; unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0};
u32 buf_size; u32 buf_size;
u32 fw_rx_counter = status->fw_rx_counter & NUM_RX_PKT_DESC_MOD_MASK; u32 fw_rx_counter = status->fw_rx_counter & NUM_RX_PKT_DESC_MOD_MASK;
u32 drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK; u32 drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK;
u32 rx_counter; u32 rx_counter;
u32 mem_block; u32 pkt_len, align_pkt_len;
u32 pkt_length; u32 pkt_offset, des;
u32 pkt_offset;
u8 hlid; u8 hlid;
bool unaligned = false; enum wl_rx_buf_align rx_align;
while (drv_rx_counter != fw_rx_counter) { while (drv_rx_counter != fw_rx_counter) {
buf_size = 0; buf_size = 0;
rx_counter = drv_rx_counter; rx_counter = drv_rx_counter;
while (rx_counter != fw_rx_counter) { while (rx_counter != fw_rx_counter) {
pkt_length = wl12xx_rx_get_buf_size(status, rx_counter); des = le32_to_cpu(status->rx_pkt_descs[rx_counter]);
if (buf_size + pkt_length > WL1271_AGGR_BUFFER_SIZE) pkt_len = wlcore_rx_get_buf_size(wl, des);
align_pkt_len = wlcore_rx_get_align_buf_size(wl,
pkt_len);
if (buf_size + align_pkt_len > WL1271_AGGR_BUFFER_SIZE)
break; break;
buf_size += pkt_length; buf_size += align_pkt_len;
rx_counter++; rx_counter++;
rx_counter &= NUM_RX_PKT_DESC_MOD_MASK; rx_counter &= NUM_RX_PKT_DESC_MOD_MASK;
} }
...@@ -216,38 +231,18 @@ void wl12xx_rx(struct wl1271 *wl, struct wl12xx_fw_status *status) ...@@ -216,38 +231,18 @@ void wl12xx_rx(struct wl1271 *wl, struct wl12xx_fw_status *status)
break; break;
} }
if (wl->chip.id != CHIP_ID_1283_PG20) {
/*
* Choose the block we want to read
* For aggregated packets, only the first memory block
* should be retrieved. The FW takes care of the rest.
*/
mem_block = wl12xx_rx_get_mem_block(status,
drv_rx_counter);
wl->rx_mem_pool_addr.addr = (mem_block << 8) +
le32_to_cpu(wl_mem_map->packet_memory_pool_start);
wl->rx_mem_pool_addr.addr_extra =
wl->rx_mem_pool_addr.addr + 4;
wl1271_write(wl, WL1271_SLV_REG_DATA,
&wl->rx_mem_pool_addr,
sizeof(wl->rx_mem_pool_addr), false);
}
/* Read all available packets at once */ /* Read all available packets at once */
wl1271_read(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf, des = le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]);
wlcore_hw_prepare_read(wl, des, buf_size);
wlcore_read_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf,
buf_size, true); buf_size, true);
/* Split data into separate packets */ /* Split data into separate packets */
pkt_offset = 0; pkt_offset = 0;
while (pkt_offset < buf_size) { while (pkt_offset < buf_size) {
pkt_length = wl12xx_rx_get_buf_size(status, des = le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]);
drv_rx_counter); pkt_len = wlcore_rx_get_buf_size(wl, des);
rx_align = wlcore_hw_get_rx_buf_align(wl, des);
unaligned = wl12xx_rx_get_unaligned(status,
drv_rx_counter);
/* /*
* the handle data call can only fail in memory-outage * the handle data call can only fail in memory-outage
...@@ -256,7 +251,7 @@ void wl12xx_rx(struct wl1271 *wl, struct wl12xx_fw_status *status) ...@@ -256,7 +251,7 @@ void wl12xx_rx(struct wl1271 *wl, struct wl12xx_fw_status *status)
*/ */
if (wl1271_rx_handle_data(wl, if (wl1271_rx_handle_data(wl,
wl->aggr_buf + pkt_offset, wl->aggr_buf + pkt_offset,
pkt_length, unaligned, pkt_len, rx_align,
&hlid) == 1) { &hlid) == 1) {
if (hlid < WL12XX_MAX_LINKS) if (hlid < WL12XX_MAX_LINKS)
__set_bit(hlid, active_hlids); __set_bit(hlid, active_hlids);
...@@ -269,7 +264,7 @@ void wl12xx_rx(struct wl1271 *wl, struct wl12xx_fw_status *status) ...@@ -269,7 +264,7 @@ void wl12xx_rx(struct wl1271 *wl, struct wl12xx_fw_status *status)
wl->rx_counter++; wl->rx_counter++;
drv_rx_counter++; drv_rx_counter++;
drv_rx_counter &= NUM_RX_PKT_DESC_MOD_MASK; drv_rx_counter &= NUM_RX_PKT_DESC_MOD_MASK;
pkt_offset += pkt_length; pkt_offset += wlcore_rx_get_align_buf_size(wl, pkt_len);
} }
} }
...@@ -277,8 +272,9 @@ void wl12xx_rx(struct wl1271 *wl, struct wl12xx_fw_status *status) ...@@ -277,8 +272,9 @@ void wl12xx_rx(struct wl1271 *wl, struct wl12xx_fw_status *status)
* Write the driver's packet counter to the FW. This is only required * Write the driver's packet counter to the FW. This is only required
* for older hardware revisions * for older hardware revisions
*/ */
if (wl->quirks & WL12XX_QUIRK_END_OF_TRANSACTION) if (wl->quirks & WLCORE_QUIRK_END_OF_TRANSACTION)
wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter); wl1271_write32(wl, WL12XX_REG_RX_DRIVER_COUNTER,
wl->rx_counter);
wl12xx_rearm_rx_streaming(wl, active_hlids); wl12xx_rearm_rx_streaming(wl, active_hlids);
} }
...@@ -96,9 +96,19 @@ ...@@ -96,9 +96,19 @@
#define RX_MEM_BLOCK_MASK 0xFF #define RX_MEM_BLOCK_MASK 0xFF
#define RX_BUF_SIZE_MASK 0xFFF00 #define RX_BUF_SIZE_MASK 0xFFF00
#define RX_BUF_SIZE_SHIFT_DIV 6 #define RX_BUF_SIZE_SHIFT_DIV 6
#define ALIGNED_RX_BUF_SIZE_MASK 0xFFFF00
#define ALIGNED_RX_BUF_SIZE_SHIFT 8
/* If set, the start of IP payload is not 4 bytes aligned */ /* If set, the start of IP payload is not 4 bytes aligned */
#define RX_BUF_UNALIGNED_PAYLOAD BIT(20) #define RX_BUF_UNALIGNED_PAYLOAD BIT(20)
/* Describes the alignment state of a Rx buffer */
enum wl_rx_buf_align {
WLCORE_RX_BUF_ALIGNED,
WLCORE_RX_BUF_UNALIGNED,
WLCORE_RX_BUF_PADDED,
};
enum { enum {
WL12XX_RX_CLASS_UNKNOWN, WL12XX_RX_CLASS_UNKNOWN,
WL12XX_RX_CLASS_MANAGEMENT, WL12XX_RX_CLASS_MANAGEMENT,
...@@ -126,7 +136,7 @@ struct wl1271_rx_descriptor { ...@@ -126,7 +136,7 @@ struct wl1271_rx_descriptor {
u8 reserved; u8 reserved;
} __packed; } __packed;
void wl12xx_rx(struct wl1271 *wl, struct wl12xx_fw_status *status); void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status *status);
u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band); u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band);
#endif #endif
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
#include <linux/ieee80211.h> #include <linux/ieee80211.h>
#include "wl12xx.h" #include "wlcore.h"
#include "debug.h" #include "debug.h"
#include "cmd.h" #include "cmd.h"
#include "scan.h" #include "scan.h"
...@@ -417,6 +417,23 @@ wl1271_scan_get_sched_scan_channels(struct wl1271 *wl, ...@@ -417,6 +417,23 @@ wl1271_scan_get_sched_scan_channels(struct wl1271 *wl,
int i, j; int i, j;
u32 flags; u32 flags;
bool force_passive = !req->n_ssids; bool force_passive = !req->n_ssids;
u32 min_dwell_time_active, max_dwell_time_active, delta_per_probe;
u32 dwell_time_passive, dwell_time_dfs;
if (band == IEEE80211_BAND_5GHZ)
delta_per_probe = c->dwell_time_delta_per_probe_5;
else
delta_per_probe = c->dwell_time_delta_per_probe;
min_dwell_time_active = c->base_dwell_time +
req->n_ssids * c->num_probe_reqs * delta_per_probe;
max_dwell_time_active = min_dwell_time_active + c->max_dwell_time_delta;
min_dwell_time_active = DIV_ROUND_UP(min_dwell_time_active, 1000);
max_dwell_time_active = DIV_ROUND_UP(max_dwell_time_active, 1000);
dwell_time_passive = DIV_ROUND_UP(c->dwell_time_passive, 1000);
dwell_time_dfs = DIV_ROUND_UP(c->dwell_time_dfs, 1000);
for (i = 0, j = start; for (i = 0, j = start;
i < req->n_channels && j < max_channels; i < req->n_channels && j < max_channels;
...@@ -440,21 +457,24 @@ wl1271_scan_get_sched_scan_channels(struct wl1271 *wl, ...@@ -440,21 +457,24 @@ wl1271_scan_get_sched_scan_channels(struct wl1271 *wl,
req->channels[i]->flags); req->channels[i]->flags);
wl1271_debug(DEBUG_SCAN, "max_power %d", wl1271_debug(DEBUG_SCAN, "max_power %d",
req->channels[i]->max_power); req->channels[i]->max_power);
wl1271_debug(DEBUG_SCAN, "min_dwell_time %d max dwell time %d",
min_dwell_time_active,
max_dwell_time_active);
if (flags & IEEE80211_CHAN_RADAR) { if (flags & IEEE80211_CHAN_RADAR) {
channels[j].flags |= SCAN_CHANNEL_FLAGS_DFS; channels[j].flags |= SCAN_CHANNEL_FLAGS_DFS;
channels[j].passive_duration = channels[j].passive_duration =
cpu_to_le16(c->dwell_time_dfs); cpu_to_le16(dwell_time_dfs);
} else { } else {
channels[j].passive_duration = channels[j].passive_duration =
cpu_to_le16(c->dwell_time_passive); cpu_to_le16(dwell_time_passive);
} }
channels[j].min_duration = channels[j].min_duration =
cpu_to_le16(c->min_dwell_time_active); cpu_to_le16(min_dwell_time_active);
channels[j].max_duration = channels[j].max_duration =
cpu_to_le16(c->max_dwell_time_active); cpu_to_le16(max_dwell_time_active);
channels[j].tx_power_att = req->channels[i]->max_power; channels[j].tx_power_att = req->channels[i]->max_power;
channels[j].channel = req->channels[i]->hw_value; channels[j].channel = req->channels[i]->hw_value;
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
#ifndef __SCAN_H__ #ifndef __SCAN_H__
#define __SCAN_H__ #define __SCAN_H__
#include "wl12xx.h" #include "wlcore.h"
int wl1271_scan(struct wl1271 *wl, struct ieee80211_vif *vif, int wl1271_scan(struct wl1271 *wl, struct ieee80211_vif *vif,
const u8 *ssid, size_t ssid_len, const u8 *ssid, size_t ssid_len,
...@@ -55,7 +55,7 @@ void wl1271_scan_sched_scan_results(struct wl1271 *wl); ...@@ -55,7 +55,7 @@ void wl1271_scan_sched_scan_results(struct wl1271 *wl);
#define WL1271_SCAN_BAND_2_4_GHZ 0 #define WL1271_SCAN_BAND_2_4_GHZ 0
#define WL1271_SCAN_BAND_5_GHZ 1 #define WL1271_SCAN_BAND_5_GHZ 1
#define WL1271_SCAN_TIMEOUT 10000 /* msec */ #define WL1271_SCAN_TIMEOUT 30000 /* msec */
enum { enum {
WL1271_SCAN_STATE_IDLE, WL1271_SCAN_STATE_IDLE,
......
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
#include <linux/wl12xx.h> #include <linux/wl12xx.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include "wl12xx.h" #include "wlcore.h"
#include "wl12xx_80211.h" #include "wl12xx_80211.h"
#include "io.h" #include "io.h"
...@@ -76,7 +76,7 @@ static void wl12xx_sdio_raw_read(struct device *child, int addr, void *buf, ...@@ -76,7 +76,7 @@ static void wl12xx_sdio_raw_read(struct device *child, int addr, void *buf,
sdio_claim_host(func); sdio_claim_host(func);
if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) { if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG)) {
((u8 *)buf)[0] = sdio_f0_readb(func, addr, &ret); ((u8 *)buf)[0] = sdio_f0_readb(func, addr, &ret);
dev_dbg(child->parent, "sdio read 52 addr 0x%x, byte 0x%02x\n", dev_dbg(child->parent, "sdio read 52 addr 0x%x, byte 0x%02x\n",
addr, ((u8 *)buf)[0]); addr, ((u8 *)buf)[0]);
...@@ -105,7 +105,7 @@ static void wl12xx_sdio_raw_write(struct device *child, int addr, void *buf, ...@@ -105,7 +105,7 @@ static void wl12xx_sdio_raw_write(struct device *child, int addr, void *buf,
sdio_claim_host(func); sdio_claim_host(func);
if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) { if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG)) {
sdio_f0_writeb(func, ((u8 *)buf)[0], addr, &ret); sdio_f0_writeb(func, ((u8 *)buf)[0], addr, &ret);
dev_dbg(child->parent, "sdio write 52 addr 0x%x, byte 0x%02x\n", dev_dbg(child->parent, "sdio write 52 addr 0x%x, byte 0x%02x\n",
addr, ((u8 *)buf)[0]); addr, ((u8 *)buf)[0]);
......
...@@ -30,12 +30,10 @@ ...@@ -30,12 +30,10 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/slab.h> #include <linux/slab.h>
#include "wl12xx.h" #include "wlcore.h"
#include "wl12xx_80211.h" #include "wl12xx_80211.h"
#include "io.h" #include "io.h"
#include "reg.h"
#define WSPI_CMD_READ 0x40000000 #define WSPI_CMD_READ 0x40000000
#define WSPI_CMD_WRITE 0x00000000 #define WSPI_CMD_WRITE 0x00000000
#define WSPI_CMD_FIXED 0x20000000 #define WSPI_CMD_FIXED 0x20000000
......
...@@ -25,10 +25,9 @@ ...@@ -25,10 +25,9 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <net/genetlink.h> #include <net/genetlink.h>
#include "wl12xx.h" #include "wlcore.h"
#include "debug.h" #include "debug.h"
#include "acx.h" #include "acx.h"
#include "reg.h"
#include "ps.h" #include "ps.h"
#include "io.h" #include "io.h"
......
...@@ -25,13 +25,19 @@ ...@@ -25,13 +25,19 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include "wl12xx.h" #include "wlcore.h"
#include "debug.h" #include "debug.h"
#include "io.h" #include "io.h"
#include "reg.h"
#include "ps.h" #include "ps.h"
#include "tx.h" #include "tx.h"
#include "event.h" #include "event.h"
#include "hw_ops.h"
/*
* TODO: this is here just for now, it must be removed when the data
* operations are in place.
*/
#include "../wl12xx/reg.h"
static int wl1271_set_default_wep_key(struct wl1271 *wl, static int wl1271_set_default_wep_key(struct wl1271 *wl,
struct wl12xx_vif *wlvif, u8 id) struct wl12xx_vif *wlvif, u8 id)
...@@ -56,8 +62,8 @@ static int wl1271_alloc_tx_id(struct wl1271 *wl, struct sk_buff *skb) ...@@ -56,8 +62,8 @@ static int wl1271_alloc_tx_id(struct wl1271 *wl, struct sk_buff *skb)
{ {
int id; int id;
id = find_first_zero_bit(wl->tx_frames_map, ACX_TX_DESCRIPTORS); id = find_first_zero_bit(wl->tx_frames_map, wl->num_tx_desc);
if (id >= ACX_TX_DESCRIPTORS) if (id >= wl->num_tx_desc)
return -EBUSY; return -EBUSY;
__set_bit(id, wl->tx_frames_map); __set_bit(id, wl->tx_frames_map);
...@@ -69,7 +75,7 @@ static int wl1271_alloc_tx_id(struct wl1271 *wl, struct sk_buff *skb) ...@@ -69,7 +75,7 @@ static int wl1271_alloc_tx_id(struct wl1271 *wl, struct sk_buff *skb)
static void wl1271_free_tx_id(struct wl1271 *wl, int id) static void wl1271_free_tx_id(struct wl1271 *wl, int id)
{ {
if (__test_and_clear_bit(id, wl->tx_frames_map)) { if (__test_and_clear_bit(id, wl->tx_frames_map)) {
if (unlikely(wl->tx_frames_cnt == ACX_TX_DESCRIPTORS)) if (unlikely(wl->tx_frames_cnt == wl->num_tx_desc))
clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
wl->tx_frames[id] = NULL; wl->tx_frames[id] = NULL;
...@@ -167,14 +173,15 @@ u8 wl12xx_tx_get_hlid(struct wl1271 *wl, struct wl12xx_vif *wlvif, ...@@ -167,14 +173,15 @@ u8 wl12xx_tx_get_hlid(struct wl1271 *wl, struct wl12xx_vif *wlvif,
return wlvif->dev_hlid; return wlvif->dev_hlid;
} }
static unsigned int wl12xx_calc_packet_alignment(struct wl1271 *wl, unsigned int wlcore_calc_packet_alignment(struct wl1271 *wl,
unsigned int packet_length) unsigned int packet_length)
{ {
if (wl->quirks & WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT) if (wl->quirks & WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN)
return ALIGN(packet_length, WL1271_TX_ALIGN_TO);
else
return ALIGN(packet_length, WL12XX_BUS_BLOCK_SIZE); return ALIGN(packet_length, WL12XX_BUS_BLOCK_SIZE);
else
return ALIGN(packet_length, WL1271_TX_ALIGN_TO);
} }
EXPORT_SYMBOL(wlcore_calc_packet_alignment);
static int wl1271_tx_allocate(struct wl1271 *wl, struct wl12xx_vif *wlvif, static int wl1271_tx_allocate(struct wl1271 *wl, struct wl12xx_vif *wlvif,
struct sk_buff *skb, u32 extra, u32 buf_offset, struct sk_buff *skb, u32 extra, u32 buf_offset,
...@@ -182,10 +189,9 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct wl12xx_vif *wlvif, ...@@ -182,10 +189,9 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct wl12xx_vif *wlvif,
{ {
struct wl1271_tx_hw_descr *desc; struct wl1271_tx_hw_descr *desc;
u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra; u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra;
u32 len;
u32 total_blocks; u32 total_blocks;
int id, ret = -EBUSY, ac; int id, ret = -EBUSY, ac;
u32 spare_blocks = wl->tx_spare_blocks; u32 spare_blocks = wl->normal_tx_spare;
bool is_dummy = false; bool is_dummy = false;
if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE) if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE)
...@@ -196,30 +202,19 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct wl12xx_vif *wlvif, ...@@ -196,30 +202,19 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct wl12xx_vif *wlvif,
if (id < 0) if (id < 0)
return id; return id;
/* approximate the number of blocks required for this packet if (unlikely(wl12xx_is_dummy_packet(wl, skb)))
in the firmware */
len = wl12xx_calc_packet_alignment(wl, total_len);
/* in case of a dummy packet, use default amount of spare mem blocks */
if (unlikely(wl12xx_is_dummy_packet(wl, skb))) {
is_dummy = true; is_dummy = true;
spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT; else if (wlvif->is_gem)
} spare_blocks = wl->gem_tx_spare;
total_blocks = (len + TX_HW_BLOCK_SIZE - 1) / TX_HW_BLOCK_SIZE + total_blocks = wlcore_hw_calc_tx_blocks(wl, total_len, spare_blocks);
spare_blocks;
if (total_blocks <= wl->tx_blocks_available) { if (total_blocks <= wl->tx_blocks_available) {
desc = (struct wl1271_tx_hw_descr *)skb_push( desc = (struct wl1271_tx_hw_descr *)skb_push(
skb, total_len - skb->len); skb, total_len - skb->len);
/* HW descriptor fields change between wl127x and wl128x */ wlcore_hw_set_tx_desc_blocks(wl, desc, total_blocks,
if (wl->chip.id == CHIP_ID_1283_PG20) { spare_blocks);
desc->wl128x_mem.total_mem_blocks = total_blocks;
} else {
desc->wl127x_mem.extra_blocks = spare_blocks;
desc->wl127x_mem.total_mem_blocks = total_blocks;
}
desc->id = id; desc->id = id;
...@@ -256,7 +251,7 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif, ...@@ -256,7 +251,7 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif,
{ {
struct timespec ts; struct timespec ts;
struct wl1271_tx_hw_descr *desc; struct wl1271_tx_hw_descr *desc;
int aligned_len, ac, rate_idx; int ac, rate_idx;
s64 hosttime; s64 hosttime;
u16 tx_attr = 0; u16 tx_attr = 0;
__le16 frame_control; __le16 frame_control;
...@@ -329,44 +324,16 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif, ...@@ -329,44 +324,16 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif,
} }
tx_attr |= rate_idx << TX_HW_ATTR_OFST_RATE_POLICY; tx_attr |= rate_idx << TX_HW_ATTR_OFST_RATE_POLICY;
desc->reserved = 0;
aligned_len = wl12xx_calc_packet_alignment(wl, skb->len);
if (wl->chip.id == CHIP_ID_1283_PG20) {
desc->wl128x_mem.extra_bytes = aligned_len - skb->len;
desc->length = cpu_to_le16(aligned_len >> 2);
wl1271_debug(DEBUG_TX, "tx_fill_hdr: hlid: %d "
"tx_attr: 0x%x len: %d life: %d mem: %d",
desc->hlid, tx_attr,
le16_to_cpu(desc->length),
le16_to_cpu(desc->life_time),
desc->wl128x_mem.total_mem_blocks);
} else {
int pad;
/* Store the aligned length in terms of words */
desc->length = cpu_to_le16(aligned_len >> 2);
/* calculate number of padding bytes */
pad = aligned_len - skb->len;
tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD;
wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d hlid: %d "
"tx_attr: 0x%x len: %d life: %d mem: %d", pad,
desc->hlid, tx_attr,
le16_to_cpu(desc->length),
le16_to_cpu(desc->life_time),
desc->wl127x_mem.total_mem_blocks);
}
/* for WEP shared auth - no fw encryption is needed */ /* for WEP shared auth - no fw encryption is needed */
if (ieee80211_is_auth(frame_control) && if (ieee80211_is_auth(frame_control) &&
ieee80211_has_protected(frame_control)) ieee80211_has_protected(frame_control))
tx_attr |= TX_HW_ATTR_HOST_ENCRYPT; tx_attr |= TX_HW_ATTR_HOST_ENCRYPT;
desc->reserved = 0;
desc->tx_attr = cpu_to_le16(tx_attr); desc->tx_attr = cpu_to_le16(tx_attr);
wlcore_hw_set_tx_desc_data_len(wl, desc, skb);
} }
/* caller must hold wl->mutex */ /* caller must hold wl->mutex */
...@@ -432,7 +399,7 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif, ...@@ -432,7 +399,7 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif,
* In special cases, we want to align to a specific block size * In special cases, we want to align to a specific block size
* (eg. for wl128x with SDIO we align to 256). * (eg. for wl128x with SDIO we align to 256).
*/ */
total_len = wl12xx_calc_packet_alignment(wl, skb->len); total_len = wlcore_calc_packet_alignment(wl, skb->len);
memcpy(wl->aggr_buf + buf_offset, skb->data, skb->len); memcpy(wl->aggr_buf + buf_offset, skb->data, skb->len);
memset(wl->aggr_buf + buf_offset + skb->len, 0, total_len - skb->len); memset(wl->aggr_buf + buf_offset + skb->len, 0, total_len - skb->len);
...@@ -718,7 +685,7 @@ void wl1271_tx_work_locked(struct wl1271 *wl) ...@@ -718,7 +685,7 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
* Flush buffer and try again. * Flush buffer and try again.
*/ */
wl1271_skb_queue_head(wl, wlvif, skb); wl1271_skb_queue_head(wl, wlvif, skb);
wl1271_write(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf, wlcore_write_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf,
buf_offset, true); buf_offset, true);
sent_packets = true; sent_packets = true;
buf_offset = 0; buf_offset = 0;
...@@ -753,7 +720,7 @@ void wl1271_tx_work_locked(struct wl1271 *wl) ...@@ -753,7 +720,7 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
out_ack: out_ack:
if (buf_offset) { if (buf_offset) {
wl1271_write(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf, wlcore_write_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf,
buf_offset, true); buf_offset, true);
sent_packets = true; sent_packets = true;
} }
...@@ -762,8 +729,8 @@ void wl1271_tx_work_locked(struct wl1271 *wl) ...@@ -762,8 +729,8 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
* Interrupt the firmware with the new packets. This is only * Interrupt the firmware with the new packets. This is only
* required for older hardware revisions * required for older hardware revisions
*/ */
if (wl->quirks & WL12XX_QUIRK_END_OF_TRANSACTION) if (wl->quirks & WLCORE_QUIRK_END_OF_TRANSACTION)
wl1271_write32(wl, WL1271_HOST_WR_ACCESS, wl1271_write32(wl, WL12XX_HOST_WR_ACCESS,
wl->tx_packets_count); wl->tx_packets_count);
wl1271_handle_tx_low_watermark(wl); wl1271_handle_tx_low_watermark(wl);
...@@ -792,11 +759,20 @@ static u8 wl1271_tx_get_rate_flags(u8 rate_class_index) ...@@ -792,11 +759,20 @@ static u8 wl1271_tx_get_rate_flags(u8 rate_class_index)
{ {
u8 flags = 0; u8 flags = 0;
if (rate_class_index >= CONF_HW_RXTX_RATE_MCS_MIN && /*
rate_class_index <= CONF_HW_RXTX_RATE_MCS_MAX) * TODO: use wl12xx constants when this code is moved to wl12xx, as
* only it uses Tx-completion.
*/
if (rate_class_index <= 8)
flags |= IEEE80211_TX_RC_MCS; flags |= IEEE80211_TX_RC_MCS;
if (rate_class_index == CONF_HW_RXTX_RATE_MCS7_SGI)
/*
* TODO: use wl12xx constants when this code is moved to wl12xx, as
* only it uses Tx-completion.
*/
if (rate_class_index == 0)
flags |= IEEE80211_TX_RC_SHORT_GI; flags |= IEEE80211_TX_RC_SHORT_GI;
return flags; return flags;
} }
...@@ -813,7 +789,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl, ...@@ -813,7 +789,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
u8 retries = 0; u8 retries = 0;
/* check for id legality */ /* check for id legality */
if (unlikely(id >= ACX_TX_DESCRIPTORS || wl->tx_frames[id] == NULL)) { if (unlikely(id >= wl->num_tx_desc || wl->tx_frames[id] == NULL)) {
wl1271_warning("TX result illegal id: %d", id); wl1271_warning("TX result illegal id: %d", id);
return; return;
} }
...@@ -834,7 +810,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl, ...@@ -834,7 +810,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
if (result->status == TX_SUCCESS) { if (result->status == TX_SUCCESS) {
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
info->flags |= IEEE80211_TX_STAT_ACK; info->flags |= IEEE80211_TX_STAT_ACK;
rate = wl1271_rate_to_idx(result->rate_class_index, rate = wlcore_rate_to_idx(wl, result->rate_class_index,
wlvif->band); wlvif->band);
rate_flags = wl1271_tx_get_rate_flags(result->rate_class_index); rate_flags = wl1271_tx_get_rate_flags(result->rate_class_index);
retries = result->ack_failures; retries = result->ack_failures;
...@@ -929,6 +905,7 @@ void wl1271_tx_complete(struct wl1271 *wl) ...@@ -929,6 +905,7 @@ void wl1271_tx_complete(struct wl1271 *wl)
wl->tx_results_count++; wl->tx_results_count++;
} }
} }
EXPORT_SYMBOL(wl1271_tx_complete);
void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid) void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid)
{ {
...@@ -1006,7 +983,7 @@ void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues) ...@@ -1006,7 +983,7 @@ void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
if (reset_tx_queues) if (reset_tx_queues)
wl1271_handle_tx_low_watermark(wl); wl1271_handle_tx_low_watermark(wl);
for (i = 0; i < ACX_TX_DESCRIPTORS; i++) { for (i = 0; i < wl->num_tx_desc; i++) {
if (wl->tx_frames[i] == NULL) if (wl->tx_frames[i] == NULL)
continue; continue;
......
...@@ -25,9 +25,6 @@ ...@@ -25,9 +25,6 @@
#ifndef __TX_H__ #ifndef __TX_H__
#define __TX_H__ #define __TX_H__
#define TX_HW_BLOCK_SPARE_DEFAULT 1
#define TX_HW_BLOCK_SIZE 252
#define TX_HW_MGMT_PKT_LIFETIME_TU 2000 #define TX_HW_MGMT_PKT_LIFETIME_TU 2000
#define TX_HW_AP_MODE_PKT_LIFETIME_TU 8000 #define TX_HW_AP_MODE_PKT_LIFETIME_TU 8000
...@@ -212,7 +209,7 @@ void wl1271_tx_complete(struct wl1271 *wl); ...@@ -212,7 +209,7 @@ void wl1271_tx_complete(struct wl1271 *wl);
void wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif); void wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif);
void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues); void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues);
void wl1271_tx_flush(struct wl1271 *wl); void wl1271_tx_flush(struct wl1271 *wl);
u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band); u8 wlcore_rate_to_idx(struct wl1271 *wl, u8 rate, enum ieee80211_band band);
u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set, u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set,
enum ieee80211_band rate_band); enum ieee80211_band rate_band);
u32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set); u32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set);
...@@ -224,6 +221,8 @@ void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid); ...@@ -224,6 +221,8 @@ void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid);
void wl1271_handle_tx_low_watermark(struct wl1271 *wl); void wl1271_handle_tx_low_watermark(struct wl1271 *wl);
bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb); bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb);
void wl12xx_rearm_rx_streaming(struct wl1271 *wl, unsigned long *active_hlids); void wl12xx_rearm_rx_streaming(struct wl1271 *wl, unsigned long *active_hlids);
unsigned int wlcore_calc_packet_alignment(struct wl1271 *wl,
unsigned int packet_length);
/* from main.c */ /* from main.c */
void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid); void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid);
......
...@@ -89,8 +89,6 @@ ...@@ -89,8 +89,6 @@
#define WL1271_AP_BSS_INDEX 0 #define WL1271_AP_BSS_INDEX 0
#define WL1271_AP_DEF_BEACON_EXP 20 #define WL1271_AP_DEF_BEACON_EXP 20
#define ACX_TX_DESCRIPTORS 16
#define WL1271_AGGR_BUFFER_SIZE (4 * PAGE_SIZE) #define WL1271_AGGR_BUFFER_SIZE (4 * PAGE_SIZE)
enum wl1271_state { enum wl1271_state {
...@@ -105,26 +103,6 @@ enum wl12xx_fw_type { ...@@ -105,26 +103,6 @@ enum wl12xx_fw_type {
WL12XX_FW_TYPE_PLT, WL12XX_FW_TYPE_PLT,
}; };
enum wl1271_partition_type {
PART_DOWN,
PART_WORK,
PART_DRPW,
PART_TABLE_LEN
};
struct wl1271_partition {
u32 size;
u32 start;
};
struct wl1271_partition_set {
struct wl1271_partition mem;
struct wl1271_partition reg;
struct wl1271_partition mem2;
struct wl1271_partition mem3;
};
struct wl1271; struct wl1271;
enum { enum {
...@@ -167,8 +145,21 @@ struct wl1271_stats { ...@@ -167,8 +145,21 @@ struct wl1271_stats {
#define AP_MAX_STATIONS 8 #define AP_MAX_STATIONS 8
struct wl_fw_packet_counters {
/* Cumulative counter of released packets per AC */
u8 tx_released_pkts[NUM_TX_QUEUES];
/* Cumulative counter of freed packets per HLID */
u8 tx_lnk_free_pkts[WL12XX_MAX_LINKS];
/* Cumulative counter of released Voice memory blocks */
u8 tx_voice_released_blks;
u8 padding[3];
} __packed;
/* FW status registers */ /* FW status registers */
struct wl12xx_fw_status { struct wl_fw_status {
__le32 intr; __le32 intr;
u8 fw_rx_counter; u8 fw_rx_counter;
u8 drv_rx_counter; u8 drv_rx_counter;
...@@ -195,16 +186,12 @@ struct wl12xx_fw_status { ...@@ -195,16 +186,12 @@ struct wl12xx_fw_status {
/* Size (in Memory Blocks) of TX pool */ /* Size (in Memory Blocks) of TX pool */
__le32 tx_total; __le32 tx_total;
/* Cumulative counter of released packets per AC */ struct wl_fw_packet_counters counters;
u8 tx_released_pkts[NUM_TX_QUEUES];
/* Cumulative counter of freed packets per HLID */
u8 tx_lnk_free_pkts[WL12XX_MAX_LINKS];
/* Cumulative counter of released Voice memory blocks */
u8 tx_voice_released_blks;
u8 padding_1[3];
__le32 log_start_addr; __le32 log_start_addr;
/* Private status to be used by the lower drivers */
u8 priv[0];
} __packed; } __packed;
struct wl1271_rx_mem_pool_addr { struct wl1271_rx_mem_pool_addr {
...@@ -292,214 +279,6 @@ struct wl1271_link { ...@@ -292,214 +279,6 @@ struct wl1271_link {
u8 ba_bitmap; u8 ba_bitmap;
}; };
struct wl1271 {
struct ieee80211_hw *hw;
bool mac80211_registered;
struct device *dev;
void *if_priv;
struct wl1271_if_operations *if_ops;
void (*set_power)(bool enable);
int irq;
int ref_clock;
spinlock_t wl_lock;
enum wl1271_state state;
enum wl12xx_fw_type fw_type;
bool plt;
u8 last_vif_count;
struct mutex mutex;
unsigned long flags;
struct wl1271_partition_set part;
struct wl1271_chip chip;
int cmd_box_addr;
int event_box_addr;
u8 *fw;
size_t fw_len;
void *nvs;
size_t nvs_len;
s8 hw_pg_ver;
/* 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;
unsigned long links_map[BITS_TO_LONGS(WL12XX_MAX_LINKS)];
unsigned long roles_map[BITS_TO_LONGS(WL12XX_MAX_ROLES)];
unsigned long roc_map[BITS_TO_LONGS(WL12XX_MAX_ROLES)];
unsigned long rate_policies_map[
BITS_TO_LONGS(WL12XX_MAX_RATE_POLICIES)];
struct list_head wlvif_list;
u8 sta_count;
u8 ap_count;
struct wl1271_acx_mem_map *target_mem_map;
/* Accounting for allocated / available TX blocks on HW */
u32 tx_blocks_freed;
u32 tx_blocks_available;
u32 tx_allocated_blocks;
u32 tx_results_count;
/* amount of spare TX blocks to use */
u32 tx_spare_blocks;
/* Accounting for allocated / available Tx packets in HW */
u32 tx_pkts_freed[NUM_TX_QUEUES];
u32 tx_allocated_pkts[NUM_TX_QUEUES];
/* Transmitted TX packets counter for chipset interface */
u32 tx_packets_count;
/* Time-offset between host and chipset clocks */
s64 time_offset;
/* Frames scheduled for transmission, not handled yet */
int tx_queue_count[NUM_TX_QUEUES];
long stopped_queues_map;
/* Frames received, not handled yet by mac80211 */
struct sk_buff_head deferred_rx_queue;
/* Frames sent, not returned yet to mac80211 */
struct sk_buff_head deferred_tx_queue;
struct work_struct tx_work;
struct workqueue_struct *freezable_wq;
/* Pending TX frames */
unsigned long tx_frames_map[BITS_TO_LONGS(ACX_TX_DESCRIPTORS)];
struct sk_buff *tx_frames[ACX_TX_DESCRIPTORS];
int tx_frames_cnt;
/* FW Rx counter */
u32 rx_counter;
/* Rx memory pool address */
struct wl1271_rx_mem_pool_addr rx_mem_pool_addr;
/* Intermediate buffer, used for packet aggregation */
u8 *aggr_buf;
/* Reusable dummy packet template */
struct sk_buff *dummy_packet;
/* Network stack work */
struct work_struct netstack_work;
/* FW log buffer */
u8 *fwlog;
/* Number of valid bytes in the FW log buffer */
ssize_t fwlog_size;
/* Sysfs FW log entry readers wait queue */
wait_queue_head_t fwlog_waitq;
/* Hardware recovery work */
struct work_struct recovery_work;
/* The mbox event mask */
u32 event_mask;
/* Mailbox pointers */
u32 mbox_ptr[2];
/* Are we currently scanning */
struct ieee80211_vif *scan_vif;
struct wl1271_scan scan;
struct delayed_work scan_complete_work;
bool sched_scanning;
/* The current band */
enum ieee80211_band band;
struct completion *elp_compl;
struct delayed_work elp_work;
/* in dBm */
int power_level;
struct wl1271_stats stats;
__le32 buffer_32;
u32 buffer_cmd;
u32 buffer_busyword[WL1271_BUSY_WORD_CNT];
struct wl12xx_fw_status *fw_status;
struct wl1271_tx_hw_res_if *tx_res_if;
/* Current chipset configuration */
struct conf_drv_settings conf;
bool sg_enabled;
bool enable_11a;
/* Most recently reported noise in dBm */
s8 noise;
/* bands supported by this instance of wl12xx */
struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS];
int tcxo_clock;
/*
* wowlan trigger was configured during suspend.
* (currently, only "ANY" trigger is supported)
*/
bool wow_enabled;
bool irq_wake_enabled;
/*
* AP-mode - links indexed by HLID. The global and broadcast links
* are always active.
*/
struct wl1271_link links[WL12XX_MAX_LINKS];
/* AP-mode - a bitmap of links currently in PS mode according to FW */
u32 ap_fw_ps_map;
/* AP-mode - a bitmap of links currently in PS mode in mac80211 */
unsigned long ap_ps_map;
/* Quirks of specific hardware revisions */
unsigned int quirks;
/* Platform limitations */
unsigned int platform_quirks;
/* number of currently active RX BA sessions */
int ba_rx_session_count;
/* AP-mode - number of currently connected stations */
int active_sta_count;
/* last wlvif we transmitted from */
struct wl12xx_vif *last_wlvif;
/* work to fire when Tx is stuck */
struct delayed_work tx_watchdog_work;
};
struct wl1271_station { struct wl1271_station {
u8 hlid; u8 hlid;
}; };
...@@ -605,6 +384,9 @@ struct wl12xx_vif { ...@@ -605,6 +384,9 @@ struct wl12xx_vif {
struct work_struct rx_streaming_disable_work; struct work_struct rx_streaming_disable_work;
struct timer_list rx_streaming_timer; struct timer_list rx_streaming_timer;
/* does the current role use GEM for encryption (AP or STA) */
bool is_gem;
/* /*
* This struct must be last! * This struct must be last!
* data that has to be saved acrossed reconfigs (e.g. recovery) * data that has to be saved acrossed reconfigs (e.g. recovery)
...@@ -679,17 +461,6 @@ size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen); ...@@ -679,17 +461,6 @@ size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen);
#define HW_BG_RATES_MASK 0xffff #define HW_BG_RATES_MASK 0xffff
#define HW_HT_RATES_OFFSET 16 #define HW_HT_RATES_OFFSET 16
/* Quirks */
/* Each RX/TX transaction requires an end-of-transaction transfer */
#define WL12XX_QUIRK_END_OF_TRANSACTION BIT(0)
/* wl127x and SPI don't support SDIO block size alignment */
#define WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT BIT(2)
/* Older firmwares did not implement the FW logger over bus feature */
#define WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED BIT(4)
#define WL12XX_HW_BLOCK_SIZE 256 #define WL12XX_HW_BLOCK_SIZE 256
#endif #endif
/*
* This file is part of wlcore
*
* Copyright (C) 2011 Texas Instruments Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#ifndef __WLCORE_H__
#define __WLCORE_H__
#include <linux/platform_device.h>
#include "wl12xx.h"
#include "event.h"
/* The maximum number of Tx descriptors in all chip families */
#define WLCORE_MAX_TX_DESCRIPTORS 32
/* forward declaration */
struct wl1271_tx_hw_descr;
enum wl_rx_buf_align;
struct wlcore_ops {
int (*identify_chip)(struct wl1271 *wl);
int (*identify_fw)(struct wl1271 *wl);
int (*boot)(struct wl1271 *wl);
void (*trigger_cmd)(struct wl1271 *wl, int cmd_box_addr,
void *buf, size_t len);
void (*ack_event)(struct wl1271 *wl);
u32 (*calc_tx_blocks)(struct wl1271 *wl, u32 len, u32 spare_blks);
void (*set_tx_desc_blocks)(struct wl1271 *wl,
struct wl1271_tx_hw_descr *desc,
u32 blks, u32 spare_blks);
void (*set_tx_desc_data_len)(struct wl1271 *wl,
struct wl1271_tx_hw_descr *desc,
struct sk_buff *skb);
enum wl_rx_buf_align (*get_rx_buf_align)(struct wl1271 *wl,
u32 rx_desc);
void (*prepare_read)(struct wl1271 *wl, u32 rx_desc, u32 len);
u32 (*get_rx_packet_len)(struct wl1271 *wl, void *rx_data,
u32 data_len);
void (*tx_delayed_compl)(struct wl1271 *wl);
void (*tx_immediate_compl)(struct wl1271 *wl);
int (*hw_init)(struct wl1271 *wl);
int (*init_vif)(struct wl1271 *wl, struct wl12xx_vif *wlvif);
u32 (*sta_get_ap_rate_mask)(struct wl1271 *wl,
struct wl12xx_vif *wlvif);
s8 (*get_pg_ver)(struct wl1271 *wl);
void (*get_mac)(struct wl1271 *wl);
};
enum wlcore_partitions {
PART_DOWN,
PART_WORK,
PART_BOOT,
PART_DRPW,
PART_TOP_PRCM_ELP_SOC,
PART_PHY_INIT,
PART_TABLE_LEN,
};
struct wlcore_partition {
u32 size;
u32 start;
};
struct wlcore_partition_set {
struct wlcore_partition mem;
struct wlcore_partition reg;
struct wlcore_partition mem2;
struct wlcore_partition mem3;
};
enum wlcore_registers {
/* register addresses, used with partition translation */
REG_ECPU_CONTROL,
REG_INTERRUPT_NO_CLEAR,
REG_INTERRUPT_ACK,
REG_COMMAND_MAILBOX_PTR,
REG_EVENT_MAILBOX_PTR,
REG_INTERRUPT_TRIG,
REG_INTERRUPT_MASK,
REG_PC_ON_RECOVERY,
REG_CHIP_ID_B,
REG_CMD_MBOX_ADDRESS,
/* data access memory addresses, used with partition translation */
REG_SLV_MEM_DATA,
REG_SLV_REG_DATA,
/* raw data access memory addresses */
REG_RAW_FW_STATUS_ADDR,
REG_TABLE_LEN,
};
struct wl1271 {
struct ieee80211_hw *hw;
bool mac80211_registered;
struct device *dev;
void *if_priv;
struct wl1271_if_operations *if_ops;
void (*set_power)(bool enable);
int irq;
int ref_clock;
spinlock_t wl_lock;
enum wl1271_state state;
enum wl12xx_fw_type fw_type;
bool plt;
u8 last_vif_count;
struct mutex mutex;
unsigned long flags;
struct wlcore_partition_set curr_part;
struct wl1271_chip chip;
int cmd_box_addr;
u8 *fw;
size_t fw_len;
void *nvs;
size_t nvs_len;
s8 hw_pg_ver;
/* 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;
unsigned long links_map[BITS_TO_LONGS(WL12XX_MAX_LINKS)];
unsigned long roles_map[BITS_TO_LONGS(WL12XX_MAX_ROLES)];
unsigned long roc_map[BITS_TO_LONGS(WL12XX_MAX_ROLES)];
unsigned long rate_policies_map[
BITS_TO_LONGS(WL12XX_MAX_RATE_POLICIES)];
struct list_head wlvif_list;
u8 sta_count;
u8 ap_count;
struct wl1271_acx_mem_map *target_mem_map;
/* Accounting for allocated / available TX blocks on HW */
u32 tx_blocks_freed;
u32 tx_blocks_available;
u32 tx_allocated_blocks;
u32 tx_results_count;
/* Accounting for allocated / available Tx packets in HW */
u32 tx_pkts_freed[NUM_TX_QUEUES];
u32 tx_allocated_pkts[NUM_TX_QUEUES];
/* Transmitted TX packets counter for chipset interface */
u32 tx_packets_count;
/* Time-offset between host and chipset clocks */
s64 time_offset;
/* Frames scheduled for transmission, not handled yet */
int tx_queue_count[NUM_TX_QUEUES];
long stopped_queues_map;
/* Frames received, not handled yet by mac80211 */
struct sk_buff_head deferred_rx_queue;
/* Frames sent, not returned yet to mac80211 */
struct sk_buff_head deferred_tx_queue;
struct work_struct tx_work;
struct workqueue_struct *freezable_wq;
/* Pending TX frames */
unsigned long tx_frames_map[BITS_TO_LONGS(WLCORE_MAX_TX_DESCRIPTORS)];
struct sk_buff *tx_frames[WLCORE_MAX_TX_DESCRIPTORS];
int tx_frames_cnt;
/* FW Rx counter */
u32 rx_counter;
/* Rx memory pool address */
struct wl1271_rx_mem_pool_addr rx_mem_pool_addr;
/* Intermediate buffer, used for packet aggregation */
u8 *aggr_buf;
/* Reusable dummy packet template */
struct sk_buff *dummy_packet;
/* Network stack work */
struct work_struct netstack_work;
/* FW log buffer */
u8 *fwlog;
/* Number of valid bytes in the FW log buffer */
ssize_t fwlog_size;
/* Sysfs FW log entry readers wait queue */
wait_queue_head_t fwlog_waitq;
/* Hardware recovery work */
struct work_struct recovery_work;
/* Pointer that holds DMA-friendly block for the mailbox */
struct event_mailbox *mbox;
/* The mbox event mask */
u32 event_mask;
/* Mailbox pointers */
u32 mbox_ptr[2];
/* Are we currently scanning */
struct ieee80211_vif *scan_vif;
struct wl1271_scan scan;
struct delayed_work scan_complete_work;
bool sched_scanning;
/* The current band */
enum ieee80211_band band;
struct completion *elp_compl;
struct delayed_work elp_work;
/* in dBm */
int power_level;
struct wl1271_stats stats;
__le32 buffer_32;
u32 buffer_cmd;
u32 buffer_busyword[WL1271_BUSY_WORD_CNT];
struct wl_fw_status *fw_status;
struct wl1271_tx_hw_res_if *tx_res_if;
/* Current chipset configuration */
struct wlcore_conf conf;
bool sg_enabled;
bool enable_11a;
/* Most recently reported noise in dBm */
s8 noise;
/* bands supported by this instance of wl12xx */
struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS];
int tcxo_clock;
/*
* wowlan trigger was configured during suspend.
* (currently, only "ANY" trigger is supported)
*/
bool wow_enabled;
bool irq_wake_enabled;
/*
* AP-mode - links indexed by HLID. The global and broadcast links
* are always active.
*/
struct wl1271_link links[WL12XX_MAX_LINKS];
/* AP-mode - a bitmap of links currently in PS mode according to FW */
u32 ap_fw_ps_map;
/* AP-mode - a bitmap of links currently in PS mode in mac80211 */
unsigned long ap_ps_map;
/* Quirks of specific hardware revisions */
unsigned int quirks;
/* Platform limitations */
unsigned int platform_quirks;
/* number of currently active RX BA sessions */
int ba_rx_session_count;
/* AP-mode - number of currently connected stations */
int active_sta_count;
/* last wlvif we transmitted from */
struct wl12xx_vif *last_wlvif;
/* work to fire when Tx is stuck */
struct delayed_work tx_watchdog_work;
struct wlcore_ops *ops;
/* pointer to the lower driver partition table */
const struct wlcore_partition_set *ptable;
/* pointer to the lower driver register table */
const int *rtable;
/* name of the firmwares to load - for PLT, single role, multi-role */
const char *plt_fw_name;
const char *sr_fw_name;
const char *mr_fw_name;
/* per-chip-family private structure */
void *priv;
/* number of TX descriptors the HW supports. */
u32 num_tx_desc;
/* spare Tx blocks for normal/GEM operating modes */
u32 normal_tx_spare;
u32 gem_tx_spare;
/* translate HW Tx rates to standard rate-indices */
const u8 **band_rate_to_idx;
/* size of table for HW rates that can be received from chip */
u8 hw_tx_rate_tbl_size;
/* this HW rate and below are considered HT rates for this chip */
u8 hw_min_ht_rate;
/* HW HT (11n) capabilities */
struct ieee80211_sta_ht_cap ht_cap;
/* size of the private FW status data */
size_t fw_status_priv_len;
};
int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev);
int __devexit wlcore_remove(struct platform_device *pdev);
struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size);
int wlcore_free_hw(struct wl1271 *wl);
/* Firmware image load chunk size */
#define CHUNK_SIZE 16384
/* Quirks */
/* Each RX/TX transaction requires an end-of-transaction transfer */
#define WLCORE_QUIRK_END_OF_TRANSACTION BIT(0)
/* wl127x and SPI don't support SDIO block size alignment */
#define WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN BIT(2)
/* means aggregated Rx packets are aligned to a SDIO block */
#define WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN BIT(3)
/* Older firmwares did not implement the FW logger over bus feature */
#define WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED BIT(4)
/* Older firmwares use an old NVS format */
#define WLCORE_QUIRK_LEGACY_NVS BIT(5)
/* Some firmwares may not support ELP */
#define WLCORE_QUIRK_NO_ELP BIT(6)
/* TODO: move to the lower drivers when all usages are abstracted */
#define CHIP_ID_1271_PG10 (0x4030101)
#define CHIP_ID_1271_PG20 (0x4030111)
#define CHIP_ID_1283_PG10 (0x05030101)
#define CHIP_ID_1283_PG20 (0x05030111)
/* TODO: move all these common registers and values elsewhere */
#define HW_ACCESS_ELP_CTRL_REG 0x1FFFC
/* ELP register commands */
#define ELPCTRL_WAKE_UP 0x1
#define ELPCTRL_WAKE_UP_WLAN_READY 0x5
#define ELPCTRL_SLEEP 0x0
/* ELP WLAN_READY bit */
#define ELPCTRL_WLAN_READY 0x2
/*************************************************************************
Interrupt Trigger Register (Host -> WiLink)
**************************************************************************/
/* Hardware to Embedded CPU Interrupts - first 32-bit register set */
/*
* The host sets this bit to inform the Wlan
* FW that a TX packet is in the XFER
* Buffer #0.
*/
#define INTR_TRIG_TX_PROC0 BIT(2)
/*
* The host sets this bit to inform the FW
* that it read a packet from RX XFER
* Buffer #0.
*/
#define INTR_TRIG_RX_PROC0 BIT(3)
#define INTR_TRIG_DEBUG_ACK BIT(4)
#define INTR_TRIG_STATE_CHANGED BIT(5)
/* Hardware to Embedded CPU Interrupts - second 32-bit register set */
/*
* The host sets this bit to inform the FW
* that it read a packet from RX XFER
* Buffer #1.
*/
#define INTR_TRIG_RX_PROC1 BIT(17)
/*
* The host sets this bit to inform the Wlan
* hardware that a TX packet is in the XFER
* Buffer #1.
*/
#define INTR_TRIG_TX_PROC1 BIT(18)
#define ACX_SLV_SOFT_RESET_BIT BIT(1)
#define SOFT_RESET_MAX_TIME 1000000
#define SOFT_RESET_STALL_TIME 1000
#define ECPU_CONTROL_HALT 0x00000101
#define WELP_ARM_COMMAND_VAL 0x4
#endif /* __WLCORE_H__ */
menuconfig WL12XX_MENU
tristate "TI wl12xx driver support"
depends on MAC80211 && EXPERIMENTAL
---help---
This will enable TI wl12xx driver support for the following chips:
wl1271, wl1273, wl1281 and wl1283.
The drivers make use of the mac80211 stack.
config WL12XX
tristate "TI wl12xx support"
depends on WL12XX_MENU && GENERIC_HARDIRQS
depends on INET
select FW_LOADER
---help---
This module adds support for wireless adapters based on TI wl1271 and
TI wl1273 chipsets. This module does *not* include support for wl1251.
For wl1251 support, use the separate homonymous driver instead.
If you choose to build a module, it will be called wl12xx. Say N if
unsure.
config WL12XX_SPI
tristate "TI wl12xx SPI support"
depends on WL12XX && SPI_MASTER
select CRC7
---help---
This module adds support for the SPI interface of adapters using
TI wl12xx chipsets. Select this if your platform is using
the SPI bus.
If you choose to build a module, it'll be called wl12xx_spi.
Say N if unsure.
config WL12XX_SDIO
tristate "TI wl12xx SDIO support"
depends on WL12XX && MMC
---help---
This module adds support for the SDIO interface of adapters using
TI wl12xx chipsets. Select this if your platform is using
the SDIO bus.
If you choose to build a module, it'll be called wl12xx_sdio.
Say N if unsure.
config WL12XX_PLATFORM_DATA
bool
depends on WL12XX_SDIO != n || WL1251_SDIO != n
default y
/*
* This file is part of wl1271
*
* Copyright (C) 2008-2009 Nokia Corporation
*
* Contact: Luciano Coelho <luciano.coelho@nokia.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#ifndef __BOOT_H__
#define __BOOT_H__
#include "wl12xx.h"
int wl1271_boot(struct wl1271 *wl);
int wl1271_load_firmware(struct wl1271 *wl);
#define WL1271_NO_SUBBANDS 8
#define WL1271_NO_POWER_LEVELS 4
#define WL1271_FW_VERSION_MAX_LEN 20
struct wl1271_static_data {
u8 mac_address[ETH_ALEN];
u8 padding[2];
u8 fw_version[WL1271_FW_VERSION_MAX_LEN];
u32 hw_version;
u8 tx_power_table[WL1271_NO_SUBBANDS][WL1271_NO_POWER_LEVELS];
};
/* number of times we try to read the INIT interrupt */
#define INIT_LOOP 20000
/* delay between retries */
#define INIT_LOOP_DELAY 50
#define WU_COUNTER_PAUSE_VAL 0x3FF
#define WELP_ARM_COMMAND_VAL 0x4
#define OCP_REG_POLARITY 0x0064
#define OCP_REG_CLK_TYPE 0x0448
#define OCP_REG_CLK_POLARITY 0x0cb2
#define OCP_REG_CLK_PULL 0x0cb4
#define CMD_MBOX_ADDRESS 0x407B4
#define POLARITY_LOW BIT(1)
#define NO_PULL (BIT(14) | BIT(15))
#define FREF_CLK_TYPE_BITS 0xfffffe7f
#define CLK_REQ_PRCM 0x100
#define FREF_CLK_POLARITY_BITS 0xfffff8ff
#define CLK_REQ_OUTN_SEL 0x700
/* PLL configuration algorithm for wl128x */
#define SYS_CLK_CFG_REG 0x2200
/* Bit[0] - 0-TCXO, 1-FREF */
#define MCS_PLL_CLK_SEL_FREF BIT(0)
/* Bit[3:2] - 01-TCXO, 10-FREF */
#define WL_CLK_REQ_TYPE_FREF BIT(3)
#define WL_CLK_REQ_TYPE_PG2 (BIT(3) | BIT(2))
/* Bit[4] - 0-TCXO, 1-FREF */
#define PRCM_CM_EN_MUX_WLAN_FREF BIT(4)
#define TCXO_ILOAD_INT_REG 0x2264
#define TCXO_CLK_DETECT_REG 0x2266
#define TCXO_DET_FAILED BIT(4)
#define FREF_ILOAD_INT_REG 0x2084
#define FREF_CLK_DETECT_REG 0x2086
#define FREF_CLK_DETECT_FAIL BIT(4)
/* Use this reg for masking during driver access */
#define WL_SPARE_REG 0x2320
#define WL_SPARE_VAL BIT(2)
/* Bit[6:5:3] - mask wl write SYS_CLK_CFG[8:5:2:4] */
#define WL_SPARE_MASK_8526 (BIT(6) | BIT(5) | BIT(3))
#define PLL_LOCK_COUNTERS_REG 0xD8C
#define PLL_LOCK_COUNTERS_COEX 0x0F
#define PLL_LOCK_COUNTERS_MCS 0xF0
#define MCS_PLL_OVERRIDE_REG 0xD90
#define MCS_PLL_CONFIG_REG 0xD92
#define MCS_SEL_IN_FREQ_MASK 0x0070
#define MCS_SEL_IN_FREQ_SHIFT 4
#define MCS_PLL_CONFIG_REG_VAL 0x73
#define MCS_PLL_ENABLE_HP (BIT(0) | BIT(1))
#define MCS_PLL_M_REG 0xD94
#define MCS_PLL_N_REG 0xD96
#define MCS_PLL_M_REG_VAL 0xC8
#define MCS_PLL_N_REG_VAL 0x07
#define SDIO_IO_DS 0xd14
/* SDIO/wSPI DS configuration values */
enum {
HCI_IO_DS_8MA = 0,
HCI_IO_DS_4MA = 1, /* default */
HCI_IO_DS_6MA = 2,
HCI_IO_DS_2MA = 3,
};
/* end PLL configuration algorithm for wl128x */
#endif
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