Commit f2776834 authored by John W. Linville's avatar John W. Linville
parents e9676695 916ef361
......@@ -6669,6 +6669,16 @@ L: alsa-devel@alsa-project.org (moderated for non-subscribers)
S: Maintained
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
M: Jon Maloy <jon.maloy@ericsson.com>
M: Allan Stephens <allan.stephens@windriver.com>
......@@ -7425,23 +7435,6 @@ M: Miloslav Trmac <mitr@volny.cz>
S: Maintained
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
M: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
L: linux-wireless@vger.kernel.org
......
......@@ -282,8 +282,7 @@ source "drivers/net/wireless/orinoco/Kconfig"
source "drivers/net/wireless/p54/Kconfig"
source "drivers/net/wireless/rt2x00/Kconfig"
source "drivers/net/wireless/rtlwifi/Kconfig"
source "drivers/net/wireless/wl1251/Kconfig"
source "drivers/net/wireless/wl12xx/Kconfig"
source "drivers/net/wireless/ti/Kconfig"
source "drivers/net/wireless/zd1211rw/Kconfig"
source "drivers/net/wireless/mwifiex/Kconfig"
......
......@@ -51,9 +51,7 @@ obj-$(CONFIG_ATH_COMMON) += ath/
obj-$(CONFIG_MAC80211_HWSIM) += mac80211_hwsim.o
obj-$(CONFIG_WL1251) += wl1251/
obj-$(CONFIG_WL12XX) += wl12xx/
obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx/
obj-$(CONFIG_WL_TI) += ti/
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 @@
#define REGISTERS_DOWN_SIZE 0x00008800
#define REGISTERS_WORK_SIZE 0x0000b000
#define HW_ACCESS_ELP_CTRL_REG_ADDR 0x1FFFC
#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
------------------------------------------
......@@ -57,14 +49,14 @@
(not self-clearing), the Wlan hardware
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_ADATA (REGISTERS_BASE + 0x000c)
#define WL1271_SLV_MEM_DATA (REGISTERS_BASE + 0x0018)
#define ACX_REG_INTERRUPT_TRIG (REGISTERS_BASE + 0x0474)
#define ACX_REG_INTERRUPT_TRIG_H (REGISTERS_BASE + 0x0478)
#define WL12XX_REG_INTERRUPT_TRIG (REGISTERS_BASE + 0x0474)
#define WL12XX_REG_INTERRUPT_TRIG_H (REGISTERS_BASE + 0x0478)
/*=============================================
Host Interrupt Mask Register - 32bit (RW)
......@@ -94,7 +86,7 @@
21- -
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)
......@@ -125,7 +117,7 @@
Reading this register doesn't
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
......@@ -148,9 +140,9 @@
HINT_STS_ND registers, thus making the
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*/
#define SOR_CFG (REGISTERS_BASE + 0x0800)
......@@ -175,9 +167,9 @@
1 halt 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
......@@ -196,72 +188,67 @@
*================================================*/
#define ACX_REG_EE_START (REGISTERS_BASE + 0x080C)
#define OCP_POR_CTR (REGISTERS_BASE + 0x09B4)
#define OCP_DATA_WRITE (REGISTERS_BASE + 0x09B8)
#define OCP_DATA_READ (REGISTERS_BASE + 0x09BC)
#define OCP_CMD (REGISTERS_BASE + 0x09C0)
#define WL1271_HOST_WR_ACCESS (REGISTERS_BASE + 0x09F8)
#define WL12XX_OCP_POR_CTR (REGISTERS_BASE + 0x09B4)
#define WL12XX_OCP_DATA_WRITE (REGISTERS_BASE + 0x09B8)
#define WL12XX_OCP_DATA_READ (REGISTERS_BASE + 0x09BC)
#define WL12XX_OCP_CMD (REGISTERS_BASE + 0x09C0)
#define CHIP_ID_B (REGISTERS_BASE + 0x5674)
#define WL12XX_HOST_WR_ACCESS (REGISTERS_BASE + 0x09F8)
#define CHIP_ID_1271_PG10 (0x4030101)
#define CHIP_ID_1271_PG20 (0x4030111)
#define CHIP_ID_1283_PG10 (0x05030101)
#define CHIP_ID_1283_PG20 (0x05030111)
#define WL12XX_CHIP_ID_B (REGISTERS_BASE + 0x5674)
#define ENABLE (REGISTERS_BASE + 0x5450)
#define WL12XX_ENABLE (REGISTERS_BASE + 0x5450)
/* Power Management registers */
#define ELP_CFG_MODE (REGISTERS_BASE + 0x5804)
#define ELP_CMD (REGISTERS_BASE + 0x5808)
#define PLL_CAL_TIME (REGISTERS_BASE + 0x5810)
#define CLK_REQ_TIME (REGISTERS_BASE + 0x5814)
#define CLK_BUF_TIME (REGISTERS_BASE + 0x5818)
#define WL12XX_ELP_CFG_MODE (REGISTERS_BASE + 0x5804)
#define WL12XX_ELP_CMD (REGISTERS_BASE + 0x5808)
#define WL12XX_PLL_CAL_TIME (REGISTERS_BASE + 0x5810)
#define WL12XX_CLK_REQ_TIME (REGISTERS_BASE + 0x5814)
#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*/
#define SCR_PAD0 (REGISTERS_BASE + 0x5608)
#define SCR_PAD1 (REGISTERS_BASE + 0x560C)
#define SCR_PAD2 (REGISTERS_BASE + 0x5610)
#define SCR_PAD3 (REGISTERS_BASE + 0x5614)
#define SCR_PAD4 (REGISTERS_BASE + 0x5618)
#define SCR_PAD4_SET (REGISTERS_BASE + 0x561C)
#define SCR_PAD4_CLR (REGISTERS_BASE + 0x5620)
#define SCR_PAD5 (REGISTERS_BASE + 0x5624)
#define SCR_PAD5_SET (REGISTERS_BASE + 0x5628)
#define SCR_PAD5_CLR (REGISTERS_BASE + 0x562C)
#define SCR_PAD6 (REGISTERS_BASE + 0x5630)
#define SCR_PAD7 (REGISTERS_BASE + 0x5634)
#define SCR_PAD8 (REGISTERS_BASE + 0x5638)
#define SCR_PAD9 (REGISTERS_BASE + 0x563C)
#define WL12XX_SCR_PAD0 (REGISTERS_BASE + 0x5608)
#define WL12XX_SCR_PAD1 (REGISTERS_BASE + 0x560C)
#define WL12XX_SCR_PAD2 (REGISTERS_BASE + 0x5610)
#define WL12XX_SCR_PAD3 (REGISTERS_BASE + 0x5614)
#define WL12XX_SCR_PAD4 (REGISTERS_BASE + 0x5618)
#define WL12XX_SCR_PAD4_SET (REGISTERS_BASE + 0x561C)
#define WL12XX_SCR_PAD4_CLR (REGISTERS_BASE + 0x5620)
#define WL12XX_SCR_PAD5 (REGISTERS_BASE + 0x5624)
#define WL12XX_SCR_PAD5_SET (REGISTERS_BASE + 0x5628)
#define WL12XX_SCR_PAD5_CLR (REGISTERS_BASE + 0x562C)
#define WL12XX_SCR_PAD6 (REGISTERS_BASE + 0x5630)
#define WL12XX_SCR_PAD7 (REGISTERS_BASE + 0x5634)
#define WL12XX_SCR_PAD8 (REGISTERS_BASE + 0x5638)
#define WL12XX_SCR_PAD9 (REGISTERS_BASE + 0x563C)
/* Spare registers*/
#define SPARE_A1 (REGISTERS_BASE + 0x0994)
#define SPARE_A2 (REGISTERS_BASE + 0x0998)
#define SPARE_A3 (REGISTERS_BASE + 0x099C)
#define SPARE_A4 (REGISTERS_BASE + 0x09A0)
#define SPARE_A5 (REGISTERS_BASE + 0x09A4)
#define SPARE_A6 (REGISTERS_BASE + 0x09A8)
#define SPARE_A7 (REGISTERS_BASE + 0x09AC)
#define SPARE_A8 (REGISTERS_BASE + 0x09B0)
#define SPARE_B1 (REGISTERS_BASE + 0x5420)
#define SPARE_B2 (REGISTERS_BASE + 0x5424)
#define SPARE_B3 (REGISTERS_BASE + 0x5428)
#define SPARE_B4 (REGISTERS_BASE + 0x542C)
#define SPARE_B5 (REGISTERS_BASE + 0x5430)
#define SPARE_B6 (REGISTERS_BASE + 0x5434)
#define SPARE_B7 (REGISTERS_BASE + 0x5438)
#define SPARE_B8 (REGISTERS_BASE + 0x543C)
#define PLL_PARAMETERS (REGISTERS_BASE + 0x6040)
#define WU_COUNTER_PAUSE (REGISTERS_BASE + 0x6008)
#define WELP_ARM_COMMAND (REGISTERS_BASE + 0x6100)
#define DRPW_SCRATCH_START (DRPW_BASE + 0x002C)
#define ACX_SLV_SOFT_RESET_BIT BIT(1)
#define WL12XX_SPARE_A1 (REGISTERS_BASE + 0x0994)
#define WL12XX_SPARE_A2 (REGISTERS_BASE + 0x0998)
#define WL12XX_SPARE_A3 (REGISTERS_BASE + 0x099C)
#define WL12XX_SPARE_A4 (REGISTERS_BASE + 0x09A0)
#define WL12XX_SPARE_A5 (REGISTERS_BASE + 0x09A4)
#define WL12XX_SPARE_A6 (REGISTERS_BASE + 0x09A8)
#define WL12XX_SPARE_A7 (REGISTERS_BASE + 0x09AC)
#define WL12XX_SPARE_A8 (REGISTERS_BASE + 0x09B0)
#define WL12XX_SPARE_B1 (REGISTERS_BASE + 0x5420)
#define WL12XX_SPARE_B2 (REGISTERS_BASE + 0x5424)
#define WL12XX_SPARE_B3 (REGISTERS_BASE + 0x5428)
#define WL12XX_SPARE_B4 (REGISTERS_BASE + 0x542C)
#define WL12XX_SPARE_B5 (REGISTERS_BASE + 0x5430)
#define WL12XX_SPARE_B6 (REGISTERS_BASE + 0x5434)
#define WL12XX_SPARE_B7 (REGISTERS_BASE + 0x5438)
#define WL12XX_SPARE_B8 (REGISTERS_BASE + 0x543C)
#define WL12XX_PLL_PARAMETERS (REGISTERS_BASE + 0x6040)
#define WL12XX_WU_COUNTER_PAUSE (REGISTERS_BASE + 0x6008)
#define WL12XX_WELP_ARM_COMMAND (REGISTERS_BASE + 0x6100)
#define WL12XX_DRPW_SCRATCH_START (DRPW_BASE + 0x002C)
#define WL12XX_CMD_MBOX_ADDRESS 0x407B4
#define ACX_REG_EEPROM_START_BIT BIT(1)
/* Command/Information Mailbox Pointers */
......@@ -279,7 +266,7 @@
the host receives the Init Complete interrupt from
the Wlan hardware.
===============================================*/
#define REG_COMMAND_MAILBOX_PTR (SCR_PAD0)
#define WL12XX_REG_COMMAND_MAILBOX_PTR (WL12XX_SCR_PAD0)
/*===============================================
Information Mailbox Pointer - 32bit RW
......@@ -294,7 +281,7 @@
until after the host receives the Init Complete interrupt from
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
......@@ -365,26 +352,6 @@
#define ACX_CONT_WIND_MIN_MASK 0x0000007f
#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_26_0 1
#define REF_FREQ_38_4 2
......@@ -400,38 +367,19 @@
#define LUT_PARAM_BB_PLL_LOOP_FILTER 5
#define LUT_PARAM_NUM 6
#define ACX_EEPROMLESS_IND_REG (SCR_PAD4)
#define WL12XX_EEPROMLESS_IND (WL12XX_SCR_PAD4)
#define USE_EEPROM 0
#define SOFT_RESET_MAX_TIME 1000000
#define SOFT_RESET_STALL_TIME 1000
#define NVS_DATA_BUNDARY_ALIGNMENT 4
/* Firmware image load chunk size */
#define CHUNK_SIZE 16384
/* Firmware image header size */
#define FW_HDR_SIZE 8
#define ECPU_CONTROL_HALT 0x00000101
/******************************************************************************
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 OFDM_RATE_BIT BIT(6)
#define PBCC_RATE_BIT BIT(7)
......@@ -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,
};
/*************************************************************************
Interrupt Trigger Register (Host -> WiLink)
**************************************************************************/
/* Hardware to Embedded CPU Interrupts - first 32-bit register set */
/* end PLL configuration algorithm for wl128x */
/*
* Host Command Interrupt. Setting this bit masks
......@@ -480,7 +496,7 @@ b12-b0 - Supported Rate indicator bits as defined below.
* the FW that it has sent a command
* 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
......@@ -488,42 +504,27 @@ b12-b0 - Supported Rate indicator bits as defined below.
* the unsolicited information from the event
* mailbox.
*/
#define 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 WL12XX_INTR_TRIG_EVENT_ACK BIT(1)
#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)
/*===============================================
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
/*
* 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 HI_CFG_DEF_VAL \
(HI_CFG_UART_ENABLE | \
HI_CFG_RST232_ENABLE | \
HI_CFG_CLOCK_REQ_SELECT | \
HI_CFG_HOST_INT_ENABLE)
#define WL127X_REG_FUSE_DATA_2_1 0x050a
#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
wl12xx_spi-objs = spi.o
wl12xx_sdio-objs = sdio.o
wlcore_spi-objs = spi.o
wlcore_sdio-objs = sdio.o
wl12xx-$(CONFIG_NL80211_TESTMODE) += testmode.o
obj-$(CONFIG_WL12XX) += wl12xx.o
obj-$(CONFIG_WL12XX_SPI) += wl12xx_spi.o
obj-$(CONFIG_WL12XX_SDIO) += wl12xx_sdio.o
wlcore-$(CONFIG_NL80211_TESTMODE) += testmode.o
obj-$(CONFIG_WLCORE) += wlcore.o
obj-$(CONFIG_WLCORE_SPI) += wlcore_spi.o
obj-$(CONFIG_WLCORE_SDIO) += wlcore_sdio.o
# small builtin driver bit
obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx_platform_data.o
......
......@@ -28,11 +28,11 @@
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include "wl12xx.h"
#include "wlcore.h"
#include "debug.h"
#include "wl12xx_80211.h"
#include "reg.h"
#include "ps.h"
#include "hw_ops.h"
int wl1271_acx_wake_up_conditions(struct wl1271 *wl, struct wl12xx_vif *wlvif,
u8 wake_up_event, u8 listen_interval)
......@@ -757,7 +757,10 @@ int wl1271_acx_sta_rate_policies(struct wl1271 *wl, struct wl12xx_vif *wlvif)
/* configure one AP supported rate class */
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.long_retry_limit = c->long_retry_limit;
acx->rate_policy.aflags = c->aflags;
......@@ -969,17 +972,14 @@ int wl12xx_acx_mem_cfg(struct wl1271 *wl)
goto out;
}
if (wl->chip.id == CHIP_ID_1283_PG20)
mem = &wl->conf.mem_wl128x;
else
mem = &wl->conf.mem_wl127x;
mem = &wl->conf.mem;
/* memory config */
mem_conf->num_stations = mem->num_stations;
mem_conf->rx_mem_block_num = mem->rx_block_num;
mem_conf->tx_min_mem_block_num = mem->tx_min_block_num;
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->tx_free_req = mem->min_req_tx_blocks;
mem_conf->rx_free_req = mem->min_req_rx_blocks;
......@@ -998,32 +998,6 @@ int wl12xx_acx_mem_cfg(struct wl1271 *wl)
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 ret;
......
......@@ -25,7 +25,7 @@
#ifndef __ACX_H__
#define __ACX_H__
#include "wl12xx.h"
#include "wlcore.h"
#include "cmd.h"
/*************************************************************************
......@@ -824,16 +824,11 @@ struct wl1271_acx_keep_alive_config {
__le32 period;
} __packed;
/* TODO: maybe this needs to be moved somewhere else? */
#define HOST_IF_CFG_RX_FIFO_ENABLE BIT(0)
#define HOST_IF_CFG_TX_EXTRA_BLKS_SWAP BIT(1)
#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 {
WL1271_ACX_TRIG_TYPE_LEVEL = 0,
WL1271_ACX_TRIG_TYPE_EDGE,
......@@ -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 wl12xx_acx_mem_cfg(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_smart_reflex(struct wl1271 *wl);
int wl1271_acx_bet_enable(struct wl1271 *wl, struct wl12xx_vif *wlvif,
......
......@@ -27,42 +27,25 @@
#include "debug.h"
#include "acx.h"
#include "reg.h"
#include "boot.h"
#include "io.h"
#include "event.h"
#include "rx.h"
#include "hw_ops.h"
static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag)
{
u32 cpu_ctrl;
/* 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) */
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)
{
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)
static int wlcore_parse_fw_ver(struct wl1271 *wl)
{
int ret;
......@@ -74,33 +57,49 @@ static void wl1271_parse_fw_ver(struct wl1271 *wl)
if (ret != 5) {
wl1271_warning("fw version incorrect value");
memset(wl->chip.fw_ver, 0, sizeof(wl->chip.fw_ver));
return;
return -EINVAL;
}
/* Check if any quirks are needed with older fw versions */
wl->quirks |= wl12xx_get_fw_ver_quirks(wl);
ret = wlcore_identify_fw(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);
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));
kfree(static_data);
/* make sure the string is NULL-terminated */
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,
size_t fw_data_len, u32 dest)
{
struct wl1271_partition_set partition;
struct wlcore_partition_set partition;
int addr, chunk_num, partition_limit;
u8 *p, *chunk;
......@@ -122,13 +121,13 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
return -ENOMEM;
}
memcpy(&partition, &wl12xx_part_table[PART_DOWN], sizeof(partition));
memcpy(&partition, &wl->ptable[PART_DOWN], sizeof(partition));
partition.mem.start = dest;
wl1271_set_partition(wl, &partition);
wlcore_set_partition(wl, &partition);
/* 10.1 set partition limit and chunk num */
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) {
/* 10.2 update partition, if needed */
......@@ -136,9 +135,9 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
if (addr > partition_limit) {
addr = dest + 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;
wl1271_set_partition(wl, &partition);
wlcore_set_partition(wl, &partition);
}
/* 10.3 upload the chunk */
......@@ -164,7 +163,7 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
return 0;
}
static int wl1271_boot_upload_firmware(struct wl1271 *wl)
int wlcore_boot_upload_firmware(struct wl1271 *wl)
{
u32 chunks, addr, len;
int ret = 0;
......@@ -196,8 +195,9 @@ static int wl1271_boot_upload_firmware(struct wl1271 *wl)
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;
int i;
......@@ -207,27 +207,7 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
if (wl->nvs == NULL)
return -ENODEV;
if (wl->chip.id == CHIP_ID_1283_PG20) {
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 {
if (wl->quirks & WLCORE_QUIRK_LEGACY_NVS) {
struct wl1271_nvs_file *nvs =
(struct wl1271_nvs_file *)wl->nvs;
/*
......@@ -255,6 +235,25 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
/* only the first part of the NVS needs to be uploaded */
nvs_len = sizeof(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 */
......@@ -281,9 +280,10 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
/*
* 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 */
nvs_ptr += 3;
......@@ -324,7 +324,7 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
nvs_len -= nvs_ptr - (u8 *)wl->nvs;
/* 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 */
nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL);
......@@ -332,7 +332,8 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
return -ENOMEM;
/* 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);
return 0;
......@@ -341,58 +342,19 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
wl1271_error("nvs data is malformed");
return -EILSEQ;
}
EXPORT_SYMBOL_GPL(wlcore_boot_upload_nvs);
static void wl1271_boot_enable_interrupts(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 wlcore_boot_run_firmware(struct wl1271 *wl)
{
int loop, ret;
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);
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);
......@@ -405,7 +367,7 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
loop = 0;
while (loop++ < INIT_LOOP) {
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) {
wl1271_error("error reading hardware complete "
......@@ -414,8 +376,8 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
}
/* check that ACX_INTR_INIT_COMPLETE is enabled */
else if (intr & WL1271_ACX_INTR_INIT_COMPLETE) {
wl1271_write32(wl, ACX_REG_INTERRUPT_ACK,
WL1271_ACX_INTR_INIT_COMPLETE);
wlcore_write_reg(wl, REG_INTERRUPT_ACK,
WL1271_ACX_INTR_INIT_COMPLETE);
break;
}
}
......@@ -427,18 +389,22 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
}
/* 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 */
wl->event_box_addr = wl1271_read32(wl, REG_EVENT_MAILBOX_PTR);
wl1271_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x", wl->cmd_box_addr);
/* set the working partition to its "running" mode offset */
wl1271_set_partition(wl, &wl12xx_part_table[PART_WORK]);
/* get hardware config event mail box */
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",
wl->cmd_box_addr, wl->event_box_addr);
wl1271_debug(DEBUG_MAILBOX, "MBOX ptrs: 0x%x 0x%x",
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
......@@ -468,319 +434,10 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
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 */
return 0;
}
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;
}
EXPORT_SYMBOL_GPL(wlcore_boot_run_firmware);
/*
* 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 @@
#include <linux/ieee80211.h>
#include <linux/slab.h>
#include "wl12xx.h"
#include "wlcore.h"
#include "debug.h"
#include "reg.h"
#include "io.h"
#include "acx.h"
#include "wl12xx_80211.h"
......@@ -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_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);
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)) {
if (time_after(jiffies, timeout)) {
wl1271_error("command complete timeout");
......@@ -85,7 +88,7 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
else
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 */
......@@ -100,8 +103,7 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
goto fail;
}
wl1271_write32(wl, ACX_REG_INTERRUPT_ACK,
WL1271_ACX_INTR_CMD_COMPLETE);
wlcore_write_reg(wl, REG_INTERRUPT_ACK, WL1271_ACX_INTR_CMD_COMPLETE);
return 0;
fail:
......@@ -110,240 +112,18 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
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
* timeout occurs (WL1271_EVENT_TIMEOUT in msecs)
*/
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;
int ret = 0;
events_vector = kmalloc(sizeof(*events_vector), GFP_DMA);
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)
if (time_after(jiffies, timeout)) {
wl1271_debug(DEBUG_CMD, "timeout waiting for event %d",
(int)mask);
return -ETIMEDOUT;
ret = -ETIMEDOUT;
goto out;
}
msleep(1);
/* read from both event fields */
wl1271_read(wl, wl->mbox_ptr[0], &events_vector,
sizeof(events_vector), false);
event = events_vector & mask;
wl1271_read(wl, wl->mbox_ptr[1], &events_vector,
sizeof(events_vector), false);
event |= events_vector & mask;
wl1271_read(wl, wl->mbox_ptr[0], events_vector,
sizeof(*events_vector), false);
event = *events_vector & mask;
wl1271_read(wl, wl->mbox_ptr[1], events_vector,
sizeof(*events_vector), false);
event |= *events_vector & mask;
} while (!event);
return 0;
out:
kfree(events_vector);
return ret;
}
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,
cmd->role_id = wlvif->dev_role_id;
if (wlvif->band == IEEE80211_BAND_5GHZ)
cmd->band = WL12XX_BAND_5GHZ;
cmd->band = WLCORE_BAND_5GHZ;
cmd->channel = wlvif->channel;
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)
cmd->role_id = wlvif->role_id;
if (wlvif->band == IEEE80211_BAND_5GHZ)
cmd->band = WL12XX_BAND_5GHZ;
cmd->band = WLCORE_BAND_5GHZ;
cmd->channel = wlvif->channel;
cmd->sta.basic_rate_set = cpu_to_le32(wlvif->basic_rate_set);
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)
switch (wlvif->band) {
case IEEE80211_BAND_2GHZ:
cmd->band = RADIO_BAND_2_4GHZ;
cmd->band = WLCORE_BAND_2_4GHZ;
break;
case IEEE80211_BAND_5GHZ:
cmd->band = RADIO_BAND_5GHZ;
cmd->band = WLCORE_BAND_5GHZ;
break;
default:
wl1271_warning("ap start - unknown band: %d", (int)wlvif->band);
cmd->band = RADIO_BAND_2_4GHZ;
cmd->band = WLCORE_BAND_2_4GHZ;
break;
}
......@@ -830,7 +613,7 @@ int wl12xx_cmd_role_start_ibss(struct wl1271 *wl, struct wl12xx_vif *wlvif)
cmd->role_id = wlvif->role_id;
if (wlvif->band == IEEE80211_BAND_5GHZ)
cmd->band = WL12XX_BAND_5GHZ;
cmd->band = WLCORE_BAND_5GHZ;
cmd->channel = wlvif->channel;
cmd->ibss.basic_rate_set = cpu_to_le32(wlvif->basic_rate_set);
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)
return ret;
}
EXPORT_SYMBOL_GPL(wl1271_cmd_test);
/**
* read acx from firmware
......@@ -960,6 +744,7 @@ int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len)
return 0;
}
EXPORT_SYMBOL_GPL(wl1271_cmd_configure);
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,
cmd->channel = wlvif->channel;
switch (wlvif->band) {
case IEEE80211_BAND_2GHZ:
cmd->band = RADIO_BAND_2_4GHZ;
cmd->band = WLCORE_BAND_2_4GHZ;
break;
case IEEE80211_BAND_5GHZ:
cmd->band = RADIO_BAND_5GHZ;
cmd->band = WLCORE_BAND_5GHZ;
break;
default:
wl1271_error("roc - unknown band: %d", (int)wlvif->band);
......
......@@ -25,17 +25,12 @@
#ifndef __CMD_H__
#define __CMD_H__
#include "wl12xx.h"
#include "wlcore.h"
struct acx_header;
int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t 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,
u8 *role_id);
int wl12xx_cmd_role_disable(struct wl1271 *wl, u8 *role_id);
......@@ -262,13 +257,13 @@ struct wl12xx_cmd_role_disable {
u8 padding[3];
} __packed;
enum wl12xx_band {
WL12XX_BAND_2_4GHZ = 0,
WL12XX_BAND_5GHZ = 1,
WL12XX_BAND_JAPAN_4_9_GHZ = 2,
WL12XX_BAND_DEFAULT = WL12XX_BAND_2_4GHZ,
WL12XX_BAND_INVALID = 0x7E,
WL12XX_BAND_MAX_RADIO = 0x7F,
enum wlcore_band {
WLCORE_BAND_2_4GHZ = 0,
WLCORE_BAND_5GHZ = 1,
WLCORE_BAND_JAPAN_4_9_GHZ = 2,
WLCORE_BAND_DEFAULT = WLCORE_BAND_2_4GHZ,
WLCORE_BAND_INVALID = 0x7E,
WLCORE_BAND_MAX_RADIO = 0x7F,
};
struct wl12xx_cmd_role_start {
......@@ -494,83 +489,6 @@ enum wl1271_channel_tune_bands {
#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:
*
......
......@@ -65,36 +65,7 @@ enum {
CONF_HW_RATE_INDEX_MAX = CONF_HW_RATE_INDEX_54MBPS,
};
enum {
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
#define CONF_HW_RXTX_RATE_UNSUPPORTED 0xff
enum {
CONF_SG_DISABLE = 0,
......@@ -1096,16 +1067,31 @@ struct conf_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) */
u16 max_dwell_time_active;
/* The delta between the min dwell time and max dwell time for
* 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;
/* 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;
/* number of probe requests to send on each channel in active scans */
......@@ -1118,26 +1104,6 @@ struct conf_sched_scan_settings {
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 {
u8 rx_ba_win_size;
u8 tx_ba_win_size;
......@@ -1286,7 +1252,7 @@ struct conf_hangover_settings {
u8 window_size;
};
struct conf_drv_settings {
struct wlcore_conf {
struct conf_sg_settings sg;
struct conf_rx_settings rx;
struct conf_tx_settings tx;
......@@ -1296,16 +1262,13 @@ struct conf_drv_settings {
struct conf_roam_trigger_settings roam_trigger;
struct conf_scan_settings scan;
struct conf_sched_scan_settings sched_scan;
struct conf_rf_settings rf;
struct conf_ht_setting ht;
struct conf_memory_settings mem_wl127x;
struct conf_memory_settings mem_wl128x;
struct conf_memory_settings mem;
struct conf_fm_coex fm_coex;
struct conf_rx_streaming_settings rx_streaming;
struct conf_fwlog fwlog;
struct conf_rate_policy_settings rate;
struct conf_hangover_settings hangover;
u8 hci_io_ds;
};
#endif
......@@ -52,6 +52,7 @@ enum {
DEBUG_ADHOC = BIT(16),
DEBUG_AP = BIT(17),
DEBUG_PROBE = BIT(18),
DEBUG_IO = BIT(19),
DEBUG_MASTER = (DEBUG_ADHOC | DEBUG_AP),
DEBUG_ALL = ~0,
};
......
......@@ -26,7 +26,7 @@
#include <linux/skbuff.h>
#include <linux/slab.h>
#include "wl12xx.h"
#include "wlcore.h"
#include "debug.h"
#include "acx.h"
#include "ps.h"
......@@ -647,6 +647,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(ba_support);
VIF_STATE_PRINT_INT(ba_allowed);
VIF_STATE_PRINT_INT(is_gem);
VIF_STATE_PRINT_LLHEX(tx_security_seq);
VIF_STATE_PRINT_INT(tx_security_last_seq_lsb);
}
......
......@@ -24,7 +24,7 @@
#ifndef __DEBUGFS_H__
#define __DEBUGFS_H__
#include "wl12xx.h"
#include "wlcore.h"
int wl1271_debugfs_init(struct wl1271 *wl);
void wl1271_debugfs_exit(struct wl1271 *wl);
......
......@@ -21,9 +21,8 @@
*
*/
#include "wl12xx.h"
#include "wlcore.h"
#include "debug.h"
#include "reg.h"
#include "io.h"
#include "event.h"
#include "ps.h"
......@@ -98,8 +97,9 @@ static void wl1271_event_mbox_dump(struct event_mailbox *mbox)
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 wl12xx_vif *wlvif;
u32 vector;
......@@ -196,7 +196,7 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
bool success;
if (!test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS,
&wl->flags))
&wlvif->flags))
continue;
success = mbox->channel_switch_status ? false : true;
......@@ -278,18 +278,8 @@ int wl1271_event_unmask(struct wl1271 *wl)
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)
{
struct event_mailbox mbox;
int ret;
wl1271_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num);
......@@ -298,16 +288,19 @@ int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num)
return -EINVAL;
/* first we read the mbox descriptor */
wl1271_read(wl, wl->mbox_ptr[mbox_num], &mbox,
sizeof(struct event_mailbox), false);
wl1271_read(wl, wl->mbox_ptr[mbox_num], wl->mbox,
sizeof(*wl->mbox), false);
/* process the descriptor */
ret = wl1271_event_process(wl, &mbox);
ret = wl1271_event_process(wl);
if (ret < 0)
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;
}
......@@ -132,8 +132,9 @@ struct event_mailbox {
u8 reserved_8[9];
} __packed;
struct wl1271;
int wl1271_event_unmask(struct wl1271 *wl);
void wl1271_event_mbox_config(struct wl1271 *wl);
int wl1271_event_handle(struct wl1271 *wl, u8 mbox);
#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 @@
#include "wl12xx_80211.h"
#include "acx.h"
#include "cmd.h"
#include "reg.h"
#include "tx.h"
#include "io.h"
#include "hw_ops.h"
int wl1271_init_templates_config(struct wl1271 *wl)
{
......@@ -319,7 +319,7 @@ static int wl12xx_init_fwlog(struct wl1271 *wl)
{
int ret;
if (wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED)
if (wl->quirks & WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED)
return 0;
ret = wl12xx_cmd_config_fwlog(wl);
......@@ -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);
}
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 */
static int wl12xx_init_sta_role(struct wl1271 *wl, struct wl12xx_vif *wlvif)
{
......@@ -582,10 +562,17 @@ int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif)
if (ret < 0)
return ret;
} else if (!wl->sta_count) {
/* Configure for ELP power saving */
ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
if (ret < 0)
return ret;
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 */
ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
if (ret < 0)
return ret;
}
}
}
......@@ -652,6 +639,10 @@ int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif)
if (ret < 0)
return ret;
ret = wlcore_hw_init_vif(wl, wlvif);
if (ret < 0)
return ret;
return 0;
}
......@@ -659,27 +650,8 @@ int wl1271_hw_init(struct wl1271 *wl)
{
int ret;
if (wl->chip.id == CHIP_ID_1283_PG20) {
ret = wl128x_cmd_general_parms(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);
/* Chip-specific hw init */
ret = wl->ops->hw_init(wl);
if (ret < 0)
return ret;
......
......@@ -24,7 +24,7 @@
#ifndef __INIT_H__
#define __INIT_H__
#include "wl12xx.h"
#include "wlcore.h"
int wl1271_hw_init_power_auth(struct wl1271 *wl);
int wl1271_init_templates_config(struct wl1271 *wl);
......
......@@ -26,84 +26,12 @@
#include <linux/spi/spi.h>
#include <linux/interrupt.h>
#include "wl12xx.h"
#include "wlcore.h"
#include "debug.h"
#include "wl12xx_80211.h"
#include "io.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)
{
if (wl->if_ops->set_block_size) {
......@@ -114,17 +42,53 @@ bool wl1271_set_block_size(struct wl1271 *wl)
return false;
}
void wl1271_disable_interrupts(struct wl1271 *wl)
void wlcore_disable_interrupts(struct wl1271 *wl)
{
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);
}
EXPORT_SYMBOL_GPL(wlcore_enable_interrupts);
/* Set the SPI partitions to access the chip addresses
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 partitions to access the chip addresses
*
* To simplify driver code, a fixed (virtual) memory map is defined for
* register and memory addresses. Because in the chipset, in different stages
......@@ -158,33 +122,43 @@ void wl1271_enable_interrupts(struct wl1271 *wl)
* | |
*
*/
int wl1271_set_partition(struct wl1271 *wl,
struct wl1271_partition_set *p)
void wlcore_set_partition(struct wl1271 *wl,
const struct wlcore_partition_set *p)
{
/* 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);
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);
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);
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);
/* write partition info to the chipset */
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_PART1_START_ADDR, p->reg.start);
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_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);
}
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)
{
......@@ -197,48 +171,3 @@ void wl1271_io_init(struct wl1271 *wl)
if (wl->if_ops->init)
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 @@
#define __IO_H__
#include <linux/irqreturn.h>
#include "reg.h"
#define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0
......@@ -43,15 +42,14 @@
#define HW_ACCESS_PRAM_MAX_RANGE 0x3c000
extern struct wl1271_partition_set wl12xx_part_table[PART_TABLE_LEN];
struct wl1271;
void wl1271_disable_interrupts(struct wl1271 *wl);
void wl1271_enable_interrupts(struct wl1271 *wl);
void wlcore_disable_interrupts(struct wl1271 *wl);
void wlcore_enable_interrupts(struct wl1271 *wl);
void wl1271_io_reset(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 */
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,
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)
{
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)
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,
size_t len, bool fixed)
{
int physical;
physical = wl1271_translate_addr(wl, addr);
physical = wlcore_translate_addr(wl, addr);
wl1271_raw_read(wl, physical, buf, len, fixed);
}
......@@ -120,11 +106,23 @@ static inline void wl1271_write(struct wl1271 *wl, int addr, void *buf,
{
int physical;
physical = wl1271_translate_addr(wl, addr);
physical = wlcore_translate_addr(wl, addr);
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,
void *buf, size_t len, bool fixed)
{
......@@ -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 */
addr = hwaddr << 5;
physical = wl1271_translate_addr(wl, addr);
physical = wlcore_translate_addr(wl, addr);
wl1271_raw_read(wl, physical, buf, len, fixed);
}
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)
{
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)
......@@ -164,13 +173,8 @@ static inline int wl1271_power_on(struct wl1271 *wl)
return ret;
}
/* Top Register IO */
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);
void wlcore_set_partition(struct wl1271 *wl,
const struct wlcore_partition_set *p);
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);
void wlcore_select_partition(struct wl1271 *wl, u8 part);
#endif
......@@ -35,10 +35,9 @@
#include <linux/sched.h>
#include <linux/interrupt.h>
#include "wl12xx.h"
#include "wlcore.h"
#include "debug.h"
#include "wl12xx_80211.h"
#include "reg.h"
#include "io.h"
#include "event.h"
#include "tx.h"
......@@ -50,342 +49,15 @@
#include "boot.h"
#include "testmode.h"
#include "scan.h"
#include "hw_ops.h"
#define WL1271_BOOT_RETRIES 3
static struct conf_drv_settings default_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 = 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,
},
};
#define WL1271_BOOT_RETRIES 3
static char *fwlog_param;
static bool bug_on_recovery;
static bool no_recovery;
static void __wl1271_op_remove_interface(struct wl1271 *wl,
struct ieee80211_vif *vif,
......@@ -628,22 +300,8 @@ static void wl12xx_tx_watchdog_work(struct work_struct *work)
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 */
if (fwlog_param) {
if (!strcmp(fwlog_param, "continuous")) {
......@@ -666,28 +324,7 @@ static int wl1271_plt_init(struct wl1271 *wl)
{
int ret;
if (wl->chip.id == CHIP_ID_1283_PG20)
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);
ret = wl->ops->hw_init(wl);
if (ret < 0)
return ret;
......@@ -750,7 +387,7 @@ static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl,
static void wl12xx_irq_update_links_status(struct wl1271 *wl,
struct wl12xx_vif *wlvif,
struct wl12xx_fw_status *status)
struct wl_fw_status *status)
{
struct wl1271_link *lnk;
u32 cur_fw_ps_map;
......@@ -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) {
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;
wl12xx_irq_ps_regulate_link(wl, wlvif, hlid,
......@@ -781,15 +419,19 @@ static void wl12xx_irq_update_links_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 timespec ts;
u32 old_tx_blk_count = wl->tx_blocks_available;
int avail, freed_blocks;
int i;
size_t status_len;
status_len = sizeof(*status) + wl->fw_status_priv_len;
wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
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, "
"drv_rx_counter = %d, tx_results_counter = %d)",
......@@ -801,10 +443,10 @@ static void wl12xx_fw_status(struct wl1271 *wl,
for (i = 0; i < NUM_TX_QUEUES; i++) {
/* prevent wrap-around in freed-packets counter */
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] = status->tx_released_pkts[i];
wl->tx_pkts_freed[i] = status->counters.tx_released_pkts[i];
}
/* prevent wrap-around in total blocks counter */
......@@ -927,6 +569,9 @@ static irqreturn_t wl1271_irq(int irq, void *cookie)
smp_mb__after_clear_bit();
wl12xx_fw_status(wl, wl->fw_status);
wlcore_hw_tx_immediate_compl(wl);
intr = le32_to_cpu(wl->fw_status->intr);
intr &= WL1271_INTR_MASK;
if (!intr) {
......@@ -963,9 +608,7 @@ static irqreturn_t wl1271_irq(int irq, void *cookie)
}
/* check for tx results */
if (wl->fw_status->tx_results_counter !=
(wl->tx_results_count & 0xff))
wl1271_tx_complete(wl);
wlcore_hw_tx_delayed_compl(wl);
/* Make sure the deferred queues don't get too long */
defer_count = skb_queue_len(&wl->deferred_tx_queue) +
......@@ -1046,10 +689,7 @@ static int wl12xx_fetch_firmware(struct wl1271 *wl, bool plt)
if (plt) {
fw_type = WL12XX_FW_TYPE_PLT;
if (wl->chip.id == CHIP_ID_1283_PG20)
fw_name = WL128X_PLT_FW_NAME;
else
fw_name = WL127X_PLT_FW_NAME;
fw_name = wl->plt_fw_name;
} else {
/*
* we can't call wl12xx_get_vif_count() here because
......@@ -1057,16 +697,10 @@ static int wl12xx_fetch_firmware(struct wl1271 *wl, bool plt)
*/
if (wl->last_vif_count > 1) {
fw_type = WL12XX_FW_TYPE_MULTI;
if (wl->chip.id == CHIP_ID_1283_PG20)
fw_name = WL128X_FW_NAME_MULTI;
else
fw_name = WL127X_FW_NAME_MULTI;
fw_name = wl->mr_fw_name;
} else {
fw_type = WL12XX_FW_TYPE_NORMAL;
if (wl->chip.id == CHIP_ID_1283_PG20)
fw_name = WL128X_FW_NAME_SINGLE;
else
fw_name = WL127X_FW_NAME_SINGLE;
fw_name = wl->sr_fw_name;
}
}
......@@ -1173,7 +807,7 @@ static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
u32 first_addr;
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.mem_blocks == 0))
return;
......@@ -1239,11 +873,20 @@ static void wl1271_recovery_work(struct work_struct *work)
wl12xx_read_fwlog_panic(wl);
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 &&
!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
* 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)
static void wl1271_fw_wakeup(struct wl1271 *wl)
{
u32 elp_reg;
elp_reg = ELPCTRL_WAKE_UP;
wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_WAKE_UP);
}
static int wl1271_setup(struct wl1271 *wl)
......@@ -1323,7 +963,7 @@ static int wl12xx_set_power_on(struct wl1271 *wl)
wl1271_io_reset(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 */
wl1271_fw_wakeup(wl);
......@@ -1348,44 +988,18 @@ static int wl12xx_chip_wakeup(struct wl1271 *wl, bool plt)
* negligible, we use the same block size for all different
* chip types.
*/
if (!wl1271_set_block_size(wl))
wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
switch (wl->chip.id) {
case CHIP_ID_1271_PG10:
wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
wl->chip.id);
if (wl1271_set_block_size(wl))
wl->quirks |= WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN;
ret = wl1271_setup(wl);
if (ret < 0)
goto out;
wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
break;
case CHIP_ID_1271_PG20:
wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
wl->chip.id);
ret = wl1271_setup(wl);
if (ret < 0)
goto out;
wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
break;
ret = wl->ops->identify_chip(wl);
if (ret < 0)
goto out;
case CHIP_ID_1283_PG20:
wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
wl->chip.id);
/* TODO: make sure the lower driver has set things up correctly */
ret = wl1271_setup(wl);
if (ret < 0)
goto out;
break;
case CHIP_ID_1283_PG10:
default:
wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
ret = -ENODEV;
ret = wl1271_setup(wl);
if (ret < 0)
goto out;
}
ret = wl12xx_fetch_firmware(wl, plt);
if (ret < 0)
......@@ -1425,7 +1039,7 @@ int wl1271_plt_start(struct wl1271 *wl)
if (ret < 0)
goto power_off;
ret = wl1271_boot(wl);
ret = wl->ops->boot(wl);
if (ret < 0)
goto power_off;
......@@ -1454,7 +1068,7 @@ int wl1271_plt_start(struct wl1271 *wl)
work function will not do anything.) Also, any other
possible concurrent operations will fail due to the
current state, hence the wl1271 struct should be safe. */
wl1271_disable_interrupts(wl);
wlcore_disable_interrupts(wl);
wl1271_flush_deferred_work(wl);
cancel_work_sync(&wl->netstack_work);
mutex_lock(&wl->mutex);
......@@ -1481,7 +1095,7 @@ int wl1271_plt_stop(struct wl1271 *wl)
* Otherwise, the interrupt handler might be called and exit without
* reading the interrupt status.
*/
wl1271_disable_interrupts(wl);
wlcore_disable_interrupts(wl);
mutex_lock(&wl->mutex);
if (!wl->plt) {
mutex_unlock(&wl->mutex);
......@@ -1491,7 +1105,7 @@ int wl1271_plt_stop(struct wl1271 *wl)
* may have been disabled when op_stop was called. It will,
* 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 "
"state: %d", wl->state);
......@@ -1652,14 +1266,12 @@ static int wl1271_configure_suspend_sta(struct wl1271 *wl,
{
int ret = 0;
mutex_lock(&wl->mutex);
if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
goto out_unlock;
goto out;
ret = wl1271_ps_elp_wakeup(wl);
if (ret < 0)
goto out_unlock;
goto out;
ret = wl1271_acx_wake_up_conditions(wl, wlvif,
wl->conf.conn.suspend_wake_up_event,
......@@ -1668,11 +1280,9 @@ static int wl1271_configure_suspend_sta(struct wl1271 *wl,
if (ret < 0)
wl1271_error("suspend: set wake up conditions failed: %d", ret);
wl1271_ps_elp_sleep(wl);
out_unlock:
mutex_unlock(&wl->mutex);
out:
return ret;
}
......@@ -1682,20 +1292,17 @@ static int wl1271_configure_suspend_ap(struct wl1271 *wl,
{
int ret = 0;
mutex_lock(&wl->mutex);
if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
goto out_unlock;
goto out;
ret = wl1271_ps_elp_wakeup(wl);
if (ret < 0)
goto out_unlock;
goto out;
ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
wl1271_ps_elp_sleep(wl);
out_unlock:
mutex_unlock(&wl->mutex);
out:
return ret;
}
......@@ -1720,10 +1327,9 @@ static void wl1271_configure_resume(struct wl1271 *wl,
if ((!is_ap) && (!is_sta))
return;
mutex_lock(&wl->mutex);
ret = wl1271_ps_elp_wakeup(wl);
if (ret < 0)
goto out;
return;
if (is_sta) {
ret = wl1271_acx_wake_up_conditions(wl, wlvif,
......@@ -1739,8 +1345,6 @@ static void wl1271_configure_resume(struct wl1271 *wl,
}
wl1271_ps_elp_sleep(wl);
out:
mutex_unlock(&wl->mutex);
}
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);
mutex_lock(&wl->mutex);
wl->wow_enabled = true;
wl12xx_for_each_wlvif(wl, wlvif) {
ret = wl1271_configure_suspend(wl, wlvif);
......@@ -1763,6 +1368,7 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw,
return ret;
}
}
mutex_unlock(&wl->mutex);
/* flush any remaining work */
wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
......@@ -1770,7 +1376,7 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw,
* disable and re-enable interrupts in order to flush
* the threaded_irq
*/
wl1271_disable_interrupts(wl);
wlcore_disable_interrupts(wl);
/*
* set suspended flag to avoid triggering a new threaded_irq
......@@ -1778,7 +1384,7 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw,
*/
set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
wl1271_enable_interrupts(wl);
wlcore_enable_interrupts(wl);
flush_work(&wl->tx_work);
flush_delayed_work(&wl->elp_work);
......@@ -1810,12 +1416,15 @@ static int wl1271_op_resume(struct ieee80211_hw *hw)
wl1271_debug(DEBUG_MAC80211,
"run postponed irq_work directly");
wl1271_irq(0, wl);
wl1271_enable_interrupts(wl);
wlcore_enable_interrupts(wl);
}
mutex_lock(&wl->mutex);
wl12xx_for_each_wlvif(wl, wlvif) {
wl1271_configure_resume(wl, wlvif);
}
wl->wow_enabled = false;
mutex_unlock(&wl->mutex);
return 0;
}
......@@ -1851,7 +1460,7 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
* Otherwise, the interrupt handler might be called and exit without
* reading the interrupt status.
*/
wl1271_disable_interrupts(wl);
wlcore_disable_interrupts(wl);
mutex_lock(&wl->mutex);
if (wl->state == WL1271_STATE_OFF) {
mutex_unlock(&wl->mutex);
......@@ -1861,7 +1470,7 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
* may have been disabled when op_stop was called. It will,
* however, balance the above call to disable_interrupts().
*/
wl1271_enable_interrupts(wl);
wlcore_enable_interrupts(wl);
return;
}
......@@ -1894,7 +1503,6 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
wl->tx_results_count = 0;
wl->tx_packets_count = 0;
wl->time_offset = 0;
wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
wl->ap_fw_ps_map = 0;
wl->ap_ps_map = 0;
wl->sched_scanning = false;
......@@ -2067,7 +1675,7 @@ static bool wl12xx_init_fw(struct wl1271 *wl)
if (ret < 0)
goto power_off;
ret = wl1271_boot(wl);
ret = wl->ops->boot(wl);
if (ret < 0)
goto power_off;
......@@ -2087,7 +1695,7 @@ static bool wl12xx_init_fw(struct wl1271 *wl)
work function will not do anything.) Also, any other
possible concurrent operations will fail due to the
current state, hence the wl1271 struct should be safe. */
wl1271_disable_interrupts(wl);
wlcore_disable_interrupts(wl);
wl1271_flush_deferred_work(wl);
cancel_work_sync(&wl->netstack_work);
mutex_lock(&wl->mutex);
......@@ -2360,10 +1968,12 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
wl12xx_free_rate_policy(wl,
&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);
wl1271_free_ap_keys(wl, wlvif);
if (wl->last_wlvif == wlvif)
wl->last_wlvif = NULL;
list_del(&wlvif->list);
......@@ -2946,6 +2556,17 @@ static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
int ret;
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) {
struct wl1271_station *wl_sta;
u8 hlid;
......@@ -2984,17 +2605,6 @@ static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
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;
if (is_zero_ether_addr(addr)) {
......@@ -3791,8 +3401,7 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
wlvif->rssi_thold = bss_conf->cqm_rssi_thold;
}
if (changed & BSS_CHANGED_BSSID &&
(is_ibss || bss_conf->assoc))
if (changed & BSS_CHANGED_BSSID)
if (!is_zero_ether_addr(bss_conf->bssid)) {
ret = wl12xx_cmd_build_null_data(wl, wlvif);
if (ret < 0)
......@@ -3801,9 +3410,6 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
ret = wl1271_build_qos_null_data(wl, vif);
if (ret < 0)
goto out;
/* Need to update the BSSID (for filtering etc) */
do_join = true;
}
if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
......@@ -3830,6 +3436,7 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
int ieoffset;
wlvif->aid = bss_conf->aid;
wlvif->beacon_int = bss_conf->beacon_int;
do_join = true;
set_assoc = true;
/*
......@@ -4662,60 +4269,12 @@ static struct ieee80211_channel wl1271_channels[] = {
{ .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 */
static struct ieee80211_supported_band wl1271_band_2ghz = {
.channels = wl1271_channels,
.n_channels = ARRAY_SIZE(wl1271_channels),
.bitrates = wl1271_rates,
.n_bitrates = ARRAY_SIZE(wl1271_rates),
.ht_cap = WL12XX_HT_CAP,
};
/* 5 GHz data rates for WL1273 */
......@@ -4784,48 +4343,11 @@ static struct ieee80211_channel wl1271_channels_5ghz[] = {
{ .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 = {
.channels = wl1271_channels_5ghz,
.n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
.bitrates = 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 = {
......@@ -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;
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);
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)) {
wl1271_error("Unsupported RX rate from HW: %d", rate);
return 0;
......@@ -5027,34 +4549,6 @@ static struct bin_attribute fwlog_attr = {
.read = wl1271_sysfs_read_fwlog,
};
static bool wl12xx_mac_in_fuse(struct wl1271 *wl)
{
bool supported = false;
u8 major, minor;
if (wl->chip.id == CHIP_ID_1283_PG20) {
major = WL128X_PG_GET_MAJOR(wl->hw_pg_ver);
minor = WL128X_PG_GET_MINOR(wl->hw_pg_ver);
/* in wl128x we have the MAC address if the PG is >= (2, 1) */
if (major > 2 || (major == 2 && minor >= 1))
supported = true;
} else {
major = WL127X_PG_GET_MAJOR(wl->hw_pg_ver);
minor = WL127X_PG_GET_MINOR(wl->hw_pg_ver);
/* in wl127x we have the MAC address if the PG is >= (3, 1) */
if (major == 3 && minor >= 1)
supported = true;
}
wl1271_debug(DEBUG_PROBE,
"PG Ver major = %d minor = %d, MAC %s present",
major, minor, supported ? "is" : "is not");
return supported;
}
static void wl12xx_derive_mac_addresses(struct wl1271 *wl,
u32 oui, u32 nic, int n)
{
......@@ -5080,47 +4574,23 @@ static void wl12xx_derive_mac_addresses(struct wl1271 *wl,
wl->hw->wiphy->addresses = wl->addresses;
}
static void wl12xx_get_fuse_mac(struct wl1271 *wl)
{
u32 mac1, mac2;
wl1271_set_partition(wl, &wl12xx_part_table[PART_DRPW]);
mac1 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_1);
mac2 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_2);
/* these are the two parts of the BD_ADDR */
wl->fuse_oui_addr = ((mac2 & 0xffff) << 8) +
((mac1 & 0xff000000) >> 24);
wl->fuse_nic_addr = mac1 & 0xffffff;
wl1271_set_partition(wl, &wl12xx_part_table[PART_DOWN]);
}
static int wl12xx_get_hw_info(struct wl1271 *wl)
{
int ret;
u32 die_info;
ret = wl12xx_set_power_on(wl);
if (ret < 0)
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->fuse_oui_addr = 0;
wl->fuse_nic_addr = 0;
wl->hw_pg_ver = (s8) (die_info & PG_VER_MASK) >> PG_VER_OFFSET;
wl->hw_pg_ver = wl->ops->get_pg_ver(wl);
if (!wl12xx_mac_in_fuse(wl)) {
wl->fuse_oui_addr = 0;
wl->fuse_nic_addr = 0;
} else {
wl12xx_get_fuse_mac(wl);
}
if (wl->ops->get_mac)
wl->ops->get_mac(wl);
wl1271_power_off(wl);
out:
......@@ -5255,8 +4725,12 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
*/
memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &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,
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->bands[IEEE80211_BAND_2GHZ];
......@@ -5280,14 +4754,14 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
wl->hw->sta_data_size = sizeof(struct wl1271_station);
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;
}
#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 wl1271 *wl;
......@@ -5306,6 +4780,13 @@ static struct ieee80211_hw *wl1271_alloc_hw(void)
wl = hw->priv;
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);
wl->hw = hw;
......@@ -5342,7 +4823,6 @@ static struct ieee80211_hw *wl1271_alloc_hw(void)
wl->quirks = 0;
wl->platform_quirks = 0;
wl->sched_scanning = false;
wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
wl->system_hlid = WL12XX_SYSTEM_HLID;
wl->active_sta_count = 0;
wl->fwlog_size = 0;
......@@ -5352,7 +4832,7 @@ static struct ieee80211_hw *wl1271_alloc_hw(void)
__set_bit(WL12XX_SYSTEM_HLID, wl->links_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;
spin_lock_init(&wl->wl_lock);
......@@ -5361,9 +4841,6 @@ static struct ieee80211_hw *wl1271_alloc_hw(void)
wl->fw_type = WL12XX_FW_TYPE_NONE;
mutex_init(&wl->mutex);
/* Apply default driver configuration. */
wl1271_conf_init(wl);
order = get_order(WL1271_AGGR_BUFFER_SIZE);
wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
if (!wl->aggr_buf) {
......@@ -5384,8 +4861,17 @@ static struct ieee80211_hw *wl1271_alloc_hw(void)
goto err_dummy_packet;
}
wl->mbox = kmalloc(sizeof(*wl->mbox), GFP_DMA);
if (!wl->mbox) {
ret = -ENOMEM;
goto err_fwlog;
}
return hw;
err_fwlog:
free_page((unsigned long)wl->fwlog);
err_dummy_packet:
dev_kfree_skb(wl->dummy_packet);
......@@ -5397,14 +4883,18 @@ static struct ieee80211_hw *wl1271_alloc_hw(void)
err_hw:
wl1271_debugfs_exit(wl);
kfree(wl->priv);
err_priv_alloc:
ieee80211_free_hw(hw);
err_hw_alloc:
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 */
mutex_lock(&wl->mutex);
......@@ -5434,10 +4924,12 @@ static int wl1271_free_hw(struct wl1271 *wl)
kfree(wl->tx_res_if);
destroy_workqueue(wl->freezable_wq);
kfree(wl->priv);
ieee80211_free_hw(wl->hw);
return 0;
}
EXPORT_SYMBOL_GPL(wlcore_free_hw);
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;
}
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 ieee80211_hw *hw;
struct wl1271 *wl;
unsigned long irqflags;
int ret = -ENODEV;
int ret;
hw = wl1271_alloc_hw();
if (IS_ERR(hw)) {
wl1271_error("can't allocate hw");
ret = PTR_ERR(hw);
goto out;
if (!wl->ops || !wl->ptable) {
ret = -EINVAL;
goto out_free_hw;
}
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->ref_clock = pdata->board_ref_clock;
wl->tcxo_clock = pdata->board_tcxo_clock;
......@@ -5512,7 +5004,7 @@ static int __devinit wl12xx_probe(struct platform_device *pdev)
wl->irq_wake_enabled = true;
device_init_wakeup(wl->dev, 1);
if (pdata->pwr_in_suspend)
hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
wl->hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
}
disable_irq(wl->irq);
......@@ -5546,7 +5038,7 @@ static int __devinit wl12xx_probe(struct platform_device *pdev)
goto out_hw_pg_ver;
}
return 0;
goto out;
out_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)
free_irq(wl->irq, wl);
out_free_hw:
wl1271_free_hw(wl);
wlcore_free_hw(wl);
out:
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);
......@@ -5574,38 +5067,11 @@ static int __devexit wl12xx_remove(struct platform_device *pdev)
}
wl1271_unregister_hw(wl);
free_irq(wl->irq, wl);
wl1271_free_hw(wl);
wlcore_free_hw(wl);
return 0;
}
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);
EXPORT_SYMBOL_GPL(wlcore_remove);
u32 wl12xx_debug_level = DEBUG_NONE;
EXPORT_SYMBOL_GPL(wl12xx_debug_level);
......@@ -5619,6 +5085,9 @@ MODULE_PARM_DESC(fwlog,
module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
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_AUTHOR("Luciano Coelho <coelho@ti.com>");
MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
......@@ -21,7 +21,6 @@
*
*/
#include "reg.h"
#include "ps.h"
#include "io.h"
#include "tx.h"
......@@ -62,7 +61,7 @@ void wl1271_elp_work(struct work_struct *work)
}
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);
out:
......@@ -74,6 +73,9 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl)
{
struct wl12xx_vif *wlvif;
if (wl->quirks & WLCORE_QUIRK_NO_ELP)
return;
/* we shouldn't get consecutive sleep requests */
if (WARN_ON(test_and_set_bit(WL1271_FLAG_ELP_REQUESTED, &wl->flags)))
return;
......@@ -125,7 +127,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl)
wl->elp_compl = &compl;
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) {
ret = wait_for_completion_timeout(
......
......@@ -24,7 +24,7 @@
#ifndef __PS_H__
#define __PS_H__
#include "wl12xx.h"
#include "wlcore.h"
#include "acx.h"
int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
......
......@@ -24,34 +24,36 @@
#include <linux/gfp.h>
#include <linux/sched.h>
#include "wl12xx.h"
#include "wlcore.h"
#include "debug.h"
#include "acx.h"
#include "reg.h"
#include "rx.h"
#include "tx.h"
#include "io.h"
#include "hw_ops.h"
static u8 wl12xx_rx_get_mem_block(struct wl12xx_fw_status *status,
u32 drv_rx_counter)
{
return le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]) &
RX_MEM_BLOCK_MASK;
}
/*
* TODO: this is here just for now, it must be removed when the data
* operations are in place.
*/
#include "../wl12xx/reg.h"
static u32 wl12xx_rx_get_buf_size(struct wl12xx_fw_status *status,
u32 drv_rx_counter)
static u32 wlcore_rx_get_buf_size(struct wl1271 *wl,
u32 rx_pkt_desc)
{
return (le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]) &
RX_BUF_SIZE_MASK) >> RX_BUF_SIZE_SHIFT_DIV;
if (wl->quirks & WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN)
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,
u32 drv_rx_counter)
static u32 wlcore_rx_get_align_buf_size(struct wl1271 *wl, u32 pkt_len)
{
/* Convert the value to bool */
return !!(le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]) &
RX_BUF_UNALIGNED_PAYLOAD);
if (wl->quirks & WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN)
return ALIGN(pkt_len, WL12XX_BUS_BLOCK_SIZE);
return pkt_len;
}
static void wl1271_rx_status(struct wl1271 *wl,
......@@ -66,10 +68,10 @@ static void wl1271_rx_status(struct wl1271 *wl,
else
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 */
if (desc->rate <= CONF_HW_RXTX_RATE_MCS0)
if (desc->rate <= wl->hw_min_ht_rate)
status->flag |= RX_FLAG_HT;
status->signal = desc->rssi;
......@@ -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,
bool unaligned, u8 *hlid)
enum wl_rx_buf_align rx_align, u8 *hlid)
{
struct wl1271_rx_descriptor *desc;
struct sk_buff *skb;
......@@ -106,8 +108,9 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
u8 *buf;
u8 beacon = 0;
u8 is_data = 0;
u8 reserved = unaligned ? NET_IP_ALIGN : 0;
u8 reserved = 0;
u16 seq_num;
u32 pkt_data_len;
/*
* 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,
if (unlikely(wl->plt))
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 */
desc = (struct wl1271_rx_descriptor *) data;
......@@ -142,8 +155,8 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
return -EINVAL;
}
/* skb length not included rx descriptor */
skb = __dev_alloc_skb(length + reserved - sizeof(*desc), GFP_KERNEL);
/* skb length not including rx descriptor */
skb = __dev_alloc_skb(pkt_data_len + reserved, GFP_KERNEL);
if (!skb) {
wl1271_error("Couldn't allocate RX frame");
return -ENOMEM;
......@@ -152,7 +165,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
/* reserve the unaligned payload(if any) */
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
......@@ -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
* 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;
hdr = (struct ieee80211_hdr *)skb->data;
......@@ -177,36 +193,35 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
beacon ? "beacon" : "",
seq_num, *hlid);
skb_trim(skb, skb->len - desc->pad_len);
skb_queue_tail(&wl->deferred_rx_queue, skb);
queue_work(wl->freezable_wq, &wl->netstack_work);
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};
u32 buf_size;
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 rx_counter;
u32 mem_block;
u32 pkt_length;
u32 pkt_offset;
u32 pkt_len, align_pkt_len;
u32 pkt_offset, des;
u8 hlid;
bool unaligned = false;
enum wl_rx_buf_align rx_align;
while (drv_rx_counter != fw_rx_counter) {
buf_size = 0;
rx_counter = drv_rx_counter;
while (rx_counter != fw_rx_counter) {
pkt_length = wl12xx_rx_get_buf_size(status, rx_counter);
if (buf_size + pkt_length > WL1271_AGGR_BUFFER_SIZE)
des = le32_to_cpu(status->rx_pkt_descs[rx_counter]);
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;
buf_size += pkt_length;
buf_size += align_pkt_len;
rx_counter++;
rx_counter &= NUM_RX_PKT_DESC_MOD_MASK;
}
......@@ -216,38 +231,18 @@ void wl12xx_rx(struct wl1271 *wl, struct wl12xx_fw_status *status)
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 */
wl1271_read(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf,
buf_size, true);
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);
/* Split data into separate packets */
pkt_offset = 0;
while (pkt_offset < buf_size) {
pkt_length = wl12xx_rx_get_buf_size(status,
drv_rx_counter);
unaligned = wl12xx_rx_get_unaligned(status,
drv_rx_counter);
des = le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]);
pkt_len = wlcore_rx_get_buf_size(wl, des);
rx_align = wlcore_hw_get_rx_buf_align(wl, des);
/*
* 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)
*/
if (wl1271_rx_handle_data(wl,
wl->aggr_buf + pkt_offset,
pkt_length, unaligned,
pkt_len, rx_align,
&hlid) == 1) {
if (hlid < WL12XX_MAX_LINKS)
__set_bit(hlid, active_hlids);
......@@ -269,7 +264,7 @@ void wl12xx_rx(struct wl1271 *wl, struct wl12xx_fw_status *status)
wl->rx_counter++;
drv_rx_counter++;
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)
* Write the driver's packet counter to the FW. This is only required
* for older hardware revisions
*/
if (wl->quirks & WL12XX_QUIRK_END_OF_TRANSACTION)
wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter);
if (wl->quirks & WLCORE_QUIRK_END_OF_TRANSACTION)
wl1271_write32(wl, WL12XX_REG_RX_DRIVER_COUNTER,
wl->rx_counter);
wl12xx_rearm_rx_streaming(wl, active_hlids);
}
......@@ -96,9 +96,19 @@
#define RX_MEM_BLOCK_MASK 0xFF
#define RX_BUF_SIZE_MASK 0xFFF00
#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 */
#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 {
WL12XX_RX_CLASS_UNKNOWN,
WL12XX_RX_CLASS_MANAGEMENT,
......@@ -126,7 +136,7 @@ struct wl1271_rx_descriptor {
u8 reserved;
} __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);
#endif
......@@ -23,7 +23,7 @@
#include <linux/ieee80211.h>
#include "wl12xx.h"
#include "wlcore.h"
#include "debug.h"
#include "cmd.h"
#include "scan.h"
......@@ -417,6 +417,23 @@ wl1271_scan_get_sched_scan_channels(struct wl1271 *wl,
int i, j;
u32 flags;
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;
i < req->n_channels && j < max_channels;
......@@ -440,21 +457,24 @@ wl1271_scan_get_sched_scan_channels(struct wl1271 *wl,
req->channels[i]->flags);
wl1271_debug(DEBUG_SCAN, "max_power %d",
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) {
channels[j].flags |= SCAN_CHANNEL_FLAGS_DFS;
channels[j].passive_duration =
cpu_to_le16(c->dwell_time_dfs);
cpu_to_le16(dwell_time_dfs);
} else {
channels[j].passive_duration =
cpu_to_le16(c->dwell_time_passive);
cpu_to_le16(dwell_time_passive);
}
channels[j].min_duration =
cpu_to_le16(c->min_dwell_time_active);
cpu_to_le16(min_dwell_time_active);
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].channel = req->channels[i]->hw_value;
......
......@@ -24,7 +24,7 @@
#ifndef __SCAN_H__
#define __SCAN_H__
#include "wl12xx.h"
#include "wlcore.h"
int wl1271_scan(struct wl1271 *wl, struct ieee80211_vif *vif,
const u8 *ssid, size_t ssid_len,
......@@ -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_5_GHZ 1
#define WL1271_SCAN_TIMEOUT 10000 /* msec */
#define WL1271_SCAN_TIMEOUT 30000 /* msec */
enum {
WL1271_SCAN_STATE_IDLE,
......
......@@ -33,7 +33,7 @@
#include <linux/wl12xx.h>
#include <linux/pm_runtime.h>
#include "wl12xx.h"
#include "wlcore.h"
#include "wl12xx_80211.h"
#include "io.h"
......@@ -76,7 +76,7 @@ static void wl12xx_sdio_raw_read(struct device *child, int addr, void *buf,
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);
dev_dbg(child->parent, "sdio read 52 addr 0x%x, byte 0x%02x\n",
addr, ((u8 *)buf)[0]);
......@@ -105,7 +105,7 @@ static void wl12xx_sdio_raw_write(struct device *child, int addr, void *buf,
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);
dev_dbg(child->parent, "sdio write 52 addr 0x%x, byte 0x%02x\n",
addr, ((u8 *)buf)[0]);
......
......@@ -30,12 +30,10 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include "wl12xx.h"
#include "wlcore.h"
#include "wl12xx_80211.h"
#include "io.h"
#include "reg.h"
#define WSPI_CMD_READ 0x40000000
#define WSPI_CMD_WRITE 0x00000000
#define WSPI_CMD_FIXED 0x20000000
......
......@@ -25,10 +25,9 @@
#include <linux/slab.h>
#include <net/genetlink.h>
#include "wl12xx.h"
#include "wlcore.h"
#include "debug.h"
#include "acx.h"
#include "reg.h"
#include "ps.h"
#include "io.h"
......
......@@ -25,13 +25,19 @@
#include <linux/module.h>
#include <linux/etherdevice.h>
#include "wl12xx.h"
#include "wlcore.h"
#include "debug.h"
#include "io.h"
#include "reg.h"
#include "ps.h"
#include "tx.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,
struct wl12xx_vif *wlvif, u8 id)
......@@ -56,8 +62,8 @@ static int wl1271_alloc_tx_id(struct wl1271 *wl, struct sk_buff *skb)
{
int id;
id = find_first_zero_bit(wl->tx_frames_map, ACX_TX_DESCRIPTORS);
if (id >= ACX_TX_DESCRIPTORS)
id = find_first_zero_bit(wl->tx_frames_map, wl->num_tx_desc);
if (id >= wl->num_tx_desc)
return -EBUSY;
__set_bit(id, wl->tx_frames_map);
......@@ -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)
{
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);
wl->tx_frames[id] = NULL;
......@@ -167,14 +173,15 @@ u8 wl12xx_tx_get_hlid(struct wl1271 *wl, struct wl12xx_vif *wlvif,
return wlvif->dev_hlid;
}
static unsigned int wl12xx_calc_packet_alignment(struct wl1271 *wl,
unsigned int packet_length)
unsigned int wlcore_calc_packet_alignment(struct wl1271 *wl,
unsigned int packet_length)
{
if (wl->quirks & WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT)
return ALIGN(packet_length, WL1271_TX_ALIGN_TO);
else
if (wl->quirks & WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN)
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,
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,
{
struct wl1271_tx_hw_descr *desc;
u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra;
u32 len;
u32 total_blocks;
int id, ret = -EBUSY, ac;
u32 spare_blocks = wl->tx_spare_blocks;
u32 spare_blocks = wl->normal_tx_spare;
bool is_dummy = false;
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,
if (id < 0)
return id;
/* approximate the number of blocks required for this packet
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))) {
if (unlikely(wl12xx_is_dummy_packet(wl, skb)))
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 +
spare_blocks;
total_blocks = wlcore_hw_calc_tx_blocks(wl, total_len, spare_blocks);
if (total_blocks <= wl->tx_blocks_available) {
desc = (struct wl1271_tx_hw_descr *)skb_push(
skb, total_len - skb->len);
/* HW descriptor fields change between wl127x and wl128x */
if (wl->chip.id == CHIP_ID_1283_PG20) {
desc->wl128x_mem.total_mem_blocks = total_blocks;
} else {
desc->wl127x_mem.extra_blocks = spare_blocks;
desc->wl127x_mem.total_mem_blocks = total_blocks;
}
wlcore_hw_set_tx_desc_blocks(wl, desc, total_blocks,
spare_blocks);
desc->id = id;
......@@ -256,7 +251,7 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif,
{
struct timespec ts;
struct wl1271_tx_hw_descr *desc;
int aligned_len, ac, rate_idx;
int ac, rate_idx;
s64 hosttime;
u16 tx_attr = 0;
__le16 frame_control;
......@@ -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;
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 */
if (ieee80211_is_auth(frame_control) &&
ieee80211_has_protected(frame_control))
tx_attr |= TX_HW_ATTR_HOST_ENCRYPT;
desc->reserved = 0;
desc->tx_attr = cpu_to_le16(tx_attr);
wlcore_hw_set_tx_desc_data_len(wl, desc, skb);
}
/* caller must hold wl->mutex */
......@@ -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
* (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);
memset(wl->aggr_buf + buf_offset + skb->len, 0, total_len - skb->len);
......@@ -718,8 +685,8 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
* Flush buffer and try again.
*/
wl1271_skb_queue_head(wl, wlvif, skb);
wl1271_write(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf,
buf_offset, true);
wlcore_write_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf,
buf_offset, true);
sent_packets = true;
buf_offset = 0;
continue;
......@@ -753,8 +720,8 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
out_ack:
if (buf_offset) {
wl1271_write(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf,
buf_offset, true);
wlcore_write_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf,
buf_offset, true);
sent_packets = true;
}
if (sent_packets) {
......@@ -762,8 +729,8 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
* Interrupt the firmware with the new packets. This is only
* required for older hardware revisions
*/
if (wl->quirks & WL12XX_QUIRK_END_OF_TRANSACTION)
wl1271_write32(wl, WL1271_HOST_WR_ACCESS,
if (wl->quirks & WLCORE_QUIRK_END_OF_TRANSACTION)
wl1271_write32(wl, WL12XX_HOST_WR_ACCESS,
wl->tx_packets_count);
wl1271_handle_tx_low_watermark(wl);
......@@ -792,11 +759,20 @@ static u8 wl1271_tx_get_rate_flags(u8 rate_class_index)
{
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;
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;
return flags;
}
......@@ -813,7 +789,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
u8 retries = 0;
/* 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);
return;
}
......@@ -834,7 +810,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
if (result->status == TX_SUCCESS) {
if (!(info->flags & IEEE80211_TX_CTL_NO_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);
rate_flags = wl1271_tx_get_rate_flags(result->rate_class_index);
retries = result->ack_failures;
......@@ -929,6 +905,7 @@ void wl1271_tx_complete(struct wl1271 *wl)
wl->tx_results_count++;
}
}
EXPORT_SYMBOL(wl1271_tx_complete);
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)
if (reset_tx_queues)
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)
continue;
......
......@@ -25,9 +25,6 @@
#ifndef __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_AP_MODE_PKT_LIFETIME_TU 8000
......@@ -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(struct wl1271 *wl, bool reset_tx_queues);
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,
enum ieee80211_band rate_band);
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);
void wl1271_handle_tx_low_watermark(struct wl1271 *wl);
bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb);
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 */
void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid);
......
......@@ -89,8 +89,6 @@
#define WL1271_AP_BSS_INDEX 0
#define WL1271_AP_DEF_BEACON_EXP 20
#define ACX_TX_DESCRIPTORS 16
#define WL1271_AGGR_BUFFER_SIZE (4 * PAGE_SIZE)
enum wl1271_state {
......@@ -105,26 +103,6 @@ enum wl12xx_fw_type {
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;
enum {
......@@ -167,8 +145,21 @@ struct wl1271_stats {
#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 */
struct wl12xx_fw_status {
struct wl_fw_status {
__le32 intr;
u8 fw_rx_counter;
u8 drv_rx_counter;
......@@ -195,16 +186,12 @@ struct wl12xx_fw_status {
/* Size (in Memory Blocks) of TX pool */
__le32 tx_total;
/* Cumulative counter of released packets per AC */
u8 tx_released_pkts[NUM_TX_QUEUES];
struct wl_fw_packet_counters counters;
/* 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;
/* Private status to be used by the lower drivers */
u8 priv[0];
} __packed;
struct wl1271_rx_mem_pool_addr {
......@@ -292,214 +279,6 @@ struct wl1271_link {
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 {
u8 hlid;
};
......@@ -605,6 +384,9 @@ struct wl12xx_vif {
struct work_struct rx_streaming_disable_work;
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!
* 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);
#define HW_BG_RATES_MASK 0xffff
#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
#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