mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-06 10:57:46 +00:00
Merge branch 'wl12xx-next' into for-linville
This commit is contained in:
commit
916ef361ce
85 changed files with 3797 additions and 2921 deletions
27
MAINTAINERS
27
MAINTAINERS
|
@ -6660,6 +6660,16 @@ L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: sound/soc/codecs/twl4030*
|
F: sound/soc/codecs/twl4030*
|
||||||
|
|
||||||
|
TI WILINK WIRELESS DRIVERS
|
||||||
|
M: Luciano Coelho <coelho@ti.com>
|
||||||
|
L: linux-wireless@vger.kernel.org
|
||||||
|
W: http://wireless.kernel.org/en/users/Drivers/wl12xx
|
||||||
|
W: http://wireless.kernel.org/en/users/Drivers/wl1251
|
||||||
|
T: git git://git.kernel.org/pub/scm/linux/kernel/git/luca/wl12xx.git
|
||||||
|
S: Maintained
|
||||||
|
F: drivers/net/wireless/ti/
|
||||||
|
F: include/linux/wl12xx.h
|
||||||
|
|
||||||
TIPC NETWORK LAYER
|
TIPC NETWORK LAYER
|
||||||
M: Jon Maloy <jon.maloy@ericsson.com>
|
M: Jon Maloy <jon.maloy@ericsson.com>
|
||||||
M: Allan Stephens <allan.stephens@windriver.com>
|
M: Allan Stephens <allan.stephens@windriver.com>
|
||||||
|
@ -7416,23 +7426,6 @@ M: Miloslav Trmac <mitr@volny.cz>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: drivers/input/misc/wistron_btns.c
|
F: drivers/input/misc/wistron_btns.c
|
||||||
|
|
||||||
WL1251 WIRELESS DRIVER
|
|
||||||
M: Luciano Coelho <coelho@ti.com>
|
|
||||||
L: linux-wireless@vger.kernel.org
|
|
||||||
W: http://wireless.kernel.org/en/users/Drivers/wl1251
|
|
||||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
|
|
||||||
S: Maintained
|
|
||||||
F: drivers/net/wireless/wl1251/*
|
|
||||||
|
|
||||||
WL1271 WIRELESS DRIVER
|
|
||||||
M: Luciano Coelho <coelho@ti.com>
|
|
||||||
L: linux-wireless@vger.kernel.org
|
|
||||||
W: http://wireless.kernel.org/en/users/Drivers/wl12xx
|
|
||||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/luca/wl12xx.git
|
|
||||||
S: Maintained
|
|
||||||
F: drivers/net/wireless/wl12xx/
|
|
||||||
F: include/linux/wl12xx.h
|
|
||||||
|
|
||||||
WL3501 WIRELESS PCMCIA CARD DRIVER
|
WL3501 WIRELESS PCMCIA CARD DRIVER
|
||||||
M: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
|
M: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
|
||||||
L: linux-wireless@vger.kernel.org
|
L: linux-wireless@vger.kernel.org
|
||||||
|
|
|
@ -282,8 +282,7 @@ source "drivers/net/wireless/orinoco/Kconfig"
|
||||||
source "drivers/net/wireless/p54/Kconfig"
|
source "drivers/net/wireless/p54/Kconfig"
|
||||||
source "drivers/net/wireless/rt2x00/Kconfig"
|
source "drivers/net/wireless/rt2x00/Kconfig"
|
||||||
source "drivers/net/wireless/rtlwifi/Kconfig"
|
source "drivers/net/wireless/rtlwifi/Kconfig"
|
||||||
source "drivers/net/wireless/wl1251/Kconfig"
|
source "drivers/net/wireless/ti/Kconfig"
|
||||||
source "drivers/net/wireless/wl12xx/Kconfig"
|
|
||||||
source "drivers/net/wireless/zd1211rw/Kconfig"
|
source "drivers/net/wireless/zd1211rw/Kconfig"
|
||||||
source "drivers/net/wireless/mwifiex/Kconfig"
|
source "drivers/net/wireless/mwifiex/Kconfig"
|
||||||
|
|
||||||
|
|
|
@ -51,9 +51,7 @@ obj-$(CONFIG_ATH_COMMON) += ath/
|
||||||
|
|
||||||
obj-$(CONFIG_MAC80211_HWSIM) += mac80211_hwsim.o
|
obj-$(CONFIG_MAC80211_HWSIM) += mac80211_hwsim.o
|
||||||
|
|
||||||
obj-$(CONFIG_WL1251) += wl1251/
|
obj-$(CONFIG_WL_TI) += ti/
|
||||||
obj-$(CONFIG_WL12XX) += wl12xx/
|
|
||||||
obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx/
|
|
||||||
|
|
||||||
obj-$(CONFIG_IWM) += iwmc3200wifi/
|
obj-$(CONFIG_IWM) += iwmc3200wifi/
|
||||||
|
|
||||||
|
|
14
drivers/net/wireless/ti/Kconfig
Normal file
14
drivers/net/wireless/ti/Kconfig
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
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
|
4
drivers/net/wireless/ti/Makefile
Normal file
4
drivers/net/wireless/ti/Makefile
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
obj-$(CONFIG_WLCORE) += wlcore/
|
||||||
|
obj-$(CONFIG_WL12XX) += wl12xx/
|
||||||
|
obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wlcore/
|
||||||
|
obj-$(CONFIG_WL1251) += wl1251/
|
8
drivers/net/wireless/ti/wl12xx/Kconfig
Normal file
8
drivers/net/wireless/ti/wl12xx/Kconfig
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
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.
|
3
drivers/net/wireless/ti/wl12xx/Makefile
Normal file
3
drivers/net/wireless/ti/wl12xx/Makefile
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
wl12xx-objs = main.o cmd.o acx.o
|
||||||
|
|
||||||
|
obj-$(CONFIG_WL12XX) += wl12xx.o
|
53
drivers/net/wireless/ti/wl12xx/acx.c
Normal file
53
drivers/net/wireless/ti/wl12xx/acx.c
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
36
drivers/net/wireless/ti/wl12xx/acx.h
Normal file
36
drivers/net/wireless/ti/wl12xx/acx.h
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* 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__ */
|
254
drivers/net/wireless/ti/wl12xx/cmd.c
Normal file
254
drivers/net/wireless/ti/wl12xx/cmd.c
Normal file
|
@ -0,0 +1,254 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
112
drivers/net/wireless/ti/wl12xx/cmd.h
Normal file
112
drivers/net/wireless/ti/wl12xx/cmd.h
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
/*
|
||||||
|
* 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__ */
|
50
drivers/net/wireless/ti/wl12xx/conf.h
Normal file
50
drivers/net/wireless/ti/wl12xx/conf.h
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* 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__ */
|
1388
drivers/net/wireless/ti/wl12xx/main.c
Normal file
1388
drivers/net/wireless/ti/wl12xx/main.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -33,16 +33,8 @@
|
||||||
#define REGISTERS_DOWN_SIZE 0x00008800
|
#define REGISTERS_DOWN_SIZE 0x00008800
|
||||||
#define REGISTERS_WORK_SIZE 0x0000b000
|
#define REGISTERS_WORK_SIZE 0x0000b000
|
||||||
|
|
||||||
#define HW_ACCESS_ELP_CTRL_REG_ADDR 0x1FFFC
|
|
||||||
#define FW_STATUS_ADDR (0x14FC0 + 0xA000)
|
#define FW_STATUS_ADDR (0x14FC0 + 0xA000)
|
||||||
|
|
||||||
/* ELP register commands */
|
|
||||||
#define ELPCTRL_WAKE_UP 0x1
|
|
||||||
#define ELPCTRL_WAKE_UP_WLAN_READY 0x5
|
|
||||||
#define ELPCTRL_SLEEP 0x0
|
|
||||||
/* ELP WLAN_READY bit */
|
|
||||||
#define ELPCTRL_WLAN_READY 0x2
|
|
||||||
|
|
||||||
/*===============================================
|
/*===============================================
|
||||||
Host Software Reset - 32bit RW
|
Host Software Reset - 32bit RW
|
||||||
------------------------------------------
|
------------------------------------------
|
||||||
|
@ -57,14 +49,14 @@
|
||||||
(not self-clearing), the Wlan hardware
|
(not self-clearing), the Wlan hardware
|
||||||
exits the software reset state.
|
exits the software reset state.
|
||||||
===============================================*/
|
===============================================*/
|
||||||
#define ACX_REG_SLV_SOFT_RESET (REGISTERS_BASE + 0x0000)
|
#define WL12XX_SLV_SOFT_RESET (REGISTERS_BASE + 0x0000)
|
||||||
|
|
||||||
#define WL1271_SLV_REG_DATA (REGISTERS_BASE + 0x0008)
|
#define WL1271_SLV_REG_DATA (REGISTERS_BASE + 0x0008)
|
||||||
#define WL1271_SLV_REG_ADATA (REGISTERS_BASE + 0x000c)
|
#define WL1271_SLV_REG_ADATA (REGISTERS_BASE + 0x000c)
|
||||||
#define WL1271_SLV_MEM_DATA (REGISTERS_BASE + 0x0018)
|
#define WL1271_SLV_MEM_DATA (REGISTERS_BASE + 0x0018)
|
||||||
|
|
||||||
#define ACX_REG_INTERRUPT_TRIG (REGISTERS_BASE + 0x0474)
|
#define WL12XX_REG_INTERRUPT_TRIG (REGISTERS_BASE + 0x0474)
|
||||||
#define ACX_REG_INTERRUPT_TRIG_H (REGISTERS_BASE + 0x0478)
|
#define WL12XX_REG_INTERRUPT_TRIG_H (REGISTERS_BASE + 0x0478)
|
||||||
|
|
||||||
/*=============================================
|
/*=============================================
|
||||||
Host Interrupt Mask Register - 32bit (RW)
|
Host Interrupt Mask Register - 32bit (RW)
|
||||||
|
@ -94,7 +86,7 @@
|
||||||
21- -
|
21- -
|
||||||
Default: 0x0001
|
Default: 0x0001
|
||||||
*==============================================*/
|
*==============================================*/
|
||||||
#define ACX_REG_INTERRUPT_MASK (REGISTERS_BASE + 0x04DC)
|
#define WL12XX_REG_INTERRUPT_MASK (REGISTERS_BASE + 0x04DC)
|
||||||
|
|
||||||
/*=============================================
|
/*=============================================
|
||||||
Host Interrupt Mask Set 16bit, (Write only)
|
Host Interrupt Mask Set 16bit, (Write only)
|
||||||
|
@ -125,7 +117,7 @@
|
||||||
Reading this register doesn't
|
Reading this register doesn't
|
||||||
effect its content.
|
effect its content.
|
||||||
=============================================*/
|
=============================================*/
|
||||||
#define ACX_REG_INTERRUPT_NO_CLEAR (REGISTERS_BASE + 0x04E8)
|
#define WL12XX_REG_INTERRUPT_NO_CLEAR (REGISTERS_BASE + 0x04E8)
|
||||||
|
|
||||||
/*=============================================
|
/*=============================================
|
||||||
Host Interrupt Status Clear on Read Register
|
Host Interrupt Status Clear on Read Register
|
||||||
|
@ -148,9 +140,9 @@
|
||||||
HINT_STS_ND registers, thus making the
|
HINT_STS_ND registers, thus making the
|
||||||
assotiated interrupt inactive. (0-no effect)
|
assotiated interrupt inactive. (0-no effect)
|
||||||
==============================================*/
|
==============================================*/
|
||||||
#define ACX_REG_INTERRUPT_ACK (REGISTERS_BASE + 0x04F0)
|
#define WL12XX_REG_INTERRUPT_ACK (REGISTERS_BASE + 0x04F0)
|
||||||
|
|
||||||
#define RX_DRIVER_COUNTER_ADDRESS (REGISTERS_BASE + 0x0538)
|
#define WL12XX_REG_RX_DRIVER_COUNTER (REGISTERS_BASE + 0x0538)
|
||||||
|
|
||||||
/* Device Configuration registers*/
|
/* Device Configuration registers*/
|
||||||
#define SOR_CFG (REGISTERS_BASE + 0x0800)
|
#define SOR_CFG (REGISTERS_BASE + 0x0800)
|
||||||
|
@ -175,9 +167,9 @@
|
||||||
1 halt eCPU
|
1 halt eCPU
|
||||||
0 enable eCPU
|
0 enable eCPU
|
||||||
===============================================*/
|
===============================================*/
|
||||||
#define ACX_REG_ECPU_CONTROL (REGISTERS_BASE + 0x0804)
|
#define WL12XX_REG_ECPU_CONTROL (REGISTERS_BASE + 0x0804)
|
||||||
|
|
||||||
#define HI_CFG (REGISTERS_BASE + 0x0808)
|
#define WL12XX_HI_CFG (REGISTERS_BASE + 0x0808)
|
||||||
|
|
||||||
/*===============================================
|
/*===============================================
|
||||||
EEPROM Burst Read Start - 32bit RW
|
EEPROM Burst Read Start - 32bit RW
|
||||||
|
@ -196,72 +188,67 @@
|
||||||
*================================================*/
|
*================================================*/
|
||||||
#define ACX_REG_EE_START (REGISTERS_BASE + 0x080C)
|
#define ACX_REG_EE_START (REGISTERS_BASE + 0x080C)
|
||||||
|
|
||||||
#define OCP_POR_CTR (REGISTERS_BASE + 0x09B4)
|
#define WL12XX_OCP_POR_CTR (REGISTERS_BASE + 0x09B4)
|
||||||
#define OCP_DATA_WRITE (REGISTERS_BASE + 0x09B8)
|
#define WL12XX_OCP_DATA_WRITE (REGISTERS_BASE + 0x09B8)
|
||||||
#define OCP_DATA_READ (REGISTERS_BASE + 0x09BC)
|
#define WL12XX_OCP_DATA_READ (REGISTERS_BASE + 0x09BC)
|
||||||
#define OCP_CMD (REGISTERS_BASE + 0x09C0)
|
#define WL12XX_OCP_CMD (REGISTERS_BASE + 0x09C0)
|
||||||
|
|
||||||
#define WL1271_HOST_WR_ACCESS (REGISTERS_BASE + 0x09F8)
|
#define WL12XX_HOST_WR_ACCESS (REGISTERS_BASE + 0x09F8)
|
||||||
|
|
||||||
#define CHIP_ID_B (REGISTERS_BASE + 0x5674)
|
#define WL12XX_CHIP_ID_B (REGISTERS_BASE + 0x5674)
|
||||||
|
|
||||||
#define CHIP_ID_1271_PG10 (0x4030101)
|
#define WL12XX_ENABLE (REGISTERS_BASE + 0x5450)
|
||||||
#define CHIP_ID_1271_PG20 (0x4030111)
|
|
||||||
#define CHIP_ID_1283_PG10 (0x05030101)
|
|
||||||
#define CHIP_ID_1283_PG20 (0x05030111)
|
|
||||||
|
|
||||||
#define ENABLE (REGISTERS_BASE + 0x5450)
|
|
||||||
|
|
||||||
/* Power Management registers */
|
/* Power Management registers */
|
||||||
#define ELP_CFG_MODE (REGISTERS_BASE + 0x5804)
|
#define WL12XX_ELP_CFG_MODE (REGISTERS_BASE + 0x5804)
|
||||||
#define ELP_CMD (REGISTERS_BASE + 0x5808)
|
#define WL12XX_ELP_CMD (REGISTERS_BASE + 0x5808)
|
||||||
#define PLL_CAL_TIME (REGISTERS_BASE + 0x5810)
|
#define WL12XX_PLL_CAL_TIME (REGISTERS_BASE + 0x5810)
|
||||||
#define CLK_REQ_TIME (REGISTERS_BASE + 0x5814)
|
#define WL12XX_CLK_REQ_TIME (REGISTERS_BASE + 0x5814)
|
||||||
#define CLK_BUF_TIME (REGISTERS_BASE + 0x5818)
|
#define WL12XX_CLK_BUF_TIME (REGISTERS_BASE + 0x5818)
|
||||||
|
|
||||||
#define CFG_PLL_SYNC_CNT (REGISTERS_BASE + 0x5820)
|
#define WL12XX_CFG_PLL_SYNC_CNT (REGISTERS_BASE + 0x5820)
|
||||||
|
|
||||||
/* Scratch Pad registers*/
|
/* Scratch Pad registers*/
|
||||||
#define SCR_PAD0 (REGISTERS_BASE + 0x5608)
|
#define WL12XX_SCR_PAD0 (REGISTERS_BASE + 0x5608)
|
||||||
#define SCR_PAD1 (REGISTERS_BASE + 0x560C)
|
#define WL12XX_SCR_PAD1 (REGISTERS_BASE + 0x560C)
|
||||||
#define SCR_PAD2 (REGISTERS_BASE + 0x5610)
|
#define WL12XX_SCR_PAD2 (REGISTERS_BASE + 0x5610)
|
||||||
#define SCR_PAD3 (REGISTERS_BASE + 0x5614)
|
#define WL12XX_SCR_PAD3 (REGISTERS_BASE + 0x5614)
|
||||||
#define SCR_PAD4 (REGISTERS_BASE + 0x5618)
|
#define WL12XX_SCR_PAD4 (REGISTERS_BASE + 0x5618)
|
||||||
#define SCR_PAD4_SET (REGISTERS_BASE + 0x561C)
|
#define WL12XX_SCR_PAD4_SET (REGISTERS_BASE + 0x561C)
|
||||||
#define SCR_PAD4_CLR (REGISTERS_BASE + 0x5620)
|
#define WL12XX_SCR_PAD4_CLR (REGISTERS_BASE + 0x5620)
|
||||||
#define SCR_PAD5 (REGISTERS_BASE + 0x5624)
|
#define WL12XX_SCR_PAD5 (REGISTERS_BASE + 0x5624)
|
||||||
#define SCR_PAD5_SET (REGISTERS_BASE + 0x5628)
|
#define WL12XX_SCR_PAD5_SET (REGISTERS_BASE + 0x5628)
|
||||||
#define SCR_PAD5_CLR (REGISTERS_BASE + 0x562C)
|
#define WL12XX_SCR_PAD5_CLR (REGISTERS_BASE + 0x562C)
|
||||||
#define SCR_PAD6 (REGISTERS_BASE + 0x5630)
|
#define WL12XX_SCR_PAD6 (REGISTERS_BASE + 0x5630)
|
||||||
#define SCR_PAD7 (REGISTERS_BASE + 0x5634)
|
#define WL12XX_SCR_PAD7 (REGISTERS_BASE + 0x5634)
|
||||||
#define SCR_PAD8 (REGISTERS_BASE + 0x5638)
|
#define WL12XX_SCR_PAD8 (REGISTERS_BASE + 0x5638)
|
||||||
#define SCR_PAD9 (REGISTERS_BASE + 0x563C)
|
#define WL12XX_SCR_PAD9 (REGISTERS_BASE + 0x563C)
|
||||||
|
|
||||||
/* Spare registers*/
|
/* Spare registers*/
|
||||||
#define SPARE_A1 (REGISTERS_BASE + 0x0994)
|
#define WL12XX_SPARE_A1 (REGISTERS_BASE + 0x0994)
|
||||||
#define SPARE_A2 (REGISTERS_BASE + 0x0998)
|
#define WL12XX_SPARE_A2 (REGISTERS_BASE + 0x0998)
|
||||||
#define SPARE_A3 (REGISTERS_BASE + 0x099C)
|
#define WL12XX_SPARE_A3 (REGISTERS_BASE + 0x099C)
|
||||||
#define SPARE_A4 (REGISTERS_BASE + 0x09A0)
|
#define WL12XX_SPARE_A4 (REGISTERS_BASE + 0x09A0)
|
||||||
#define SPARE_A5 (REGISTERS_BASE + 0x09A4)
|
#define WL12XX_SPARE_A5 (REGISTERS_BASE + 0x09A4)
|
||||||
#define SPARE_A6 (REGISTERS_BASE + 0x09A8)
|
#define WL12XX_SPARE_A6 (REGISTERS_BASE + 0x09A8)
|
||||||
#define SPARE_A7 (REGISTERS_BASE + 0x09AC)
|
#define WL12XX_SPARE_A7 (REGISTERS_BASE + 0x09AC)
|
||||||
#define SPARE_A8 (REGISTERS_BASE + 0x09B0)
|
#define WL12XX_SPARE_A8 (REGISTERS_BASE + 0x09B0)
|
||||||
#define SPARE_B1 (REGISTERS_BASE + 0x5420)
|
#define WL12XX_SPARE_B1 (REGISTERS_BASE + 0x5420)
|
||||||
#define SPARE_B2 (REGISTERS_BASE + 0x5424)
|
#define WL12XX_SPARE_B2 (REGISTERS_BASE + 0x5424)
|
||||||
#define SPARE_B3 (REGISTERS_BASE + 0x5428)
|
#define WL12XX_SPARE_B3 (REGISTERS_BASE + 0x5428)
|
||||||
#define SPARE_B4 (REGISTERS_BASE + 0x542C)
|
#define WL12XX_SPARE_B4 (REGISTERS_BASE + 0x542C)
|
||||||
#define SPARE_B5 (REGISTERS_BASE + 0x5430)
|
#define WL12XX_SPARE_B5 (REGISTERS_BASE + 0x5430)
|
||||||
#define SPARE_B6 (REGISTERS_BASE + 0x5434)
|
#define WL12XX_SPARE_B6 (REGISTERS_BASE + 0x5434)
|
||||||
#define SPARE_B7 (REGISTERS_BASE + 0x5438)
|
#define WL12XX_SPARE_B7 (REGISTERS_BASE + 0x5438)
|
||||||
#define SPARE_B8 (REGISTERS_BASE + 0x543C)
|
#define WL12XX_SPARE_B8 (REGISTERS_BASE + 0x543C)
|
||||||
|
|
||||||
#define PLL_PARAMETERS (REGISTERS_BASE + 0x6040)
|
#define WL12XX_PLL_PARAMETERS (REGISTERS_BASE + 0x6040)
|
||||||
#define WU_COUNTER_PAUSE (REGISTERS_BASE + 0x6008)
|
#define WL12XX_WU_COUNTER_PAUSE (REGISTERS_BASE + 0x6008)
|
||||||
#define WELP_ARM_COMMAND (REGISTERS_BASE + 0x6100)
|
#define WL12XX_WELP_ARM_COMMAND (REGISTERS_BASE + 0x6100)
|
||||||
#define DRPW_SCRATCH_START (DRPW_BASE + 0x002C)
|
#define WL12XX_DRPW_SCRATCH_START (DRPW_BASE + 0x002C)
|
||||||
|
|
||||||
|
#define WL12XX_CMD_MBOX_ADDRESS 0x407B4
|
||||||
|
|
||||||
#define ACX_SLV_SOFT_RESET_BIT BIT(1)
|
|
||||||
#define ACX_REG_EEPROM_START_BIT BIT(1)
|
#define ACX_REG_EEPROM_START_BIT BIT(1)
|
||||||
|
|
||||||
/* Command/Information Mailbox Pointers */
|
/* Command/Information Mailbox Pointers */
|
||||||
|
@ -279,7 +266,7 @@
|
||||||
the host receives the Init Complete interrupt from
|
the host receives the Init Complete interrupt from
|
||||||
the Wlan hardware.
|
the Wlan hardware.
|
||||||
===============================================*/
|
===============================================*/
|
||||||
#define REG_COMMAND_MAILBOX_PTR (SCR_PAD0)
|
#define WL12XX_REG_COMMAND_MAILBOX_PTR (WL12XX_SCR_PAD0)
|
||||||
|
|
||||||
/*===============================================
|
/*===============================================
|
||||||
Information Mailbox Pointer - 32bit RW
|
Information Mailbox Pointer - 32bit RW
|
||||||
|
@ -294,7 +281,7 @@
|
||||||
until after the host receives the Init Complete interrupt from
|
until after the host receives the Init Complete interrupt from
|
||||||
the Wlan hardware.
|
the Wlan hardware.
|
||||||
===============================================*/
|
===============================================*/
|
||||||
#define REG_EVENT_MAILBOX_PTR (SCR_PAD1)
|
#define WL12XX_REG_EVENT_MAILBOX_PTR (WL12XX_SCR_PAD1)
|
||||||
|
|
||||||
/*===============================================
|
/*===============================================
|
||||||
EEPROM Read/Write Request 32bit RW
|
EEPROM Read/Write Request 32bit RW
|
||||||
|
@ -365,26 +352,6 @@
|
||||||
#define ACX_CONT_WIND_MIN_MASK 0x0000007f
|
#define ACX_CONT_WIND_MIN_MASK 0x0000007f
|
||||||
#define ACX_CONT_WIND_MAX 0x03ff0000
|
#define ACX_CONT_WIND_MAX 0x03ff0000
|
||||||
|
|
||||||
/*===============================================
|
|
||||||
HI_CFG Interface Configuration Register Values
|
|
||||||
------------------------------------------
|
|
||||||
===============================================*/
|
|
||||||
#define HI_CFG_UART_ENABLE 0x00000004
|
|
||||||
#define HI_CFG_RST232_ENABLE 0x00000008
|
|
||||||
#define HI_CFG_CLOCK_REQ_SELECT 0x00000010
|
|
||||||
#define HI_CFG_HOST_INT_ENABLE 0x00000020
|
|
||||||
#define HI_CFG_VLYNQ_OUTPUT_ENABLE 0x00000040
|
|
||||||
#define HI_CFG_HOST_INT_ACTIVE_LOW 0x00000080
|
|
||||||
#define HI_CFG_UART_TX_OUT_GPIO_15 0x00000100
|
|
||||||
#define HI_CFG_UART_TX_OUT_GPIO_14 0x00000200
|
|
||||||
#define HI_CFG_UART_TX_OUT_GPIO_7 0x00000400
|
|
||||||
|
|
||||||
#define HI_CFG_DEF_VAL \
|
|
||||||
(HI_CFG_UART_ENABLE | \
|
|
||||||
HI_CFG_RST232_ENABLE | \
|
|
||||||
HI_CFG_CLOCK_REQ_SELECT | \
|
|
||||||
HI_CFG_HOST_INT_ENABLE)
|
|
||||||
|
|
||||||
#define REF_FREQ_19_2 0
|
#define REF_FREQ_19_2 0
|
||||||
#define REF_FREQ_26_0 1
|
#define REF_FREQ_26_0 1
|
||||||
#define REF_FREQ_38_4 2
|
#define REF_FREQ_38_4 2
|
||||||
|
@ -400,38 +367,19 @@
|
||||||
#define LUT_PARAM_BB_PLL_LOOP_FILTER 5
|
#define LUT_PARAM_BB_PLL_LOOP_FILTER 5
|
||||||
#define LUT_PARAM_NUM 6
|
#define LUT_PARAM_NUM 6
|
||||||
|
|
||||||
#define ACX_EEPROMLESS_IND_REG (SCR_PAD4)
|
#define WL12XX_EEPROMLESS_IND (WL12XX_SCR_PAD4)
|
||||||
#define USE_EEPROM 0
|
#define USE_EEPROM 0
|
||||||
#define SOFT_RESET_MAX_TIME 1000000
|
|
||||||
#define SOFT_RESET_STALL_TIME 1000
|
|
||||||
#define NVS_DATA_BUNDARY_ALIGNMENT 4
|
#define NVS_DATA_BUNDARY_ALIGNMENT 4
|
||||||
|
|
||||||
|
|
||||||
/* Firmware image load chunk size */
|
|
||||||
#define CHUNK_SIZE 16384
|
|
||||||
|
|
||||||
/* Firmware image header size */
|
/* Firmware image header size */
|
||||||
#define FW_HDR_SIZE 8
|
#define FW_HDR_SIZE 8
|
||||||
|
|
||||||
#define ECPU_CONTROL_HALT 0x00000101
|
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
|
|
||||||
CHANNELS, BAND & REG DOMAINS definitions
|
CHANNELS, BAND & REG DOMAINS definitions
|
||||||
|
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
enum {
|
|
||||||
RADIO_BAND_2_4GHZ = 0, /* 2.4 Ghz band */
|
|
||||||
RADIO_BAND_5GHZ = 1, /* 5 Ghz band */
|
|
||||||
RADIO_BAND_JAPAN_4_9_GHZ = 2,
|
|
||||||
DEFAULT_BAND = RADIO_BAND_2_4GHZ,
|
|
||||||
INVALID_BAND = 0xFE,
|
|
||||||
MAX_RADIO_BANDS = 0xFF
|
|
||||||
};
|
|
||||||
|
|
||||||
#define SHORT_PREAMBLE_BIT BIT(0) /* CCK or Barker depending on the rate */
|
#define SHORT_PREAMBLE_BIT BIT(0) /* CCK or Barker depending on the rate */
|
||||||
#define OFDM_RATE_BIT BIT(6)
|
#define OFDM_RATE_BIT BIT(6)
|
||||||
#define PBCC_RATE_BIT BIT(7)
|
#define PBCC_RATE_BIT BIT(7)
|
||||||
|
@ -465,14 +413,82 @@ b12-b0 - Supported Rate indicator bits as defined below.
|
||||||
|
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
|
#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
|
||||||
|
|
||||||
Interrupt Trigger Register (Host -> WiLink)
|
#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
|
||||||
|
|
||||||
/* Hardware to Embedded CPU Interrupts - first 32-bit register set */
|
#define WU_COUNTER_PAUSE_VAL 0x3FF
|
||||||
|
|
||||||
|
/* PLL configuration algorithm for wl128x */
|
||||||
|
#define SYS_CLK_CFG_REG 0x2200
|
||||||
|
/* Bit[0] - 0-TCXO, 1-FREF */
|
||||||
|
#define MCS_PLL_CLK_SEL_FREF BIT(0)
|
||||||
|
/* Bit[3:2] - 01-TCXO, 10-FREF */
|
||||||
|
#define WL_CLK_REQ_TYPE_FREF BIT(3)
|
||||||
|
#define WL_CLK_REQ_TYPE_PG2 (BIT(3) | BIT(2))
|
||||||
|
/* Bit[4] - 0-TCXO, 1-FREF */
|
||||||
|
#define PRCM_CM_EN_MUX_WLAN_FREF BIT(4)
|
||||||
|
|
||||||
|
#define TCXO_ILOAD_INT_REG 0x2264
|
||||||
|
#define TCXO_CLK_DETECT_REG 0x2266
|
||||||
|
|
||||||
|
#define TCXO_DET_FAILED BIT(4)
|
||||||
|
|
||||||
|
#define FREF_ILOAD_INT_REG 0x2084
|
||||||
|
#define FREF_CLK_DETECT_REG 0x2086
|
||||||
|
#define FREF_CLK_DETECT_FAIL BIT(4)
|
||||||
|
|
||||||
|
/* Use this reg for masking during driver access */
|
||||||
|
#define WL_SPARE_REG 0x2320
|
||||||
|
#define WL_SPARE_VAL BIT(2)
|
||||||
|
/* Bit[6:5:3] - mask wl write SYS_CLK_CFG[8:5:2:4] */
|
||||||
|
#define WL_SPARE_MASK_8526 (BIT(6) | BIT(5) | BIT(3))
|
||||||
|
|
||||||
|
#define PLL_LOCK_COUNTERS_REG 0xD8C
|
||||||
|
#define PLL_LOCK_COUNTERS_COEX 0x0F
|
||||||
|
#define PLL_LOCK_COUNTERS_MCS 0xF0
|
||||||
|
#define MCS_PLL_OVERRIDE_REG 0xD90
|
||||||
|
#define MCS_PLL_CONFIG_REG 0xD92
|
||||||
|
#define MCS_SEL_IN_FREQ_MASK 0x0070
|
||||||
|
#define MCS_SEL_IN_FREQ_SHIFT 4
|
||||||
|
#define MCS_PLL_CONFIG_REG_VAL 0x73
|
||||||
|
#define MCS_PLL_ENABLE_HP (BIT(0) | BIT(1))
|
||||||
|
|
||||||
|
#define MCS_PLL_M_REG 0xD94
|
||||||
|
#define MCS_PLL_N_REG 0xD96
|
||||||
|
#define MCS_PLL_M_REG_VAL 0xC8
|
||||||
|
#define MCS_PLL_N_REG_VAL 0x07
|
||||||
|
|
||||||
|
#define SDIO_IO_DS 0xd14
|
||||||
|
|
||||||
|
/* SDIO/wSPI DS configuration values */
|
||||||
|
enum {
|
||||||
|
HCI_IO_DS_8MA = 0,
|
||||||
|
HCI_IO_DS_4MA = 1, /* default */
|
||||||
|
HCI_IO_DS_6MA = 2,
|
||||||
|
HCI_IO_DS_2MA = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* end PLL configuration algorithm for wl128x */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Host Command Interrupt. Setting this bit masks
|
* Host Command Interrupt. Setting this bit masks
|
||||||
|
@ -480,7 +496,7 @@ b12-b0 - Supported Rate indicator bits as defined below.
|
||||||
* the FW that it has sent a command
|
* the FW that it has sent a command
|
||||||
* to the Wlan hardware Command Mailbox.
|
* to the Wlan hardware Command Mailbox.
|
||||||
*/
|
*/
|
||||||
#define INTR_TRIG_CMD BIT(0)
|
#define WL12XX_INTR_TRIG_CMD BIT(0)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Host Event Acknowlegde Interrupt. The host
|
* Host Event Acknowlegde Interrupt. The host
|
||||||
|
@ -488,42 +504,27 @@ b12-b0 - Supported Rate indicator bits as defined below.
|
||||||
* the unsolicited information from the event
|
* the unsolicited information from the event
|
||||||
* mailbox.
|
* mailbox.
|
||||||
*/
|
*/
|
||||||
#define INTR_TRIG_EVENT_ACK BIT(1)
|
#define WL12XX_INTR_TRIG_EVENT_ACK BIT(1)
|
||||||
|
|
||||||
/*
|
/*===============================================
|
||||||
* The host sets this bit to inform the Wlan
|
HI_CFG Interface Configuration Register Values
|
||||||
* FW that a TX packet is in the XFER
|
------------------------------------------
|
||||||
* Buffer #0.
|
===============================================*/
|
||||||
*/
|
#define HI_CFG_UART_ENABLE 0x00000004
|
||||||
#define INTR_TRIG_TX_PROC0 BIT(2)
|
#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 \
|
||||||
* The host sets this bit to inform the FW
|
(HI_CFG_UART_ENABLE | \
|
||||||
* that it read a packet from RX XFER
|
HI_CFG_RST232_ENABLE | \
|
||||||
* Buffer #0.
|
HI_CFG_CLOCK_REQ_SELECT | \
|
||||||
*/
|
HI_CFG_HOST_INT_ENABLE)
|
||||||
#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 WL127X_REG_FUSE_DATA_2_1 0x050a
|
#define WL127X_REG_FUSE_DATA_2_1 0x050a
|
||||||
#define WL128X_REG_FUSE_DATA_2_1 0x2152
|
#define WL128X_REG_FUSE_DATA_2_1 0x2152
|
31
drivers/net/wireless/ti/wl12xx/wl12xx.h
Normal file
31
drivers/net/wireless/ti/wl12xx/wl12xx.h
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* 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__ */
|
41
drivers/net/wireless/ti/wlcore/Kconfig
Normal file
41
drivers/net/wireless/ti/wlcore/Kconfig
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
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
|
15
drivers/net/wireless/ti/wlcore/Makefile
Normal file
15
drivers/net/wireless/ti/wlcore/Makefile
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
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
|
||||||
|
|
||||||
|
wlcore_spi-objs = spi.o
|
||||||
|
wlcore_sdio-objs = 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
|
||||||
|
|
||||||
|
ccflags-y += -D__CHECK_ENDIAN__
|
|
@ -28,11 +28,11 @@
|
||||||
#include <linux/spi/spi.h>
|
#include <linux/spi/spi.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
|
||||||
#include "wl12xx.h"
|
#include "wlcore.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "wl12xx_80211.h"
|
#include "wl12xx_80211.h"
|
||||||
#include "reg.h"
|
|
||||||
#include "ps.h"
|
#include "ps.h"
|
||||||
|
#include "hw_ops.h"
|
||||||
|
|
||||||
int wl1271_acx_wake_up_conditions(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
int wl1271_acx_wake_up_conditions(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||||
u8 wake_up_event, u8 listen_interval)
|
u8 wake_up_event, u8 listen_interval)
|
||||||
|
@ -757,7 +757,10 @@ int wl1271_acx_sta_rate_policies(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||||
|
|
||||||
/* configure one AP supported rate class */
|
/* configure one AP supported rate class */
|
||||||
acx->rate_policy_idx = cpu_to_le32(wlvif->sta.ap_rate_idx);
|
acx->rate_policy_idx = cpu_to_le32(wlvif->sta.ap_rate_idx);
|
||||||
acx->rate_policy.enabled_rates = cpu_to_le32(wlvif->rate_set);
|
|
||||||
|
/* the AP policy is HW specific */
|
||||||
|
acx->rate_policy.enabled_rates =
|
||||||
|
cpu_to_le32(wlcore_hw_sta_get_ap_rate_mask(wl, wlvif));
|
||||||
acx->rate_policy.short_retry_limit = c->short_retry_limit;
|
acx->rate_policy.short_retry_limit = c->short_retry_limit;
|
||||||
acx->rate_policy.long_retry_limit = c->long_retry_limit;
|
acx->rate_policy.long_retry_limit = c->long_retry_limit;
|
||||||
acx->rate_policy.aflags = c->aflags;
|
acx->rate_policy.aflags = c->aflags;
|
||||||
|
@ -969,17 +972,14 @@ int wl12xx_acx_mem_cfg(struct wl1271 *wl)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wl->chip.id == CHIP_ID_1283_PG20)
|
mem = &wl->conf.mem;
|
||||||
mem = &wl->conf.mem_wl128x;
|
|
||||||
else
|
|
||||||
mem = &wl->conf.mem_wl127x;
|
|
||||||
|
|
||||||
/* memory config */
|
/* memory config */
|
||||||
mem_conf->num_stations = mem->num_stations;
|
mem_conf->num_stations = mem->num_stations;
|
||||||
mem_conf->rx_mem_block_num = mem->rx_block_num;
|
mem_conf->rx_mem_block_num = mem->rx_block_num;
|
||||||
mem_conf->tx_min_mem_block_num = mem->tx_min_block_num;
|
mem_conf->tx_min_mem_block_num = mem->tx_min_block_num;
|
||||||
mem_conf->num_ssid_profiles = mem->ssid_profiles;
|
mem_conf->num_ssid_profiles = mem->ssid_profiles;
|
||||||
mem_conf->total_tx_descriptors = cpu_to_le32(ACX_TX_DESCRIPTORS);
|
mem_conf->total_tx_descriptors = cpu_to_le32(wl->num_tx_desc);
|
||||||
mem_conf->dyn_mem_enable = mem->dynamic_memory;
|
mem_conf->dyn_mem_enable = mem->dynamic_memory;
|
||||||
mem_conf->tx_free_req = mem->min_req_tx_blocks;
|
mem_conf->tx_free_req = mem->min_req_tx_blocks;
|
||||||
mem_conf->rx_free_req = mem->min_req_rx_blocks;
|
mem_conf->rx_free_req = mem->min_req_rx_blocks;
|
||||||
|
@ -998,32 +998,6 @@ int wl12xx_acx_mem_cfg(struct wl1271 *wl)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int wl1271_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap)
|
|
||||||
{
|
|
||||||
struct wl1271_acx_host_config_bitmap *bitmap_conf;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
bitmap_conf = kzalloc(sizeof(*bitmap_conf), GFP_KERNEL);
|
|
||||||
if (!bitmap_conf) {
|
|
||||||
ret = -ENOMEM;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
bitmap_conf->host_cfg_bitmap = cpu_to_le32(host_cfg_bitmap);
|
|
||||||
|
|
||||||
ret = wl1271_cmd_configure(wl, ACX_HOST_IF_CFG_BITMAP,
|
|
||||||
bitmap_conf, sizeof(*bitmap_conf));
|
|
||||||
if (ret < 0) {
|
|
||||||
wl1271_warning("wl1271 bitmap config opt failed: %d", ret);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
kfree(bitmap_conf);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int wl1271_acx_init_mem_config(struct wl1271 *wl)
|
int wl1271_acx_init_mem_config(struct wl1271 *wl)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
|
@ -25,7 +25,7 @@
|
||||||
#ifndef __ACX_H__
|
#ifndef __ACX_H__
|
||||||
#define __ACX_H__
|
#define __ACX_H__
|
||||||
|
|
||||||
#include "wl12xx.h"
|
#include "wlcore.h"
|
||||||
#include "cmd.h"
|
#include "cmd.h"
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
|
@ -824,16 +824,11 @@ struct wl1271_acx_keep_alive_config {
|
||||||
__le32 period;
|
__le32 period;
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
/* TODO: maybe this needs to be moved somewhere else? */
|
||||||
#define HOST_IF_CFG_RX_FIFO_ENABLE BIT(0)
|
#define HOST_IF_CFG_RX_FIFO_ENABLE BIT(0)
|
||||||
#define HOST_IF_CFG_TX_EXTRA_BLKS_SWAP BIT(1)
|
#define HOST_IF_CFG_TX_EXTRA_BLKS_SWAP BIT(1)
|
||||||
#define HOST_IF_CFG_TX_PAD_TO_SDIO_BLK BIT(3)
|
#define HOST_IF_CFG_TX_PAD_TO_SDIO_BLK BIT(3)
|
||||||
|
|
||||||
struct wl1271_acx_host_config_bitmap {
|
|
||||||
struct acx_header header;
|
|
||||||
|
|
||||||
__le32 host_cfg_bitmap;
|
|
||||||
} __packed;
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
WL1271_ACX_TRIG_TYPE_LEVEL = 0,
|
WL1271_ACX_TRIG_TYPE_LEVEL = 0,
|
||||||
WL1271_ACX_TRIG_TYPE_EDGE,
|
WL1271_ACX_TRIG_TYPE_EDGE,
|
||||||
|
@ -1274,7 +1269,6 @@ int wl1271_acx_frag_threshold(struct wl1271 *wl, u32 frag_threshold);
|
||||||
int wl1271_acx_tx_config_options(struct wl1271 *wl);
|
int wl1271_acx_tx_config_options(struct wl1271 *wl);
|
||||||
int wl12xx_acx_mem_cfg(struct wl1271 *wl);
|
int wl12xx_acx_mem_cfg(struct wl1271 *wl);
|
||||||
int wl1271_acx_init_mem_config(struct wl1271 *wl);
|
int wl1271_acx_init_mem_config(struct wl1271 *wl);
|
||||||
int wl1271_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap);
|
|
||||||
int wl1271_acx_init_rx_interrupt(struct wl1271 *wl);
|
int wl1271_acx_init_rx_interrupt(struct wl1271 *wl);
|
||||||
int wl1271_acx_smart_reflex(struct wl1271 *wl);
|
int wl1271_acx_smart_reflex(struct wl1271 *wl);
|
||||||
int wl1271_acx_bet_enable(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
int wl1271_acx_bet_enable(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
443
drivers/net/wireless/ti/wlcore/boot.c
Normal file
443
drivers/net/wireless/ti/wlcore/boot.c
Normal file
|
@ -0,0 +1,443 @@
|
||||||
|
/*
|
||||||
|
* This file is part of wl1271
|
||||||
|
*
|
||||||
|
* Copyright (C) 2008-2010 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
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/wl12xx.h>
|
||||||
|
#include <linux/export.h>
|
||||||
|
|
||||||
|
#include "debug.h"
|
||||||
|
#include "acx.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 = wlcore_read_reg(wl, REG_ECPU_CONTROL);
|
||||||
|
|
||||||
|
/* 10.5.1 run the firmware (II) */
|
||||||
|
cpu_ctrl |= flag;
|
||||||
|
wlcore_write_reg(wl, REG_ECPU_CONTROL, cpu_ctrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int wlcore_parse_fw_ver(struct wl1271 *wl)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = sscanf(wl->chip.fw_ver_str + 4, "%u.%u.%u.%u.%u",
|
||||||
|
&wl->chip.fw_ver[0], &wl->chip.fw_ver[1],
|
||||||
|
&wl->chip.fw_ver[2], &wl->chip.fw_ver[3],
|
||||||
|
&wl->chip.fw_ver[4]);
|
||||||
|
|
||||||
|
if (ret != 5) {
|
||||||
|
wl1271_warning("fw version incorrect value");
|
||||||
|
memset(wl->chip.fw_ver, 0, sizeof(wl->chip.fw_ver));
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = wlcore_identify_fw(wl);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int wlcore_boot_fw_version(struct wl1271 *wl)
|
||||||
|
{
|
||||||
|
struct wl1271_static_data *static_data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
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,
|
||||||
|
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';
|
||||||
|
|
||||||
|
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 wlcore_partition_set partition;
|
||||||
|
int addr, chunk_num, partition_limit;
|
||||||
|
u8 *p, *chunk;
|
||||||
|
|
||||||
|
/* whal_FwCtrl_LoadFwImageSm() */
|
||||||
|
|
||||||
|
wl1271_debug(DEBUG_BOOT, "starting firmware upload");
|
||||||
|
|
||||||
|
wl1271_debug(DEBUG_BOOT, "fw_data_len %zd chunk_size %d",
|
||||||
|
fw_data_len, CHUNK_SIZE);
|
||||||
|
|
||||||
|
if ((fw_data_len % 4) != 0) {
|
||||||
|
wl1271_error("firmware length not multiple of four");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
chunk = kmalloc(CHUNK_SIZE, GFP_KERNEL);
|
||||||
|
if (!chunk) {
|
||||||
|
wl1271_error("allocation for firmware upload chunk failed");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(&partition, &wl->ptable[PART_DOWN], sizeof(partition));
|
||||||
|
partition.mem.start = dest;
|
||||||
|
wlcore_set_partition(wl, &partition);
|
||||||
|
|
||||||
|
/* 10.1 set partition limit and chunk num */
|
||||||
|
chunk_num = 0;
|
||||||
|
partition_limit = wl->ptable[PART_DOWN].mem.size;
|
||||||
|
|
||||||
|
while (chunk_num < fw_data_len / CHUNK_SIZE) {
|
||||||
|
/* 10.2 update partition, if needed */
|
||||||
|
addr = dest + (chunk_num + 2) * CHUNK_SIZE;
|
||||||
|
if (addr > partition_limit) {
|
||||||
|
addr = dest + chunk_num * CHUNK_SIZE;
|
||||||
|
partition_limit = chunk_num * CHUNK_SIZE +
|
||||||
|
wl->ptable[PART_DOWN].mem.size;
|
||||||
|
partition.mem.start = addr;
|
||||||
|
wlcore_set_partition(wl, &partition);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 10.3 upload the chunk */
|
||||||
|
addr = dest + chunk_num * CHUNK_SIZE;
|
||||||
|
p = buf + chunk_num * CHUNK_SIZE;
|
||||||
|
memcpy(chunk, p, CHUNK_SIZE);
|
||||||
|
wl1271_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x",
|
||||||
|
p, addr);
|
||||||
|
wl1271_write(wl, addr, chunk, CHUNK_SIZE, false);
|
||||||
|
|
||||||
|
chunk_num++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 10.4 upload the last chunk */
|
||||||
|
addr = dest + chunk_num * CHUNK_SIZE;
|
||||||
|
p = buf + chunk_num * CHUNK_SIZE;
|
||||||
|
memcpy(chunk, p, fw_data_len % CHUNK_SIZE);
|
||||||
|
wl1271_debug(DEBUG_BOOT, "uploading fw last chunk (%zd B) 0x%p to 0x%x",
|
||||||
|
fw_data_len % CHUNK_SIZE, p, addr);
|
||||||
|
wl1271_write(wl, addr, chunk, fw_data_len % CHUNK_SIZE, false);
|
||||||
|
|
||||||
|
kfree(chunk);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int wlcore_boot_upload_firmware(struct wl1271 *wl)
|
||||||
|
{
|
||||||
|
u32 chunks, addr, len;
|
||||||
|
int ret = 0;
|
||||||
|
u8 *fw;
|
||||||
|
|
||||||
|
fw = wl->fw;
|
||||||
|
chunks = be32_to_cpup((__be32 *) fw);
|
||||||
|
fw += sizeof(u32);
|
||||||
|
|
||||||
|
wl1271_debug(DEBUG_BOOT, "firmware chunks to be uploaded: %u", chunks);
|
||||||
|
|
||||||
|
while (chunks--) {
|
||||||
|
addr = be32_to_cpup((__be32 *) fw);
|
||||||
|
fw += sizeof(u32);
|
||||||
|
len = be32_to_cpup((__be32 *) fw);
|
||||||
|
fw += sizeof(u32);
|
||||||
|
|
||||||
|
if (len > 300000) {
|
||||||
|
wl1271_info("firmware chunk too long: %u", len);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
wl1271_debug(DEBUG_BOOT, "chunk %d addr 0x%x len %u",
|
||||||
|
chunks, addr, len);
|
||||||
|
ret = wl1271_boot_upload_firmware_chunk(wl, fw, len, addr);
|
||||||
|
if (ret != 0)
|
||||||
|
break;
|
||||||
|
fw += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(wlcore_boot_upload_firmware);
|
||||||
|
|
||||||
|
int wlcore_boot_upload_nvs(struct wl1271 *wl)
|
||||||
|
{
|
||||||
|
size_t nvs_len, burst_len;
|
||||||
|
int i;
|
||||||
|
u32 dest_addr, val;
|
||||||
|
u8 *nvs_ptr, *nvs_aligned;
|
||||||
|
|
||||||
|
if (wl->nvs == NULL)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
if (wl->quirks & WLCORE_QUIRK_LEGACY_NVS) {
|
||||||
|
struct wl1271_nvs_file *nvs =
|
||||||
|
(struct wl1271_nvs_file *)wl->nvs;
|
||||||
|
/*
|
||||||
|
* FIXME: the LEGACY NVS image support (NVS's missing the 5GHz
|
||||||
|
* band configurations) can be removed when those NVS files stop
|
||||||
|
* floating around.
|
||||||
|
*/
|
||||||
|
if (wl->nvs_len == sizeof(struct wl1271_nvs_file) ||
|
||||||
|
wl->nvs_len == WL1271_INI_LEGACY_NVS_FILE_SIZE) {
|
||||||
|
if (nvs->general_params.dual_mode_select)
|
||||||
|
wl->enable_11a = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wl->nvs_len != sizeof(struct wl1271_nvs_file) &&
|
||||||
|
(wl->nvs_len != WL1271_INI_LEGACY_NVS_FILE_SIZE ||
|
||||||
|
wl->enable_11a)) {
|
||||||
|
wl1271_error("nvs size is not as expected: %zu != %zu",
|
||||||
|
wl->nvs_len, sizeof(struct wl1271_nvs_file));
|
||||||
|
kfree(wl->nvs);
|
||||||
|
wl->nvs = NULL;
|
||||||
|
wl->nvs_len = 0;
|
||||||
|
return -EILSEQ;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* only the first part of the NVS needs to be uploaded */
|
||||||
|
nvs_len = sizeof(nvs->nvs);
|
||||||
|
nvs_ptr = (u8 *) nvs->nvs;
|
||||||
|
} else {
|
||||||
|
struct 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 */
|
||||||
|
nvs_ptr[11] = wl->addresses[0].addr[0];
|
||||||
|
nvs_ptr[10] = wl->addresses[0].addr[1];
|
||||||
|
nvs_ptr[6] = wl->addresses[0].addr[2];
|
||||||
|
nvs_ptr[5] = wl->addresses[0].addr[3];
|
||||||
|
nvs_ptr[4] = wl->addresses[0].addr[4];
|
||||||
|
nvs_ptr[3] = wl->addresses[0].addr[5];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Layout before the actual NVS tables:
|
||||||
|
* 1 byte : burst length.
|
||||||
|
* 2 bytes: destination address.
|
||||||
|
* n bytes: data to burst copy.
|
||||||
|
*
|
||||||
|
* This is ended by a 0 length, then the NVS tables.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* FIXME: Do we need to check here whether the LSB is 1? */
|
||||||
|
while (nvs_ptr[0]) {
|
||||||
|
burst_len = nvs_ptr[0];
|
||||||
|
dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Due to our new wl1271_translate_reg_addr function,
|
||||||
|
* we need to add the register partition start address
|
||||||
|
* to the destination
|
||||||
|
*/
|
||||||
|
dest_addr += wl->curr_part.reg.start;
|
||||||
|
|
||||||
|
/* We move our pointer to the data */
|
||||||
|
nvs_ptr += 3;
|
||||||
|
|
||||||
|
for (i = 0; i < burst_len; i++) {
|
||||||
|
if (nvs_ptr + 3 >= (u8 *) wl->nvs + nvs_len)
|
||||||
|
goto out_badnvs;
|
||||||
|
|
||||||
|
val = (nvs_ptr[0] | (nvs_ptr[1] << 8)
|
||||||
|
| (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24));
|
||||||
|
|
||||||
|
wl1271_debug(DEBUG_BOOT,
|
||||||
|
"nvs burst write 0x%x: 0x%x",
|
||||||
|
dest_addr, val);
|
||||||
|
wl1271_write32(wl, dest_addr, val);
|
||||||
|
|
||||||
|
nvs_ptr += 4;
|
||||||
|
dest_addr += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nvs_ptr >= (u8 *) wl->nvs + nvs_len)
|
||||||
|
goto out_badnvs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We've reached the first zero length, the first NVS table
|
||||||
|
* is located at an aligned offset which is at least 7 bytes further.
|
||||||
|
* NOTE: The wl->nvs->nvs element must be first, in order to
|
||||||
|
* simplify the casting, we assume it is at the beginning of
|
||||||
|
* the wl->nvs structure.
|
||||||
|
*/
|
||||||
|
nvs_ptr = (u8 *)wl->nvs +
|
||||||
|
ALIGN(nvs_ptr - (u8 *)wl->nvs + 7, 4);
|
||||||
|
|
||||||
|
if (nvs_ptr >= (u8 *) wl->nvs + nvs_len)
|
||||||
|
goto out_badnvs;
|
||||||
|
|
||||||
|
nvs_len -= nvs_ptr - (u8 *)wl->nvs;
|
||||||
|
|
||||||
|
/* Now we must set the partition correctly */
|
||||||
|
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);
|
||||||
|
if (!nvs_aligned)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
/* And finally we upload the NVS tables */
|
||||||
|
wlcore_write_data(wl, REG_CMD_MBOX_ADDRESS,
|
||||||
|
nvs_aligned, nvs_len, false);
|
||||||
|
|
||||||
|
kfree(nvs_aligned);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
out_badnvs:
|
||||||
|
wl1271_error("nvs data is malformed");
|
||||||
|
return -EILSEQ;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(wlcore_boot_upload_nvs);
|
||||||
|
|
||||||
|
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 = wlcore_read_reg(wl, REG_CHIP_ID_B);
|
||||||
|
|
||||||
|
wl1271_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id);
|
||||||
|
|
||||||
|
if (chip_id != wl->chip.id) {
|
||||||
|
wl1271_error("chip id doesn't match after firmware boot");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* wait for init to complete */
|
||||||
|
loop = 0;
|
||||||
|
while (loop++ < INIT_LOOP) {
|
||||||
|
udelay(INIT_LOOP_DELAY);
|
||||||
|
intr = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR);
|
||||||
|
|
||||||
|
if (intr == 0xffffffff) {
|
||||||
|
wl1271_error("error reading hardware complete "
|
||||||
|
"init indication");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
/* check that ACX_INTR_INIT_COMPLETE is enabled */
|
||||||
|
else if (intr & WL1271_ACX_INTR_INIT_COMPLETE) {
|
||||||
|
wlcore_write_reg(wl, REG_INTERRUPT_ACK,
|
||||||
|
WL1271_ACX_INTR_INIT_COMPLETE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loop > INIT_LOOP) {
|
||||||
|
wl1271_error("timeout waiting for the hardware to "
|
||||||
|
"complete initialization");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get hardware config command mail box */
|
||||||
|
wl->cmd_box_addr = wlcore_read_reg(wl, REG_COMMAND_MAILBOX_PTR);
|
||||||
|
|
||||||
|
wl1271_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x", wl->cmd_box_addr);
|
||||||
|
|
||||||
|
/* 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, "MBOX ptrs: 0x%x 0x%x",
|
||||||
|
wl->mbox_ptr[0], wl->mbox_ptr[1]);
|
||||||
|
|
||||||
|
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
|
||||||
|
* ready to receive event from the command mailbox
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* unmask required mbox events */
|
||||||
|
wl->event_mask = BSS_LOSE_EVENT_ID |
|
||||||
|
SCAN_COMPLETE_EVENT_ID |
|
||||||
|
ROLE_STOP_COMPLETE_EVENT_ID |
|
||||||
|
RSSI_SNR_TRIGGER_0_EVENT_ID |
|
||||||
|
PSPOLL_DELIVERY_FAILURE_EVENT_ID |
|
||||||
|
SOFT_GEMINI_SENSE_EVENT_ID |
|
||||||
|
PERIODIC_SCAN_REPORT_EVENT_ID |
|
||||||
|
PERIODIC_SCAN_COMPLETE_EVENT_ID |
|
||||||
|
DUMMY_PACKET_EVENT_ID |
|
||||||
|
PEER_REMOVE_COMPLETE_EVENT_ID |
|
||||||
|
BA_SESSION_RX_CONSTRAINT_EVENT_ID |
|
||||||
|
REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID |
|
||||||
|
INACTIVE_STA_EVENT_ID |
|
||||||
|
MAX_TX_RETRY_EVENT_ID |
|
||||||
|
CHANNEL_SWITCH_COMPLETE_EVENT_ID;
|
||||||
|
|
||||||
|
ret = wl1271_event_unmask(wl);
|
||||||
|
if (ret < 0) {
|
||||||
|
wl1271_error("EVENT mask setting failed");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set the working partition to its "running" mode offset */
|
||||||
|
wlcore_set_partition(wl, &wl->ptable[PART_WORK]);
|
||||||
|
|
||||||
|
/* firmware startup completed */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(wlcore_boot_run_firmware);
|
54
drivers/net/wireless/ti/wlcore/boot.h
Normal file
54
drivers/net/wireless/ti/wlcore/boot.h
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* 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/ieee80211.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
|
||||||
#include "wl12xx.h"
|
#include "wlcore.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "reg.h"
|
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "acx.h"
|
#include "acx.h"
|
||||||
#include "wl12xx_80211.h"
|
#include "wl12xx_80211.h"
|
||||||
|
@ -67,11 +66,15 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
|
||||||
|
|
||||||
wl1271_write(wl, wl->cmd_box_addr, buf, len, false);
|
wl1271_write(wl, wl->cmd_box_addr, buf, len, false);
|
||||||
|
|
||||||
wl1271_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD);
|
/*
|
||||||
|
* TODO: we just need this because one bit is in a different
|
||||||
|
* place. Is there any better way?
|
||||||
|
*/
|
||||||
|
wl->ops->trigger_cmd(wl, wl->cmd_box_addr, buf, len);
|
||||||
|
|
||||||
timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT);
|
timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT);
|
||||||
|
|
||||||
intr = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
|
intr = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR);
|
||||||
while (!(intr & WL1271_ACX_INTR_CMD_COMPLETE)) {
|
while (!(intr & WL1271_ACX_INTR_CMD_COMPLETE)) {
|
||||||
if (time_after(jiffies, timeout)) {
|
if (time_after(jiffies, timeout)) {
|
||||||
wl1271_error("command complete timeout");
|
wl1271_error("command complete timeout");
|
||||||
|
@ -85,7 +88,7 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
|
||||||
else
|
else
|
||||||
msleep(1);
|
msleep(1);
|
||||||
|
|
||||||
intr = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
|
intr = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* read back the status code of the command */
|
/* read back the status code of the command */
|
||||||
|
@ -100,8 +103,7 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
wl1271_write32(wl, ACX_REG_INTERRUPT_ACK,
|
wlcore_write_reg(wl, REG_INTERRUPT_ACK, WL1271_ACX_INTR_CMD_COMPLETE);
|
||||||
WL1271_ACX_INTR_CMD_COMPLETE);
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
|
@ -110,240 +112,18 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int wl1271_cmd_general_parms(struct wl1271 *wl)
|
|
||||||
{
|
|
||||||
struct wl1271_general_parms_cmd *gen_parms;
|
|
||||||
struct wl1271_ini_general_params *gp =
|
|
||||||
&((struct wl1271_nvs_file *)wl->nvs)->general_params;
|
|
||||||
bool answer = false;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!wl->nvs)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) {
|
|
||||||
wl1271_warning("FEM index from INI out of bounds");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL);
|
|
||||||
if (!gen_parms)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM;
|
|
||||||
|
|
||||||
memcpy(&gen_parms->general_params, gp, sizeof(*gp));
|
|
||||||
|
|
||||||
if (gp->tx_bip_fem_auto_detect)
|
|
||||||
answer = true;
|
|
||||||
|
|
||||||
/* Override the REF CLK from the NVS with the one from platform data */
|
|
||||||
gen_parms->general_params.ref_clock = wl->ref_clock;
|
|
||||||
|
|
||||||
ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer);
|
|
||||||
if (ret < 0) {
|
|
||||||
wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
gp->tx_bip_fem_manufacturer =
|
|
||||||
gen_parms->general_params.tx_bip_fem_manufacturer;
|
|
||||||
|
|
||||||
if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) {
|
|
||||||
wl1271_warning("FEM index from FW out of bounds");
|
|
||||||
ret = -EINVAL;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n",
|
|
||||||
answer ? "auto" : "manual", gp->tx_bip_fem_manufacturer);
|
|
||||||
|
|
||||||
out:
|
|
||||||
kfree(gen_parms);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int wl128x_cmd_general_parms(struct wl1271 *wl)
|
|
||||||
{
|
|
||||||
struct wl128x_general_parms_cmd *gen_parms;
|
|
||||||
struct wl128x_ini_general_params *gp =
|
|
||||||
&((struct wl128x_nvs_file *)wl->nvs)->general_params;
|
|
||||||
bool answer = false;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!wl->nvs)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) {
|
|
||||||
wl1271_warning("FEM index from ini out of bounds");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL);
|
|
||||||
if (!gen_parms)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM;
|
|
||||||
|
|
||||||
memcpy(&gen_parms->general_params, gp, sizeof(*gp));
|
|
||||||
|
|
||||||
if (gp->tx_bip_fem_auto_detect)
|
|
||||||
answer = true;
|
|
||||||
|
|
||||||
/* Replace REF and TCXO CLKs with the ones from platform data */
|
|
||||||
gen_parms->general_params.ref_clock = wl->ref_clock;
|
|
||||||
gen_parms->general_params.tcxo_ref_clock = wl->tcxo_clock;
|
|
||||||
|
|
||||||
ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer);
|
|
||||||
if (ret < 0) {
|
|
||||||
wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
gp->tx_bip_fem_manufacturer =
|
|
||||||
gen_parms->general_params.tx_bip_fem_manufacturer;
|
|
||||||
|
|
||||||
if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) {
|
|
||||||
wl1271_warning("FEM index from FW out of bounds");
|
|
||||||
ret = -EINVAL;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n",
|
|
||||||
answer ? "auto" : "manual", gp->tx_bip_fem_manufacturer);
|
|
||||||
|
|
||||||
out:
|
|
||||||
kfree(gen_parms);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int wl1271_cmd_radio_parms(struct wl1271 *wl)
|
|
||||||
{
|
|
||||||
struct wl1271_nvs_file *nvs = (struct wl1271_nvs_file *)wl->nvs;
|
|
||||||
struct wl1271_radio_parms_cmd *radio_parms;
|
|
||||||
struct wl1271_ini_general_params *gp = &nvs->general_params;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!wl->nvs)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL);
|
|
||||||
if (!radio_parms)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM;
|
|
||||||
|
|
||||||
/* 2.4GHz parameters */
|
|
||||||
memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2,
|
|
||||||
sizeof(struct wl1271_ini_band_params_2));
|
|
||||||
memcpy(&radio_parms->dyn_params_2,
|
|
||||||
&nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params,
|
|
||||||
sizeof(struct wl1271_ini_fem_params_2));
|
|
||||||
|
|
||||||
/* 5GHz parameters */
|
|
||||||
memcpy(&radio_parms->static_params_5,
|
|
||||||
&nvs->stat_radio_params_5,
|
|
||||||
sizeof(struct wl1271_ini_band_params_5));
|
|
||||||
memcpy(&radio_parms->dyn_params_5,
|
|
||||||
&nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params,
|
|
||||||
sizeof(struct wl1271_ini_fem_params_5));
|
|
||||||
|
|
||||||
wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ",
|
|
||||||
radio_parms, sizeof(*radio_parms));
|
|
||||||
|
|
||||||
ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0);
|
|
||||||
if (ret < 0)
|
|
||||||
wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed");
|
|
||||||
|
|
||||||
kfree(radio_parms);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int wl128x_cmd_radio_parms(struct wl1271 *wl)
|
|
||||||
{
|
|
||||||
struct wl128x_nvs_file *nvs = (struct wl128x_nvs_file *)wl->nvs;
|
|
||||||
struct wl128x_radio_parms_cmd *radio_parms;
|
|
||||||
struct wl128x_ini_general_params *gp = &nvs->general_params;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!wl->nvs)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL);
|
|
||||||
if (!radio_parms)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM;
|
|
||||||
|
|
||||||
/* 2.4GHz parameters */
|
|
||||||
memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2,
|
|
||||||
sizeof(struct wl128x_ini_band_params_2));
|
|
||||||
memcpy(&radio_parms->dyn_params_2,
|
|
||||||
&nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params,
|
|
||||||
sizeof(struct wl128x_ini_fem_params_2));
|
|
||||||
|
|
||||||
/* 5GHz parameters */
|
|
||||||
memcpy(&radio_parms->static_params_5,
|
|
||||||
&nvs->stat_radio_params_5,
|
|
||||||
sizeof(struct wl128x_ini_band_params_5));
|
|
||||||
memcpy(&radio_parms->dyn_params_5,
|
|
||||||
&nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params,
|
|
||||||
sizeof(struct wl128x_ini_fem_params_5));
|
|
||||||
|
|
||||||
radio_parms->fem_vendor_and_options = nvs->fem_vendor_and_options;
|
|
||||||
|
|
||||||
wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ",
|
|
||||||
radio_parms, sizeof(*radio_parms));
|
|
||||||
|
|
||||||
ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0);
|
|
||||||
if (ret < 0)
|
|
||||||
wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed");
|
|
||||||
|
|
||||||
kfree(radio_parms);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int wl1271_cmd_ext_radio_parms(struct wl1271 *wl)
|
|
||||||
{
|
|
||||||
struct wl1271_ext_radio_parms_cmd *ext_radio_parms;
|
|
||||||
struct conf_rf_settings *rf = &wl->conf.rf;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!wl->nvs)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
ext_radio_parms = kzalloc(sizeof(*ext_radio_parms), GFP_KERNEL);
|
|
||||||
if (!ext_radio_parms)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
ext_radio_parms->test.id = TEST_CMD_INI_FILE_RF_EXTENDED_PARAM;
|
|
||||||
|
|
||||||
memcpy(ext_radio_parms->tx_per_channel_power_compensation_2,
|
|
||||||
rf->tx_per_channel_power_compensation_2,
|
|
||||||
CONF_TX_PWR_COMPENSATION_LEN_2);
|
|
||||||
memcpy(ext_radio_parms->tx_per_channel_power_compensation_5,
|
|
||||||
rf->tx_per_channel_power_compensation_5,
|
|
||||||
CONF_TX_PWR_COMPENSATION_LEN_5);
|
|
||||||
|
|
||||||
wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_EXT_RADIO_PARAM: ",
|
|
||||||
ext_radio_parms, sizeof(*ext_radio_parms));
|
|
||||||
|
|
||||||
ret = wl1271_cmd_test(wl, ext_radio_parms, sizeof(*ext_radio_parms), 0);
|
|
||||||
if (ret < 0)
|
|
||||||
wl1271_warning("TEST_CMD_INI_FILE_RF_EXTENDED_PARAM failed");
|
|
||||||
|
|
||||||
kfree(ext_radio_parms);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Poll the mailbox event field until any of the bits in the mask is set or a
|
* Poll the mailbox event field until any of the bits in the mask is set or a
|
||||||
* timeout occurs (WL1271_EVENT_TIMEOUT in msecs)
|
* timeout occurs (WL1271_EVENT_TIMEOUT in msecs)
|
||||||
*/
|
*/
|
||||||
static int wl1271_cmd_wait_for_event_or_timeout(struct wl1271 *wl, u32 mask)
|
static int wl1271_cmd_wait_for_event_or_timeout(struct wl1271 *wl, u32 mask)
|
||||||
{
|
{
|
||||||
u32 events_vector, event;
|
u32 *events_vector;
|
||||||
|
u32 event;
|
||||||
unsigned long timeout;
|
unsigned long timeout;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
events_vector = kmalloc(sizeof(*events_vector), GFP_DMA);
|
||||||
|
|
||||||
timeout = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT);
|
timeout = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT);
|
||||||
|
|
||||||
|
@ -351,21 +131,24 @@ static int wl1271_cmd_wait_for_event_or_timeout(struct wl1271 *wl, u32 mask)
|
||||||
if (time_after(jiffies, timeout)) {
|
if (time_after(jiffies, timeout)) {
|
||||||
wl1271_debug(DEBUG_CMD, "timeout waiting for event %d",
|
wl1271_debug(DEBUG_CMD, "timeout waiting for event %d",
|
||||||
(int)mask);
|
(int)mask);
|
||||||
return -ETIMEDOUT;
|
ret = -ETIMEDOUT;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
msleep(1);
|
msleep(1);
|
||||||
|
|
||||||
/* read from both event fields */
|
/* read from both event fields */
|
||||||
wl1271_read(wl, wl->mbox_ptr[0], &events_vector,
|
wl1271_read(wl, wl->mbox_ptr[0], events_vector,
|
||||||
sizeof(events_vector), false);
|
sizeof(*events_vector), false);
|
||||||
event = events_vector & mask;
|
event = *events_vector & mask;
|
||||||
wl1271_read(wl, wl->mbox_ptr[1], &events_vector,
|
wl1271_read(wl, wl->mbox_ptr[1], events_vector,
|
||||||
sizeof(events_vector), false);
|
sizeof(*events_vector), false);
|
||||||
event |= events_vector & mask;
|
event |= *events_vector & mask;
|
||||||
} while (!event);
|
} while (!event);
|
||||||
|
|
||||||
return 0;
|
out:
|
||||||
|
kfree(events_vector);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask)
|
static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask)
|
||||||
|
@ -522,7 +305,7 @@ static int wl12xx_cmd_role_start_dev(struct wl1271 *wl,
|
||||||
|
|
||||||
cmd->role_id = wlvif->dev_role_id;
|
cmd->role_id = wlvif->dev_role_id;
|
||||||
if (wlvif->band == IEEE80211_BAND_5GHZ)
|
if (wlvif->band == IEEE80211_BAND_5GHZ)
|
||||||
cmd->band = WL12XX_BAND_5GHZ;
|
cmd->band = WLCORE_BAND_5GHZ;
|
||||||
cmd->channel = wlvif->channel;
|
cmd->channel = wlvif->channel;
|
||||||
|
|
||||||
if (wlvif->dev_hlid == WL12XX_INVALID_LINK_ID) {
|
if (wlvif->dev_hlid == WL12XX_INVALID_LINK_ID) {
|
||||||
|
@ -613,7 +396,7 @@ int wl12xx_cmd_role_start_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||||
|
|
||||||
cmd->role_id = wlvif->role_id;
|
cmd->role_id = wlvif->role_id;
|
||||||
if (wlvif->band == IEEE80211_BAND_5GHZ)
|
if (wlvif->band == IEEE80211_BAND_5GHZ)
|
||||||
cmd->band = WL12XX_BAND_5GHZ;
|
cmd->band = WLCORE_BAND_5GHZ;
|
||||||
cmd->channel = wlvif->channel;
|
cmd->channel = wlvif->channel;
|
||||||
cmd->sta.basic_rate_set = cpu_to_le32(wlvif->basic_rate_set);
|
cmd->sta.basic_rate_set = cpu_to_le32(wlvif->basic_rate_set);
|
||||||
cmd->sta.beacon_interval = cpu_to_le16(wlvif->beacon_int);
|
cmd->sta.beacon_interval = cpu_to_le16(wlvif->beacon_int);
|
||||||
|
@ -750,14 +533,14 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||||
|
|
||||||
switch (wlvif->band) {
|
switch (wlvif->band) {
|
||||||
case IEEE80211_BAND_2GHZ:
|
case IEEE80211_BAND_2GHZ:
|
||||||
cmd->band = RADIO_BAND_2_4GHZ;
|
cmd->band = WLCORE_BAND_2_4GHZ;
|
||||||
break;
|
break;
|
||||||
case IEEE80211_BAND_5GHZ:
|
case IEEE80211_BAND_5GHZ:
|
||||||
cmd->band = RADIO_BAND_5GHZ;
|
cmd->band = WLCORE_BAND_5GHZ;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
wl1271_warning("ap start - unknown band: %d", (int)wlvif->band);
|
wl1271_warning("ap start - unknown band: %d", (int)wlvif->band);
|
||||||
cmd->band = RADIO_BAND_2_4GHZ;
|
cmd->band = WLCORE_BAND_2_4GHZ;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -830,7 +613,7 @@ int wl12xx_cmd_role_start_ibss(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||||
|
|
||||||
cmd->role_id = wlvif->role_id;
|
cmd->role_id = wlvif->role_id;
|
||||||
if (wlvif->band == IEEE80211_BAND_5GHZ)
|
if (wlvif->band == IEEE80211_BAND_5GHZ)
|
||||||
cmd->band = WL12XX_BAND_5GHZ;
|
cmd->band = WLCORE_BAND_5GHZ;
|
||||||
cmd->channel = wlvif->channel;
|
cmd->channel = wlvif->channel;
|
||||||
cmd->ibss.basic_rate_set = cpu_to_le32(wlvif->basic_rate_set);
|
cmd->ibss.basic_rate_set = cpu_to_le32(wlvif->basic_rate_set);
|
||||||
cmd->ibss.beacon_interval = cpu_to_le16(wlvif->beacon_int);
|
cmd->ibss.beacon_interval = cpu_to_le16(wlvif->beacon_int);
|
||||||
|
@ -904,6 +687,7 @@ int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer)
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(wl1271_cmd_test);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* read acx from firmware
|
* read acx from firmware
|
||||||
|
@ -960,6 +744,7 @@ int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(wl1271_cmd_configure);
|
||||||
|
|
||||||
int wl1271_cmd_data_path(struct wl1271 *wl, bool enable)
|
int wl1271_cmd_data_path(struct wl1271 *wl, bool enable)
|
||||||
{
|
{
|
||||||
|
@ -1730,10 +1515,10 @@ static int wl12xx_cmd_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||||
cmd->channel = wlvif->channel;
|
cmd->channel = wlvif->channel;
|
||||||
switch (wlvif->band) {
|
switch (wlvif->band) {
|
||||||
case IEEE80211_BAND_2GHZ:
|
case IEEE80211_BAND_2GHZ:
|
||||||
cmd->band = RADIO_BAND_2_4GHZ;
|
cmd->band = WLCORE_BAND_2_4GHZ;
|
||||||
break;
|
break;
|
||||||
case IEEE80211_BAND_5GHZ:
|
case IEEE80211_BAND_5GHZ:
|
||||||
cmd->band = RADIO_BAND_5GHZ;
|
cmd->band = WLCORE_BAND_5GHZ;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
wl1271_error("roc - unknown band: %d", (int)wlvif->band);
|
wl1271_error("roc - unknown band: %d", (int)wlvif->band);
|
|
@ -25,17 +25,12 @@
|
||||||
#ifndef __CMD_H__
|
#ifndef __CMD_H__
|
||||||
#define __CMD_H__
|
#define __CMD_H__
|
||||||
|
|
||||||
#include "wl12xx.h"
|
#include "wlcore.h"
|
||||||
|
|
||||||
struct acx_header;
|
struct acx_header;
|
||||||
|
|
||||||
int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
|
int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
|
||||||
size_t res_len);
|
size_t res_len);
|
||||||
int wl1271_cmd_general_parms(struct wl1271 *wl);
|
|
||||||
int wl128x_cmd_general_parms(struct wl1271 *wl);
|
|
||||||
int wl1271_cmd_radio_parms(struct wl1271 *wl);
|
|
||||||
int wl128x_cmd_radio_parms(struct wl1271 *wl);
|
|
||||||
int wl1271_cmd_ext_radio_parms(struct wl1271 *wl);
|
|
||||||
int wl12xx_cmd_role_enable(struct wl1271 *wl, u8 *addr, u8 role_type,
|
int wl12xx_cmd_role_enable(struct wl1271 *wl, u8 *addr, u8 role_type,
|
||||||
u8 *role_id);
|
u8 *role_id);
|
||||||
int wl12xx_cmd_role_disable(struct wl1271 *wl, u8 *role_id);
|
int wl12xx_cmd_role_disable(struct wl1271 *wl, u8 *role_id);
|
||||||
|
@ -262,13 +257,13 @@ struct wl12xx_cmd_role_disable {
|
||||||
u8 padding[3];
|
u8 padding[3];
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
enum wl12xx_band {
|
enum wlcore_band {
|
||||||
WL12XX_BAND_2_4GHZ = 0,
|
WLCORE_BAND_2_4GHZ = 0,
|
||||||
WL12XX_BAND_5GHZ = 1,
|
WLCORE_BAND_5GHZ = 1,
|
||||||
WL12XX_BAND_JAPAN_4_9_GHZ = 2,
|
WLCORE_BAND_JAPAN_4_9_GHZ = 2,
|
||||||
WL12XX_BAND_DEFAULT = WL12XX_BAND_2_4GHZ,
|
WLCORE_BAND_DEFAULT = WLCORE_BAND_2_4GHZ,
|
||||||
WL12XX_BAND_INVALID = 0x7E,
|
WLCORE_BAND_INVALID = 0x7E,
|
||||||
WL12XX_BAND_MAX_RADIO = 0x7F,
|
WLCORE_BAND_MAX_RADIO = 0x7F,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct wl12xx_cmd_role_start {
|
struct wl12xx_cmd_role_start {
|
||||||
|
@ -494,83 +489,6 @@ enum wl1271_channel_tune_bands {
|
||||||
|
|
||||||
#define WL1271_PD_REFERENCE_POINT_BAND_B_G 0
|
#define WL1271_PD_REFERENCE_POINT_BAND_B_G 0
|
||||||
|
|
||||||
#define TEST_CMD_INI_FILE_RADIO_PARAM 0x19
|
|
||||||
#define TEST_CMD_INI_FILE_GENERAL_PARAM 0x1E
|
|
||||||
#define TEST_CMD_INI_FILE_RF_EXTENDED_PARAM 0x26
|
|
||||||
|
|
||||||
struct wl1271_general_parms_cmd {
|
|
||||||
struct wl1271_cmd_header header;
|
|
||||||
|
|
||||||
struct wl1271_cmd_test_header test;
|
|
||||||
|
|
||||||
struct wl1271_ini_general_params general_params;
|
|
||||||
|
|
||||||
u8 sr_debug_table[WL1271_INI_MAX_SMART_REFLEX_PARAM];
|
|
||||||
u8 sr_sen_n_p;
|
|
||||||
u8 sr_sen_n_p_gain;
|
|
||||||
u8 sr_sen_nrn;
|
|
||||||
u8 sr_sen_prn;
|
|
||||||
u8 padding[3];
|
|
||||||
} __packed;
|
|
||||||
|
|
||||||
struct wl128x_general_parms_cmd {
|
|
||||||
struct wl1271_cmd_header header;
|
|
||||||
|
|
||||||
struct wl1271_cmd_test_header test;
|
|
||||||
|
|
||||||
struct wl128x_ini_general_params general_params;
|
|
||||||
|
|
||||||
u8 sr_debug_table[WL1271_INI_MAX_SMART_REFLEX_PARAM];
|
|
||||||
u8 sr_sen_n_p;
|
|
||||||
u8 sr_sen_n_p_gain;
|
|
||||||
u8 sr_sen_nrn;
|
|
||||||
u8 sr_sen_prn;
|
|
||||||
u8 padding[3];
|
|
||||||
} __packed;
|
|
||||||
|
|
||||||
struct wl1271_radio_parms_cmd {
|
|
||||||
struct wl1271_cmd_header header;
|
|
||||||
|
|
||||||
struct wl1271_cmd_test_header test;
|
|
||||||
|
|
||||||
/* Static radio parameters */
|
|
||||||
struct wl1271_ini_band_params_2 static_params_2;
|
|
||||||
struct wl1271_ini_band_params_5 static_params_5;
|
|
||||||
|
|
||||||
/* Dynamic radio parameters */
|
|
||||||
struct wl1271_ini_fem_params_2 dyn_params_2;
|
|
||||||
u8 padding2;
|
|
||||||
struct wl1271_ini_fem_params_5 dyn_params_5;
|
|
||||||
u8 padding3[2];
|
|
||||||
} __packed;
|
|
||||||
|
|
||||||
struct wl128x_radio_parms_cmd {
|
|
||||||
struct wl1271_cmd_header header;
|
|
||||||
|
|
||||||
struct wl1271_cmd_test_header test;
|
|
||||||
|
|
||||||
/* Static radio parameters */
|
|
||||||
struct wl128x_ini_band_params_2 static_params_2;
|
|
||||||
struct wl128x_ini_band_params_5 static_params_5;
|
|
||||||
|
|
||||||
u8 fem_vendor_and_options;
|
|
||||||
|
|
||||||
/* Dynamic radio parameters */
|
|
||||||
struct wl128x_ini_fem_params_2 dyn_params_2;
|
|
||||||
u8 padding2;
|
|
||||||
struct wl128x_ini_fem_params_5 dyn_params_5;
|
|
||||||
} __packed;
|
|
||||||
|
|
||||||
struct wl1271_ext_radio_parms_cmd {
|
|
||||||
struct wl1271_cmd_header header;
|
|
||||||
|
|
||||||
struct wl1271_cmd_test_header test;
|
|
||||||
|
|
||||||
u8 tx_per_channel_power_compensation_2[CONF_TX_PWR_COMPENSATION_LEN_2];
|
|
||||||
u8 tx_per_channel_power_compensation_5[CONF_TX_PWR_COMPENSATION_LEN_5];
|
|
||||||
u8 padding[3];
|
|
||||||
} __packed;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* There are three types of disconnections:
|
* There are three types of disconnections:
|
||||||
*
|
*
|
|
@ -65,36 +65,7 @@ enum {
|
||||||
CONF_HW_RATE_INDEX_MAX = CONF_HW_RATE_INDEX_54MBPS,
|
CONF_HW_RATE_INDEX_MAX = CONF_HW_RATE_INDEX_54MBPS,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
#define CONF_HW_RXTX_RATE_UNSUPPORTED 0xff
|
||||||
CONF_HW_RXTX_RATE_MCS7_SGI = 0,
|
|
||||||
CONF_HW_RXTX_RATE_MCS7,
|
|
||||||
CONF_HW_RXTX_RATE_MCS6,
|
|
||||||
CONF_HW_RXTX_RATE_MCS5,
|
|
||||||
CONF_HW_RXTX_RATE_MCS4,
|
|
||||||
CONF_HW_RXTX_RATE_MCS3,
|
|
||||||
CONF_HW_RXTX_RATE_MCS2,
|
|
||||||
CONF_HW_RXTX_RATE_MCS1,
|
|
||||||
CONF_HW_RXTX_RATE_MCS0,
|
|
||||||
CONF_HW_RXTX_RATE_54,
|
|
||||||
CONF_HW_RXTX_RATE_48,
|
|
||||||
CONF_HW_RXTX_RATE_36,
|
|
||||||
CONF_HW_RXTX_RATE_24,
|
|
||||||
CONF_HW_RXTX_RATE_22,
|
|
||||||
CONF_HW_RXTX_RATE_18,
|
|
||||||
CONF_HW_RXTX_RATE_12,
|
|
||||||
CONF_HW_RXTX_RATE_11,
|
|
||||||
CONF_HW_RXTX_RATE_9,
|
|
||||||
CONF_HW_RXTX_RATE_6,
|
|
||||||
CONF_HW_RXTX_RATE_5_5,
|
|
||||||
CONF_HW_RXTX_RATE_2,
|
|
||||||
CONF_HW_RXTX_RATE_1,
|
|
||||||
CONF_HW_RXTX_RATE_MAX,
|
|
||||||
CONF_HW_RXTX_RATE_UNSUPPORTED = 0xff
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Rates between and including these are MCS rates */
|
|
||||||
#define CONF_HW_RXTX_RATE_MCS_MIN CONF_HW_RXTX_RATE_MCS7_SGI
|
|
||||||
#define CONF_HW_RXTX_RATE_MCS_MAX CONF_HW_RXTX_RATE_MCS0
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
CONF_SG_DISABLE = 0,
|
CONF_SG_DISABLE = 0,
|
||||||
|
@ -1096,16 +1067,31 @@ struct conf_scan_settings {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct conf_sched_scan_settings {
|
struct conf_sched_scan_settings {
|
||||||
/* minimum time to wait on the channel for active scans (in TUs) */
|
/*
|
||||||
u16 min_dwell_time_active;
|
* The base time to wait on the channel for active scans (in TU/1000).
|
||||||
|
* The minimum dwell time is calculated according to this:
|
||||||
|
* min_dwell_time = base + num_of_probes_to_be_sent * delta_per_probe
|
||||||
|
* The maximum dwell time is calculated according to this:
|
||||||
|
* max_dwell_time = min_dwell_time + max_dwell_time_delta
|
||||||
|
*/
|
||||||
|
u32 base_dwell_time;
|
||||||
|
|
||||||
/* maximum time to wait on the channel for active scans (in TUs) */
|
/* The delta between the min dwell time and max dwell time for
|
||||||
u16 max_dwell_time_active;
|
* active scans (in TU/1000s). The max dwell time is used by the FW once
|
||||||
|
* traffic is detected on the channel.
|
||||||
|
*/
|
||||||
|
u32 max_dwell_time_delta;
|
||||||
|
|
||||||
/* time to wait on the channel for passive scans (in TUs) */
|
/* Delta added to min dwell time per each probe in 2.4 GHz (TU/1000) */
|
||||||
|
u32 dwell_time_delta_per_probe;
|
||||||
|
|
||||||
|
/* Delta added to min dwell time per each probe in 5 GHz (TU/1000) */
|
||||||
|
u32 dwell_time_delta_per_probe_5;
|
||||||
|
|
||||||
|
/* time to wait on the channel for passive scans (in TU/1000) */
|
||||||
u32 dwell_time_passive;
|
u32 dwell_time_passive;
|
||||||
|
|
||||||
/* time to wait on the channel for DFS scans (in TUs) */
|
/* time to wait on the channel for DFS scans (in TU/1000) */
|
||||||
u32 dwell_time_dfs;
|
u32 dwell_time_dfs;
|
||||||
|
|
||||||
/* number of probe requests to send on each channel in active scans */
|
/* number of probe requests to send on each channel in active scans */
|
||||||
|
@ -1118,26 +1104,6 @@ struct conf_sched_scan_settings {
|
||||||
s8 snr_threshold;
|
s8 snr_threshold;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* these are number of channels on the band divided by two, rounded up */
|
|
||||||
#define CONF_TX_PWR_COMPENSATION_LEN_2 7
|
|
||||||
#define CONF_TX_PWR_COMPENSATION_LEN_5 18
|
|
||||||
|
|
||||||
struct conf_rf_settings {
|
|
||||||
/*
|
|
||||||
* Per channel power compensation for 2.4GHz
|
|
||||||
*
|
|
||||||
* Range: s8
|
|
||||||
*/
|
|
||||||
u8 tx_per_channel_power_compensation_2[CONF_TX_PWR_COMPENSATION_LEN_2];
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Per channel power compensation for 5GHz
|
|
||||||
*
|
|
||||||
* Range: s8
|
|
||||||
*/
|
|
||||||
u8 tx_per_channel_power_compensation_5[CONF_TX_PWR_COMPENSATION_LEN_5];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct conf_ht_setting {
|
struct conf_ht_setting {
|
||||||
u8 rx_ba_win_size;
|
u8 rx_ba_win_size;
|
||||||
u8 tx_ba_win_size;
|
u8 tx_ba_win_size;
|
||||||
|
@ -1286,7 +1252,7 @@ struct conf_hangover_settings {
|
||||||
u8 window_size;
|
u8 window_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct conf_drv_settings {
|
struct wlcore_conf {
|
||||||
struct conf_sg_settings sg;
|
struct conf_sg_settings sg;
|
||||||
struct conf_rx_settings rx;
|
struct conf_rx_settings rx;
|
||||||
struct conf_tx_settings tx;
|
struct conf_tx_settings tx;
|
||||||
|
@ -1296,16 +1262,13 @@ struct conf_drv_settings {
|
||||||
struct conf_roam_trigger_settings roam_trigger;
|
struct conf_roam_trigger_settings roam_trigger;
|
||||||
struct conf_scan_settings scan;
|
struct conf_scan_settings scan;
|
||||||
struct conf_sched_scan_settings sched_scan;
|
struct conf_sched_scan_settings sched_scan;
|
||||||
struct conf_rf_settings rf;
|
|
||||||
struct conf_ht_setting ht;
|
struct conf_ht_setting ht;
|
||||||
struct conf_memory_settings mem_wl127x;
|
struct conf_memory_settings mem;
|
||||||
struct conf_memory_settings mem_wl128x;
|
|
||||||
struct conf_fm_coex fm_coex;
|
struct conf_fm_coex fm_coex;
|
||||||
struct conf_rx_streaming_settings rx_streaming;
|
struct conf_rx_streaming_settings rx_streaming;
|
||||||
struct conf_fwlog fwlog;
|
struct conf_fwlog fwlog;
|
||||||
struct conf_rate_policy_settings rate;
|
struct conf_rate_policy_settings rate;
|
||||||
struct conf_hangover_settings hangover;
|
struct conf_hangover_settings hangover;
|
||||||
u8 hci_io_ds;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -52,6 +52,7 @@ enum {
|
||||||
DEBUG_ADHOC = BIT(16),
|
DEBUG_ADHOC = BIT(16),
|
||||||
DEBUG_AP = BIT(17),
|
DEBUG_AP = BIT(17),
|
||||||
DEBUG_PROBE = BIT(18),
|
DEBUG_PROBE = BIT(18),
|
||||||
|
DEBUG_IO = BIT(19),
|
||||||
DEBUG_MASTER = (DEBUG_ADHOC | DEBUG_AP),
|
DEBUG_MASTER = (DEBUG_ADHOC | DEBUG_AP),
|
||||||
DEBUG_ALL = ~0,
|
DEBUG_ALL = ~0,
|
||||||
};
|
};
|
|
@ -26,7 +26,7 @@
|
||||||
#include <linux/skbuff.h>
|
#include <linux/skbuff.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
|
||||||
#include "wl12xx.h"
|
#include "wlcore.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "acx.h"
|
#include "acx.h"
|
||||||
#include "ps.h"
|
#include "ps.h"
|
||||||
|
@ -653,6 +653,7 @@ static ssize_t vifs_state_read(struct file *file, char __user *user_buf,
|
||||||
VIF_STATE_PRINT_INT(last_rssi_event);
|
VIF_STATE_PRINT_INT(last_rssi_event);
|
||||||
VIF_STATE_PRINT_INT(ba_support);
|
VIF_STATE_PRINT_INT(ba_support);
|
||||||
VIF_STATE_PRINT_INT(ba_allowed);
|
VIF_STATE_PRINT_INT(ba_allowed);
|
||||||
|
VIF_STATE_PRINT_INT(is_gem);
|
||||||
VIF_STATE_PRINT_LLHEX(tx_security_seq);
|
VIF_STATE_PRINT_LLHEX(tx_security_seq);
|
||||||
VIF_STATE_PRINT_INT(tx_security_last_seq_lsb);
|
VIF_STATE_PRINT_INT(tx_security_last_seq_lsb);
|
||||||
}
|
}
|
|
@ -24,7 +24,7 @@
|
||||||
#ifndef __DEBUGFS_H__
|
#ifndef __DEBUGFS_H__
|
||||||
#define __DEBUGFS_H__
|
#define __DEBUGFS_H__
|
||||||
|
|
||||||
#include "wl12xx.h"
|
#include "wlcore.h"
|
||||||
|
|
||||||
int wl1271_debugfs_init(struct wl1271 *wl);
|
int wl1271_debugfs_init(struct wl1271 *wl);
|
||||||
void wl1271_debugfs_exit(struct wl1271 *wl);
|
void wl1271_debugfs_exit(struct wl1271 *wl);
|
|
@ -21,9 +21,8 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "wl12xx.h"
|
#include "wlcore.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "reg.h"
|
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "event.h"
|
#include "event.h"
|
||||||
#include "ps.h"
|
#include "ps.h"
|
||||||
|
@ -98,8 +97,9 @@ static void wl1271_event_mbox_dump(struct event_mailbox *mbox)
|
||||||
wl1271_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask);
|
wl1271_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
|
static int wl1271_event_process(struct wl1271 *wl)
|
||||||
{
|
{
|
||||||
|
struct event_mailbox *mbox = wl->mbox;
|
||||||
struct ieee80211_vif *vif;
|
struct ieee80211_vif *vif;
|
||||||
struct wl12xx_vif *wlvif;
|
struct wl12xx_vif *wlvif;
|
||||||
u32 vector;
|
u32 vector;
|
||||||
|
@ -196,7 +196,7 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
|
||||||
bool success;
|
bool success;
|
||||||
|
|
||||||
if (!test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS,
|
if (!test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS,
|
||||||
&wl->flags))
|
&wlvif->flags))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
success = mbox->channel_switch_status ? false : true;
|
success = mbox->channel_switch_status ? false : true;
|
||||||
|
@ -278,18 +278,8 @@ int wl1271_event_unmask(struct wl1271 *wl)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void wl1271_event_mbox_config(struct wl1271 *wl)
|
|
||||||
{
|
|
||||||
wl->mbox_ptr[0] = wl1271_read32(wl, REG_EVENT_MAILBOX_PTR);
|
|
||||||
wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox);
|
|
||||||
|
|
||||||
wl1271_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x",
|
|
||||||
wl->mbox_ptr[0], wl->mbox_ptr[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num)
|
int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num)
|
||||||
{
|
{
|
||||||
struct event_mailbox mbox;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
wl1271_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num);
|
wl1271_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num);
|
||||||
|
@ -298,16 +288,19 @@ int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/* first we read the mbox descriptor */
|
/* first we read the mbox descriptor */
|
||||||
wl1271_read(wl, wl->mbox_ptr[mbox_num], &mbox,
|
wl1271_read(wl, wl->mbox_ptr[mbox_num], wl->mbox,
|
||||||
sizeof(struct event_mailbox), false);
|
sizeof(*wl->mbox), false);
|
||||||
|
|
||||||
/* process the descriptor */
|
/* process the descriptor */
|
||||||
ret = wl1271_event_process(wl, &mbox);
|
ret = wl1271_event_process(wl);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/* then we let the firmware know it can go on...*/
|
/*
|
||||||
wl1271_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK);
|
* TODO: we just need this because one bit is in a different
|
||||||
|
* place. Is there any better way?
|
||||||
|
*/
|
||||||
|
wl->ops->ack_event(wl);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
|
@ -132,8 +132,9 @@ struct event_mailbox {
|
||||||
u8 reserved_8[9];
|
u8 reserved_8[9];
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
struct wl1271;
|
||||||
|
|
||||||
int wl1271_event_unmask(struct wl1271 *wl);
|
int wl1271_event_unmask(struct wl1271 *wl);
|
||||||
void wl1271_event_mbox_config(struct wl1271 *wl);
|
|
||||||
int wl1271_event_handle(struct wl1271 *wl, u8 mbox);
|
int wl1271_event_handle(struct wl1271 *wl, u8 mbox);
|
||||||
|
|
||||||
#endif
|
#endif
|
122
drivers/net/wireless/ti/wlcore/hw_ops.h
Normal file
122
drivers/net/wireless/ti/wlcore/hw_ops.h
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
/*
|
||||||
|
* 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 "wl12xx_80211.h"
|
||||||
#include "acx.h"
|
#include "acx.h"
|
||||||
#include "cmd.h"
|
#include "cmd.h"
|
||||||
#include "reg.h"
|
|
||||||
#include "tx.h"
|
#include "tx.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
|
#include "hw_ops.h"
|
||||||
|
|
||||||
int wl1271_init_templates_config(struct wl1271 *wl)
|
int wl1271_init_templates_config(struct wl1271 *wl)
|
||||||
{
|
{
|
||||||
|
@ -319,7 +319,7 @@ static int wl12xx_init_fwlog(struct wl1271 *wl)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED)
|
if (wl->quirks & WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
ret = wl12xx_cmd_config_fwlog(wl);
|
ret = wl12xx_cmd_config_fwlog(wl);
|
||||||
|
@ -494,26 +494,6 @@ static int wl1271_set_ba_policies(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||||
return wl12xx_acx_set_ba_initiator_policy(wl, wlvif);
|
return wl12xx_acx_set_ba_initiator_policy(wl, wlvif);
|
||||||
}
|
}
|
||||||
|
|
||||||
int wl1271_chip_specific_init(struct wl1271 *wl)
|
|
||||||
{
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
if (wl->chip.id == CHIP_ID_1283_PG20) {
|
|
||||||
u32 host_cfg_bitmap = HOST_IF_CFG_RX_FIFO_ENABLE;
|
|
||||||
|
|
||||||
if (!(wl->quirks & WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT))
|
|
||||||
/* Enable SDIO padding */
|
|
||||||
host_cfg_bitmap |= HOST_IF_CFG_TX_PAD_TO_SDIO_BLK;
|
|
||||||
|
|
||||||
/* Must be before wl1271_acx_init_mem_config() */
|
|
||||||
ret = wl1271_acx_host_if_cfg_bitmap(wl, host_cfg_bitmap);
|
|
||||||
if (ret < 0)
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
out:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* vif-specifc initialization */
|
/* vif-specifc initialization */
|
||||||
static int wl12xx_init_sta_role(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
static int wl12xx_init_sta_role(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||||
{
|
{
|
||||||
|
@ -582,12 +562,19 @@ int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif)
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
} else if (!wl->sta_count) {
|
} else if (!wl->sta_count) {
|
||||||
|
if (wl->quirks & WLCORE_QUIRK_NO_ELP) {
|
||||||
|
/* Configure for power always on */
|
||||||
|
ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
} else {
|
||||||
/* Configure for ELP power saving */
|
/* Configure for ELP power saving */
|
||||||
ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
|
ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Mode specific init */
|
/* Mode specific init */
|
||||||
if (is_ap) {
|
if (is_ap) {
|
||||||
|
@ -652,6 +639,10 @@ int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif)
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
ret = wlcore_hw_init_vif(wl, wlvif);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -659,27 +650,8 @@ int wl1271_hw_init(struct wl1271 *wl)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (wl->chip.id == CHIP_ID_1283_PG20) {
|
/* Chip-specific hw init */
|
||||||
ret = wl128x_cmd_general_parms(wl);
|
ret = wl->ops->hw_init(wl);
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
ret = wl128x_cmd_radio_parms(wl);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
} else {
|
|
||||||
ret = wl1271_cmd_general_parms(wl);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
ret = wl1271_cmd_radio_parms(wl);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
ret = wl1271_cmd_ext_radio_parms(wl);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Chip-specific init */
|
|
||||||
ret = wl1271_chip_specific_init(wl);
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
#ifndef __INIT_H__
|
#ifndef __INIT_H__
|
||||||
#define __INIT_H__
|
#define __INIT_H__
|
||||||
|
|
||||||
#include "wl12xx.h"
|
#include "wlcore.h"
|
||||||
|
|
||||||
int wl1271_hw_init_power_auth(struct wl1271 *wl);
|
int wl1271_hw_init_power_auth(struct wl1271 *wl);
|
||||||
int wl1271_init_templates_config(struct wl1271 *wl);
|
int wl1271_init_templates_config(struct wl1271 *wl);
|
|
@ -26,84 +26,12 @@
|
||||||
#include <linux/spi/spi.h>
|
#include <linux/spi/spi.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
|
|
||||||
#include "wl12xx.h"
|
#include "wlcore.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "wl12xx_80211.h"
|
#include "wl12xx_80211.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "tx.h"
|
#include "tx.h"
|
||||||
|
|
||||||
#define OCP_CMD_LOOP 32
|
|
||||||
|
|
||||||
#define OCP_CMD_WRITE 0x1
|
|
||||||
#define OCP_CMD_READ 0x2
|
|
||||||
|
|
||||||
#define OCP_READY_MASK BIT(18)
|
|
||||||
#define OCP_STATUS_MASK (BIT(16) | BIT(17))
|
|
||||||
|
|
||||||
#define OCP_STATUS_NO_RESP 0x00000
|
|
||||||
#define OCP_STATUS_OK 0x10000
|
|
||||||
#define OCP_STATUS_REQ_FAILED 0x20000
|
|
||||||
#define OCP_STATUS_RESP_ERROR 0x30000
|
|
||||||
|
|
||||||
struct wl1271_partition_set wl12xx_part_table[PART_TABLE_LEN] = {
|
|
||||||
[PART_DOWN] = {
|
|
||||||
.mem = {
|
|
||||||
.start = 0x00000000,
|
|
||||||
.size = 0x000177c0
|
|
||||||
},
|
|
||||||
.reg = {
|
|
||||||
.start = REGISTERS_BASE,
|
|
||||||
.size = 0x00008800
|
|
||||||
},
|
|
||||||
.mem2 = {
|
|
||||||
.start = 0x00000000,
|
|
||||||
.size = 0x00000000
|
|
||||||
},
|
|
||||||
.mem3 = {
|
|
||||||
.start = 0x00000000,
|
|
||||||
.size = 0x00000000
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
[PART_WORK] = {
|
|
||||||
.mem = {
|
|
||||||
.start = 0x00040000,
|
|
||||||
.size = 0x00014fc0
|
|
||||||
},
|
|
||||||
.reg = {
|
|
||||||
.start = REGISTERS_BASE,
|
|
||||||
.size = 0x0000a000
|
|
||||||
},
|
|
||||||
.mem2 = {
|
|
||||||
.start = 0x003004f8,
|
|
||||||
.size = 0x00000004
|
|
||||||
},
|
|
||||||
.mem3 = {
|
|
||||||
.start = 0x00040404,
|
|
||||||
.size = 0x00000000
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
[PART_DRPW] = {
|
|
||||||
.mem = {
|
|
||||||
.start = 0x00040000,
|
|
||||||
.size = 0x00014fc0
|
|
||||||
},
|
|
||||||
.reg = {
|
|
||||||
.start = DRPW_BASE,
|
|
||||||
.size = 0x00006000
|
|
||||||
},
|
|
||||||
.mem2 = {
|
|
||||||
.start = 0x00000000,
|
|
||||||
.size = 0x00000000
|
|
||||||
},
|
|
||||||
.mem3 = {
|
|
||||||
.start = 0x00000000,
|
|
||||||
.size = 0x00000000
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
bool wl1271_set_block_size(struct wl1271 *wl)
|
bool wl1271_set_block_size(struct wl1271 *wl)
|
||||||
{
|
{
|
||||||
if (wl->if_ops->set_block_size) {
|
if (wl->if_ops->set_block_size) {
|
||||||
|
@ -114,17 +42,53 @@ bool wl1271_set_block_size(struct wl1271 *wl)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void wl1271_disable_interrupts(struct wl1271 *wl)
|
void wlcore_disable_interrupts(struct wl1271 *wl)
|
||||||
{
|
{
|
||||||
disable_irq(wl->irq);
|
disable_irq(wl->irq);
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(wlcore_disable_interrupts);
|
||||||
|
|
||||||
void wl1271_enable_interrupts(struct wl1271 *wl)
|
void wlcore_enable_interrupts(struct wl1271 *wl)
|
||||||
{
|
{
|
||||||
enable_irq(wl->irq);
|
enable_irq(wl->irq);
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(wlcore_enable_interrupts);
|
||||||
|
|
||||||
/* 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
|
* To simplify driver code, a fixed (virtual) memory map is defined for
|
||||||
* register and memory addresses. Because in the chipset, in different stages
|
* register and memory addresses. Because in the chipset, in different stages
|
||||||
|
@ -158,33 +122,43 @@ void wl1271_enable_interrupts(struct wl1271 *wl)
|
||||||
* | |
|
* | |
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int wl1271_set_partition(struct wl1271 *wl,
|
void wlcore_set_partition(struct wl1271 *wl,
|
||||||
struct wl1271_partition_set *p)
|
const struct wlcore_partition_set *p)
|
||||||
{
|
{
|
||||||
/* copy partition info */
|
/* copy partition info */
|
||||||
memcpy(&wl->part, p, sizeof(*p));
|
memcpy(&wl->curr_part, p, sizeof(*p));
|
||||||
|
|
||||||
wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
|
wl1271_debug(DEBUG_IO, "mem_start %08X mem_size %08X",
|
||||||
p->mem.start, p->mem.size);
|
p->mem.start, p->mem.size);
|
||||||
wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
|
wl1271_debug(DEBUG_IO, "reg_start %08X reg_size %08X",
|
||||||
p->reg.start, p->reg.size);
|
p->reg.start, p->reg.size);
|
||||||
wl1271_debug(DEBUG_SPI, "mem2_start %08X mem2_size %08X",
|
wl1271_debug(DEBUG_IO, "mem2_start %08X mem2_size %08X",
|
||||||
p->mem2.start, p->mem2.size);
|
p->mem2.start, p->mem2.size);
|
||||||
wl1271_debug(DEBUG_SPI, "mem3_start %08X mem3_size %08X",
|
wl1271_debug(DEBUG_IO, "mem3_start %08X mem3_size %08X",
|
||||||
p->mem3.start, p->mem3.size);
|
p->mem3.start, p->mem3.size);
|
||||||
|
|
||||||
/* write partition info to the chipset */
|
|
||||||
wl1271_raw_write32(wl, HW_PART0_START_ADDR, p->mem.start);
|
wl1271_raw_write32(wl, HW_PART0_START_ADDR, p->mem.start);
|
||||||
wl1271_raw_write32(wl, HW_PART0_SIZE_ADDR, p->mem.size);
|
wl1271_raw_write32(wl, HW_PART0_SIZE_ADDR, p->mem.size);
|
||||||
wl1271_raw_write32(wl, HW_PART1_START_ADDR, p->reg.start);
|
wl1271_raw_write32(wl, HW_PART1_START_ADDR, p->reg.start);
|
||||||
wl1271_raw_write32(wl, HW_PART1_SIZE_ADDR, p->reg.size);
|
wl1271_raw_write32(wl, HW_PART1_SIZE_ADDR, p->reg.size);
|
||||||
wl1271_raw_write32(wl, HW_PART2_START_ADDR, p->mem2.start);
|
wl1271_raw_write32(wl, HW_PART2_START_ADDR, p->mem2.start);
|
||||||
wl1271_raw_write32(wl, HW_PART2_SIZE_ADDR, p->mem2.size);
|
wl1271_raw_write32(wl, HW_PART2_SIZE_ADDR, p->mem2.size);
|
||||||
|
/*
|
||||||
|
* We don't need the size of the last partition, as it is
|
||||||
|
* automatically calculated based on the total memory size and
|
||||||
|
* the sizes of the previous partitions.
|
||||||
|
*/
|
||||||
wl1271_raw_write32(wl, HW_PART3_START_ADDR, p->mem3.start);
|
wl1271_raw_write32(wl, HW_PART3_START_ADDR, p->mem3.start);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(wl1271_set_partition);
|
EXPORT_SYMBOL_GPL(wlcore_set_partition);
|
||||||
|
|
||||||
|
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(wlcore_select_partition);
|
||||||
|
|
||||||
void wl1271_io_reset(struct wl1271 *wl)
|
void wl1271_io_reset(struct wl1271 *wl)
|
||||||
{
|
{
|
||||||
|
@ -197,48 +171,3 @@ void wl1271_io_init(struct wl1271 *wl)
|
||||||
if (wl->if_ops->init)
|
if (wl->if_ops->init)
|
||||||
wl->if_ops->init(wl->dev);
|
wl->if_ops->init(wl->dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val)
|
|
||||||
{
|
|
||||||
/* write address >> 1 + 0x30000 to OCP_POR_CTR */
|
|
||||||
addr = (addr >> 1) + 0x30000;
|
|
||||||
wl1271_write32(wl, OCP_POR_CTR, addr);
|
|
||||||
|
|
||||||
/* write value to OCP_POR_WDATA */
|
|
||||||
wl1271_write32(wl, OCP_DATA_WRITE, val);
|
|
||||||
|
|
||||||
/* write 1 to OCP_CMD */
|
|
||||||
wl1271_write32(wl, OCP_CMD, OCP_CMD_WRITE);
|
|
||||||
}
|
|
||||||
|
|
||||||
u16 wl1271_top_reg_read(struct wl1271 *wl, int addr)
|
|
||||||
{
|
|
||||||
u32 val;
|
|
||||||
int timeout = OCP_CMD_LOOP;
|
|
||||||
|
|
||||||
/* write address >> 1 + 0x30000 to OCP_POR_CTR */
|
|
||||||
addr = (addr >> 1) + 0x30000;
|
|
||||||
wl1271_write32(wl, OCP_POR_CTR, addr);
|
|
||||||
|
|
||||||
/* write 2 to OCP_CMD */
|
|
||||||
wl1271_write32(wl, OCP_CMD, OCP_CMD_READ);
|
|
||||||
|
|
||||||
/* poll for data ready */
|
|
||||||
do {
|
|
||||||
val = wl1271_read32(wl, OCP_DATA_READ);
|
|
||||||
} while (!(val & OCP_READY_MASK) && --timeout);
|
|
||||||
|
|
||||||
if (!timeout) {
|
|
||||||
wl1271_warning("Top register access timed out.");
|
|
||||||
return 0xffff;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* check data status and return if OK */
|
|
||||||
if ((val & OCP_STATUS_MASK) == OCP_STATUS_OK)
|
|
||||||
return val & 0xffff;
|
|
||||||
else {
|
|
||||||
wl1271_warning("Top register access returned error.");
|
|
||||||
return 0xffff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -26,7 +26,6 @@
|
||||||
#define __IO_H__
|
#define __IO_H__
|
||||||
|
|
||||||
#include <linux/irqreturn.h>
|
#include <linux/irqreturn.h>
|
||||||
#include "reg.h"
|
|
||||||
|
|
||||||
#define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0
|
#define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0
|
||||||
|
|
||||||
|
@ -43,15 +42,14 @@
|
||||||
|
|
||||||
#define HW_ACCESS_PRAM_MAX_RANGE 0x3c000
|
#define HW_ACCESS_PRAM_MAX_RANGE 0x3c000
|
||||||
|
|
||||||
extern struct wl1271_partition_set wl12xx_part_table[PART_TABLE_LEN];
|
|
||||||
|
|
||||||
struct wl1271;
|
struct wl1271;
|
||||||
|
|
||||||
void wl1271_disable_interrupts(struct wl1271 *wl);
|
void wlcore_disable_interrupts(struct wl1271 *wl);
|
||||||
void wl1271_enable_interrupts(struct wl1271 *wl);
|
void wlcore_enable_interrupts(struct wl1271 *wl);
|
||||||
|
|
||||||
void wl1271_io_reset(struct wl1271 *wl);
|
void wl1271_io_reset(struct wl1271 *wl);
|
||||||
void wl1271_io_init(struct wl1271 *wl);
|
void wl1271_io_init(struct wl1271 *wl);
|
||||||
|
int wlcore_translate_addr(struct wl1271 *wl, int addr);
|
||||||
|
|
||||||
/* Raw target IO, address is not translated */
|
/* Raw target IO, address is not translated */
|
||||||
static inline void wl1271_raw_write(struct wl1271 *wl, int addr, void *buf,
|
static inline void wl1271_raw_write(struct wl1271 *wl, int addr, void *buf,
|
||||||
|
@ -66,6 +64,18 @@ static inline void wl1271_raw_read(struct wl1271 *wl, int addr, void *buf,
|
||||||
wl->if_ops->read(wl->dev, addr, buf, len, fixed);
|
wl->if_ops->read(wl->dev, addr, buf, len, fixed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void wlcore_raw_read_data(struct wl1271 *wl, int reg, void *buf,
|
||||||
|
size_t len, bool fixed)
|
||||||
|
{
|
||||||
|
wl1271_raw_read(wl, wl->rtable[reg], buf, len, fixed);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void wlcore_raw_write_data(struct wl1271 *wl, int reg, void *buf,
|
||||||
|
size_t len, bool fixed)
|
||||||
|
{
|
||||||
|
wl1271_raw_write(wl, wl->rtable[reg], buf, len, fixed);
|
||||||
|
}
|
||||||
|
|
||||||
static inline u32 wl1271_raw_read32(struct wl1271 *wl, int addr)
|
static inline u32 wl1271_raw_read32(struct wl1271 *wl, int addr)
|
||||||
{
|
{
|
||||||
wl1271_raw_read(wl, addr, &wl->buffer_32,
|
wl1271_raw_read(wl, addr, &wl->buffer_32,
|
||||||
|
@ -81,36 +91,12 @@ static inline void wl1271_raw_write32(struct wl1271 *wl, int addr, u32 val)
|
||||||
sizeof(wl->buffer_32), false);
|
sizeof(wl->buffer_32), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Translated target IO */
|
|
||||||
static inline int wl1271_translate_addr(struct wl1271 *wl, int addr)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* To translate, first check to which window of addresses the
|
|
||||||
* particular address belongs. Then subtract the starting address
|
|
||||||
* of that window from the address. Then, add offset of the
|
|
||||||
* translated region.
|
|
||||||
*
|
|
||||||
* The translated regions occur next to each other in physical device
|
|
||||||
* memory, so just add the sizes of the preceding address regions to
|
|
||||||
* get the offset to the new region.
|
|
||||||
*
|
|
||||||
* Currently, only the two first regions are addressed, and the
|
|
||||||
* assumption is that all addresses will fall into either of those
|
|
||||||
* two.
|
|
||||||
*/
|
|
||||||
if ((addr >= wl->part.reg.start) &&
|
|
||||||
(addr < wl->part.reg.start + wl->part.reg.size))
|
|
||||||
return addr - wl->part.reg.start + wl->part.mem.size;
|
|
||||||
else
|
|
||||||
return addr - wl->part.mem.start;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void wl1271_read(struct wl1271 *wl, int addr, void *buf,
|
static inline void wl1271_read(struct wl1271 *wl, int addr, void *buf,
|
||||||
size_t len, bool fixed)
|
size_t len, bool fixed)
|
||||||
{
|
{
|
||||||
int physical;
|
int physical;
|
||||||
|
|
||||||
physical = wl1271_translate_addr(wl, addr);
|
physical = wlcore_translate_addr(wl, addr);
|
||||||
|
|
||||||
wl1271_raw_read(wl, physical, buf, len, fixed);
|
wl1271_raw_read(wl, physical, buf, len, fixed);
|
||||||
}
|
}
|
||||||
|
@ -120,11 +106,23 @@ static inline void wl1271_write(struct wl1271 *wl, int addr, void *buf,
|
||||||
{
|
{
|
||||||
int physical;
|
int physical;
|
||||||
|
|
||||||
physical = wl1271_translate_addr(wl, addr);
|
physical = wlcore_translate_addr(wl, addr);
|
||||||
|
|
||||||
wl1271_raw_write(wl, physical, buf, len, fixed);
|
wl1271_raw_write(wl, physical, buf, len, fixed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void wlcore_write_data(struct wl1271 *wl, int reg, void *buf,
|
||||||
|
size_t len, bool fixed)
|
||||||
|
{
|
||||||
|
wl1271_write(wl, wl->rtable[reg], buf, len, fixed);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void wlcore_read_data(struct wl1271 *wl, int reg, void *buf,
|
||||||
|
size_t len, bool fixed)
|
||||||
|
{
|
||||||
|
wl1271_read(wl, wl->rtable[reg], buf, len, fixed);
|
||||||
|
}
|
||||||
|
|
||||||
static inline void wl1271_read_hwaddr(struct wl1271 *wl, int hwaddr,
|
static inline void wl1271_read_hwaddr(struct wl1271 *wl, int hwaddr,
|
||||||
void *buf, size_t len, bool fixed)
|
void *buf, size_t len, bool fixed)
|
||||||
{
|
{
|
||||||
|
@ -134,19 +132,30 @@ static inline void wl1271_read_hwaddr(struct wl1271 *wl, int hwaddr,
|
||||||
/* Addresses are stored internally as addresses to 32 bytes blocks */
|
/* Addresses are stored internally as addresses to 32 bytes blocks */
|
||||||
addr = hwaddr << 5;
|
addr = hwaddr << 5;
|
||||||
|
|
||||||
physical = wl1271_translate_addr(wl, addr);
|
physical = wlcore_translate_addr(wl, addr);
|
||||||
|
|
||||||
wl1271_raw_read(wl, physical, buf, len, fixed);
|
wl1271_raw_read(wl, physical, buf, len, fixed);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u32 wl1271_read32(struct wl1271 *wl, int addr)
|
static inline u32 wl1271_read32(struct wl1271 *wl, int addr)
|
||||||
{
|
{
|
||||||
return wl1271_raw_read32(wl, wl1271_translate_addr(wl, addr));
|
return wl1271_raw_read32(wl, wlcore_translate_addr(wl, addr));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void wl1271_write32(struct wl1271 *wl, int addr, u32 val)
|
static inline void wl1271_write32(struct wl1271 *wl, int addr, u32 val)
|
||||||
{
|
{
|
||||||
wl1271_raw_write32(wl, wl1271_translate_addr(wl, addr), val);
|
wl1271_raw_write32(wl, wlcore_translate_addr(wl, addr), val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline u32 wlcore_read_reg(struct wl1271 *wl, int reg)
|
||||||
|
{
|
||||||
|
return wl1271_raw_read32(wl,
|
||||||
|
wlcore_translate_addr(wl, wl->rtable[reg]));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void wlcore_write_reg(struct wl1271 *wl, int reg, u32 val)
|
||||||
|
{
|
||||||
|
wl1271_raw_write32(wl, wlcore_translate_addr(wl, wl->rtable[reg]), val);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void wl1271_power_off(struct wl1271 *wl)
|
static inline void wl1271_power_off(struct wl1271 *wl)
|
||||||
|
@ -164,13 +173,8 @@ static inline int wl1271_power_on(struct wl1271 *wl)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void wlcore_set_partition(struct wl1271 *wl,
|
||||||
/* Top Register IO */
|
const struct wlcore_partition_set *p);
|
||||||
void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val);
|
|
||||||
u16 wl1271_top_reg_read(struct wl1271 *wl, int addr);
|
|
||||||
|
|
||||||
int wl1271_set_partition(struct wl1271 *wl,
|
|
||||||
struct wl1271_partition_set *p);
|
|
||||||
|
|
||||||
bool wl1271_set_block_size(struct wl1271 *wl);
|
bool wl1271_set_block_size(struct wl1271 *wl);
|
||||||
|
|
||||||
|
@ -178,4 +182,6 @@ bool wl1271_set_block_size(struct wl1271 *wl);
|
||||||
|
|
||||||
int wl1271_tx_dummy_packet(struct wl1271 *wl);
|
int wl1271_tx_dummy_packet(struct wl1271 *wl);
|
||||||
|
|
||||||
|
void wlcore_select_partition(struct wl1271 *wl, u8 part);
|
||||||
|
|
||||||
#endif
|
#endif
|
File diff suppressed because it is too large
Load diff
|
@ -21,7 +21,6 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "reg.h"
|
|
||||||
#include "ps.h"
|
#include "ps.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "tx.h"
|
#include "tx.h"
|
||||||
|
@ -62,7 +61,7 @@ void wl1271_elp_work(struct work_struct *work)
|
||||||
}
|
}
|
||||||
|
|
||||||
wl1271_debug(DEBUG_PSM, "chip to elp");
|
wl1271_debug(DEBUG_PSM, "chip to elp");
|
||||||
wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP);
|
wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_SLEEP);
|
||||||
set_bit(WL1271_FLAG_IN_ELP, &wl->flags);
|
set_bit(WL1271_FLAG_IN_ELP, &wl->flags);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
@ -74,6 +73,9 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl)
|
||||||
{
|
{
|
||||||
struct wl12xx_vif *wlvif;
|
struct wl12xx_vif *wlvif;
|
||||||
|
|
||||||
|
if (wl->quirks & WLCORE_QUIRK_NO_ELP)
|
||||||
|
return;
|
||||||
|
|
||||||
/* we shouldn't get consecutive sleep requests */
|
/* we shouldn't get consecutive sleep requests */
|
||||||
if (WARN_ON(test_and_set_bit(WL1271_FLAG_ELP_REQUESTED, &wl->flags)))
|
if (WARN_ON(test_and_set_bit(WL1271_FLAG_ELP_REQUESTED, &wl->flags)))
|
||||||
return;
|
return;
|
||||||
|
@ -125,7 +127,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl)
|
||||||
wl->elp_compl = &compl;
|
wl->elp_compl = &compl;
|
||||||
spin_unlock_irqrestore(&wl->wl_lock, flags);
|
spin_unlock_irqrestore(&wl->wl_lock, flags);
|
||||||
|
|
||||||
wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP);
|
wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_WAKE_UP);
|
||||||
|
|
||||||
if (!pending) {
|
if (!pending) {
|
||||||
ret = wait_for_completion_timeout(
|
ret = wait_for_completion_timeout(
|
|
@ -24,7 +24,7 @@
|
||||||
#ifndef __PS_H__
|
#ifndef __PS_H__
|
||||||
#define __PS_H__
|
#define __PS_H__
|
||||||
|
|
||||||
#include "wl12xx.h"
|
#include "wlcore.h"
|
||||||
#include "acx.h"
|
#include "acx.h"
|
||||||
|
|
||||||
int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
|
@ -24,34 +24,36 @@
|
||||||
#include <linux/gfp.h>
|
#include <linux/gfp.h>
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
|
|
||||||
#include "wl12xx.h"
|
#include "wlcore.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "acx.h"
|
#include "acx.h"
|
||||||
#include "reg.h"
|
|
||||||
#include "rx.h"
|
#include "rx.h"
|
||||||
#include "tx.h"
|
#include "tx.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
|
#include "hw_ops.h"
|
||||||
|
|
||||||
static u8 wl12xx_rx_get_mem_block(struct wl12xx_fw_status *status,
|
/*
|
||||||
u32 drv_rx_counter)
|
* TODO: this is here just for now, it must be removed when the data
|
||||||
|
* operations are in place.
|
||||||
|
*/
|
||||||
|
#include "../wl12xx/reg.h"
|
||||||
|
|
||||||
|
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]) &
|
if (wl->quirks & WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN)
|
||||||
RX_MEM_BLOCK_MASK;
|
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 u32 wl12xx_rx_get_buf_size(struct wl12xx_fw_status *status,
|
static u32 wlcore_rx_get_align_buf_size(struct wl1271 *wl, u32 pkt_len)
|
||||||
u32 drv_rx_counter)
|
|
||||||
{
|
{
|
||||||
return (le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]) &
|
if (wl->quirks & WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN)
|
||||||
RX_BUF_SIZE_MASK) >> RX_BUF_SIZE_SHIFT_DIV;
|
return ALIGN(pkt_len, WL12XX_BUS_BLOCK_SIZE);
|
||||||
}
|
|
||||||
|
|
||||||
static bool wl12xx_rx_get_unaligned(struct wl12xx_fw_status *status,
|
return pkt_len;
|
||||||
u32 drv_rx_counter)
|
|
||||||
{
|
|
||||||
/* Convert the value to bool */
|
|
||||||
return !!(le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]) &
|
|
||||||
RX_BUF_UNALIGNED_PAYLOAD);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wl1271_rx_status(struct wl1271 *wl,
|
static void wl1271_rx_status(struct wl1271 *wl,
|
||||||
|
@ -66,10 +68,10 @@ static void wl1271_rx_status(struct wl1271 *wl,
|
||||||
else
|
else
|
||||||
status->band = IEEE80211_BAND_5GHZ;
|
status->band = IEEE80211_BAND_5GHZ;
|
||||||
|
|
||||||
status->rate_idx = wl1271_rate_to_idx(desc->rate, status->band);
|
status->rate_idx = wlcore_rate_to_idx(wl, desc->rate, status->band);
|
||||||
|
|
||||||
/* 11n support */
|
/* 11n support */
|
||||||
if (desc->rate <= CONF_HW_RXTX_RATE_MCS0)
|
if (desc->rate <= wl->hw_min_ht_rate)
|
||||||
status->flag |= RX_FLAG_HT;
|
status->flag |= RX_FLAG_HT;
|
||||||
|
|
||||||
status->signal = desc->rssi;
|
status->signal = desc->rssi;
|
||||||
|
@ -98,7 +100,7 @@ static void wl1271_rx_status(struct wl1271 *wl,
|
||||||
}
|
}
|
||||||
|
|
||||||
static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
|
static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
|
||||||
bool unaligned, u8 *hlid)
|
enum wl_rx_buf_align rx_align, u8 *hlid)
|
||||||
{
|
{
|
||||||
struct wl1271_rx_descriptor *desc;
|
struct wl1271_rx_descriptor *desc;
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
|
@ -106,8 +108,9 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
|
||||||
u8 *buf;
|
u8 *buf;
|
||||||
u8 beacon = 0;
|
u8 beacon = 0;
|
||||||
u8 is_data = 0;
|
u8 is_data = 0;
|
||||||
u8 reserved = unaligned ? NET_IP_ALIGN : 0;
|
u8 reserved = 0;
|
||||||
u16 seq_num;
|
u16 seq_num;
|
||||||
|
u32 pkt_data_len;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In PLT mode we seem to get frames and mac80211 warns about them,
|
* In PLT mode we seem to get frames and mac80211 warns about them,
|
||||||
|
@ -116,6 +119,16 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
|
||||||
if (unlikely(wl->plt))
|
if (unlikely(wl->plt))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
pkt_data_len = wlcore_hw_get_rx_packet_len(wl, data, length);
|
||||||
|
if (!pkt_data_len) {
|
||||||
|
wl1271_error("Invalid packet arrived from HW. length %d",
|
||||||
|
length);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rx_align == WLCORE_RX_BUF_UNALIGNED)
|
||||||
|
reserved = NET_IP_ALIGN;
|
||||||
|
|
||||||
/* the data read starts with the descriptor */
|
/* the data read starts with the descriptor */
|
||||||
desc = (struct wl1271_rx_descriptor *) data;
|
desc = (struct wl1271_rx_descriptor *) data;
|
||||||
|
|
||||||
|
@ -142,8 +155,8 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* skb length not included rx descriptor */
|
/* skb length not including rx descriptor */
|
||||||
skb = __dev_alloc_skb(length + reserved - sizeof(*desc), GFP_KERNEL);
|
skb = __dev_alloc_skb(pkt_data_len + reserved, GFP_KERNEL);
|
||||||
if (!skb) {
|
if (!skb) {
|
||||||
wl1271_error("Couldn't allocate RX frame");
|
wl1271_error("Couldn't allocate RX frame");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -152,7 +165,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
|
||||||
/* reserve the unaligned payload(if any) */
|
/* reserve the unaligned payload(if any) */
|
||||||
skb_reserve(skb, reserved);
|
skb_reserve(skb, reserved);
|
||||||
|
|
||||||
buf = skb_put(skb, length - sizeof(*desc));
|
buf = skb_put(skb, pkt_data_len);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copy packets from aggregation buffer to the skbs without rx
|
* Copy packets from aggregation buffer to the skbs without rx
|
||||||
|
@ -160,7 +173,10 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
|
||||||
* packets copy the packets in offset of 2 bytes guarantee IP header
|
* packets copy the packets in offset of 2 bytes guarantee IP header
|
||||||
* payload aligned to 4 bytes.
|
* payload aligned to 4 bytes.
|
||||||
*/
|
*/
|
||||||
memcpy(buf, data + sizeof(*desc), length - sizeof(*desc));
|
memcpy(buf, data + sizeof(*desc), pkt_data_len);
|
||||||
|
if (rx_align == WLCORE_RX_BUF_PADDED)
|
||||||
|
skb_pull(skb, NET_IP_ALIGN);
|
||||||
|
|
||||||
*hlid = desc->hlid;
|
*hlid = desc->hlid;
|
||||||
|
|
||||||
hdr = (struct ieee80211_hdr *)skb->data;
|
hdr = (struct ieee80211_hdr *)skb->data;
|
||||||
|
@ -177,36 +193,35 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
|
||||||
beacon ? "beacon" : "",
|
beacon ? "beacon" : "",
|
||||||
seq_num, *hlid);
|
seq_num, *hlid);
|
||||||
|
|
||||||
skb_trim(skb, skb->len - desc->pad_len);
|
|
||||||
|
|
||||||
skb_queue_tail(&wl->deferred_rx_queue, skb);
|
skb_queue_tail(&wl->deferred_rx_queue, skb);
|
||||||
queue_work(wl->freezable_wq, &wl->netstack_work);
|
queue_work(wl->freezable_wq, &wl->netstack_work);
|
||||||
|
|
||||||
return is_data;
|
return is_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void wl12xx_rx(struct wl1271 *wl, struct wl12xx_fw_status *status)
|
void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status *status)
|
||||||
{
|
{
|
||||||
struct wl1271_acx_mem_map *wl_mem_map = wl->target_mem_map;
|
|
||||||
unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0};
|
unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0};
|
||||||
u32 buf_size;
|
u32 buf_size;
|
||||||
u32 fw_rx_counter = status->fw_rx_counter & NUM_RX_PKT_DESC_MOD_MASK;
|
u32 fw_rx_counter = status->fw_rx_counter & NUM_RX_PKT_DESC_MOD_MASK;
|
||||||
u32 drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK;
|
u32 drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK;
|
||||||
u32 rx_counter;
|
u32 rx_counter;
|
||||||
u32 mem_block;
|
u32 pkt_len, align_pkt_len;
|
||||||
u32 pkt_length;
|
u32 pkt_offset, des;
|
||||||
u32 pkt_offset;
|
|
||||||
u8 hlid;
|
u8 hlid;
|
||||||
bool unaligned = false;
|
enum wl_rx_buf_align rx_align;
|
||||||
|
|
||||||
while (drv_rx_counter != fw_rx_counter) {
|
while (drv_rx_counter != fw_rx_counter) {
|
||||||
buf_size = 0;
|
buf_size = 0;
|
||||||
rx_counter = drv_rx_counter;
|
rx_counter = drv_rx_counter;
|
||||||
while (rx_counter != fw_rx_counter) {
|
while (rx_counter != fw_rx_counter) {
|
||||||
pkt_length = wl12xx_rx_get_buf_size(status, rx_counter);
|
des = le32_to_cpu(status->rx_pkt_descs[rx_counter]);
|
||||||
if (buf_size + pkt_length > WL1271_AGGR_BUFFER_SIZE)
|
pkt_len = wlcore_rx_get_buf_size(wl, des);
|
||||||
|
align_pkt_len = wlcore_rx_get_align_buf_size(wl,
|
||||||
|
pkt_len);
|
||||||
|
if (buf_size + align_pkt_len > WL1271_AGGR_BUFFER_SIZE)
|
||||||
break;
|
break;
|
||||||
buf_size += pkt_length;
|
buf_size += align_pkt_len;
|
||||||
rx_counter++;
|
rx_counter++;
|
||||||
rx_counter &= NUM_RX_PKT_DESC_MOD_MASK;
|
rx_counter &= NUM_RX_PKT_DESC_MOD_MASK;
|
||||||
}
|
}
|
||||||
|
@ -216,38 +231,18 @@ void wl12xx_rx(struct wl1271 *wl, struct wl12xx_fw_status *status)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wl->chip.id != CHIP_ID_1283_PG20) {
|
|
||||||
/*
|
|
||||||
* Choose the block we want to read
|
|
||||||
* For aggregated packets, only the first memory block
|
|
||||||
* should be retrieved. The FW takes care of the rest.
|
|
||||||
*/
|
|
||||||
mem_block = wl12xx_rx_get_mem_block(status,
|
|
||||||
drv_rx_counter);
|
|
||||||
|
|
||||||
wl->rx_mem_pool_addr.addr = (mem_block << 8) +
|
|
||||||
le32_to_cpu(wl_mem_map->packet_memory_pool_start);
|
|
||||||
|
|
||||||
wl->rx_mem_pool_addr.addr_extra =
|
|
||||||
wl->rx_mem_pool_addr.addr + 4;
|
|
||||||
|
|
||||||
wl1271_write(wl, WL1271_SLV_REG_DATA,
|
|
||||||
&wl->rx_mem_pool_addr,
|
|
||||||
sizeof(wl->rx_mem_pool_addr), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read all available packets at once */
|
/* Read all available packets at once */
|
||||||
wl1271_read(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf,
|
des = le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]);
|
||||||
|
wlcore_hw_prepare_read(wl, des, buf_size);
|
||||||
|
wlcore_read_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf,
|
||||||
buf_size, true);
|
buf_size, true);
|
||||||
|
|
||||||
/* Split data into separate packets */
|
/* Split data into separate packets */
|
||||||
pkt_offset = 0;
|
pkt_offset = 0;
|
||||||
while (pkt_offset < buf_size) {
|
while (pkt_offset < buf_size) {
|
||||||
pkt_length = wl12xx_rx_get_buf_size(status,
|
des = le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]);
|
||||||
drv_rx_counter);
|
pkt_len = wlcore_rx_get_buf_size(wl, des);
|
||||||
|
rx_align = wlcore_hw_get_rx_buf_align(wl, des);
|
||||||
unaligned = wl12xx_rx_get_unaligned(status,
|
|
||||||
drv_rx_counter);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* the handle data call can only fail in memory-outage
|
* the handle data call can only fail in memory-outage
|
||||||
|
@ -256,7 +251,7 @@ void wl12xx_rx(struct wl1271 *wl, struct wl12xx_fw_status *status)
|
||||||
*/
|
*/
|
||||||
if (wl1271_rx_handle_data(wl,
|
if (wl1271_rx_handle_data(wl,
|
||||||
wl->aggr_buf + pkt_offset,
|
wl->aggr_buf + pkt_offset,
|
||||||
pkt_length, unaligned,
|
pkt_len, rx_align,
|
||||||
&hlid) == 1) {
|
&hlid) == 1) {
|
||||||
if (hlid < WL12XX_MAX_LINKS)
|
if (hlid < WL12XX_MAX_LINKS)
|
||||||
__set_bit(hlid, active_hlids);
|
__set_bit(hlid, active_hlids);
|
||||||
|
@ -269,7 +264,7 @@ void wl12xx_rx(struct wl1271 *wl, struct wl12xx_fw_status *status)
|
||||||
wl->rx_counter++;
|
wl->rx_counter++;
|
||||||
drv_rx_counter++;
|
drv_rx_counter++;
|
||||||
drv_rx_counter &= NUM_RX_PKT_DESC_MOD_MASK;
|
drv_rx_counter &= NUM_RX_PKT_DESC_MOD_MASK;
|
||||||
pkt_offset += pkt_length;
|
pkt_offset += wlcore_rx_get_align_buf_size(wl, pkt_len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,8 +272,9 @@ void wl12xx_rx(struct wl1271 *wl, struct wl12xx_fw_status *status)
|
||||||
* Write the driver's packet counter to the FW. This is only required
|
* Write the driver's packet counter to the FW. This is only required
|
||||||
* for older hardware revisions
|
* for older hardware revisions
|
||||||
*/
|
*/
|
||||||
if (wl->quirks & WL12XX_QUIRK_END_OF_TRANSACTION)
|
if (wl->quirks & WLCORE_QUIRK_END_OF_TRANSACTION)
|
||||||
wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter);
|
wl1271_write32(wl, WL12XX_REG_RX_DRIVER_COUNTER,
|
||||||
|
wl->rx_counter);
|
||||||
|
|
||||||
wl12xx_rearm_rx_streaming(wl, active_hlids);
|
wl12xx_rearm_rx_streaming(wl, active_hlids);
|
||||||
}
|
}
|
|
@ -96,9 +96,19 @@
|
||||||
#define RX_MEM_BLOCK_MASK 0xFF
|
#define RX_MEM_BLOCK_MASK 0xFF
|
||||||
#define RX_BUF_SIZE_MASK 0xFFF00
|
#define RX_BUF_SIZE_MASK 0xFFF00
|
||||||
#define RX_BUF_SIZE_SHIFT_DIV 6
|
#define RX_BUF_SIZE_SHIFT_DIV 6
|
||||||
|
#define ALIGNED_RX_BUF_SIZE_MASK 0xFFFF00
|
||||||
|
#define ALIGNED_RX_BUF_SIZE_SHIFT 8
|
||||||
|
|
||||||
/* If set, the start of IP payload is not 4 bytes aligned */
|
/* If set, the start of IP payload is not 4 bytes aligned */
|
||||||
#define RX_BUF_UNALIGNED_PAYLOAD BIT(20)
|
#define RX_BUF_UNALIGNED_PAYLOAD BIT(20)
|
||||||
|
|
||||||
|
/* Describes the alignment state of a Rx buffer */
|
||||||
|
enum wl_rx_buf_align {
|
||||||
|
WLCORE_RX_BUF_ALIGNED,
|
||||||
|
WLCORE_RX_BUF_UNALIGNED,
|
||||||
|
WLCORE_RX_BUF_PADDED,
|
||||||
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
WL12XX_RX_CLASS_UNKNOWN,
|
WL12XX_RX_CLASS_UNKNOWN,
|
||||||
WL12XX_RX_CLASS_MANAGEMENT,
|
WL12XX_RX_CLASS_MANAGEMENT,
|
||||||
|
@ -126,7 +136,7 @@ struct wl1271_rx_descriptor {
|
||||||
u8 reserved;
|
u8 reserved;
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
void wl12xx_rx(struct wl1271 *wl, struct wl12xx_fw_status *status);
|
void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status *status);
|
||||||
u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band);
|
u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band);
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -23,7 +23,7 @@
|
||||||
|
|
||||||
#include <linux/ieee80211.h>
|
#include <linux/ieee80211.h>
|
||||||
|
|
||||||
#include "wl12xx.h"
|
#include "wlcore.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "cmd.h"
|
#include "cmd.h"
|
||||||
#include "scan.h"
|
#include "scan.h"
|
||||||
|
@ -417,6 +417,23 @@ wl1271_scan_get_sched_scan_channels(struct wl1271 *wl,
|
||||||
int i, j;
|
int i, j;
|
||||||
u32 flags;
|
u32 flags;
|
||||||
bool force_passive = !req->n_ssids;
|
bool force_passive = !req->n_ssids;
|
||||||
|
u32 min_dwell_time_active, max_dwell_time_active, delta_per_probe;
|
||||||
|
u32 dwell_time_passive, dwell_time_dfs;
|
||||||
|
|
||||||
|
if (band == IEEE80211_BAND_5GHZ)
|
||||||
|
delta_per_probe = c->dwell_time_delta_per_probe_5;
|
||||||
|
else
|
||||||
|
delta_per_probe = c->dwell_time_delta_per_probe;
|
||||||
|
|
||||||
|
min_dwell_time_active = c->base_dwell_time +
|
||||||
|
req->n_ssids * c->num_probe_reqs * delta_per_probe;
|
||||||
|
|
||||||
|
max_dwell_time_active = min_dwell_time_active + c->max_dwell_time_delta;
|
||||||
|
|
||||||
|
min_dwell_time_active = DIV_ROUND_UP(min_dwell_time_active, 1000);
|
||||||
|
max_dwell_time_active = DIV_ROUND_UP(max_dwell_time_active, 1000);
|
||||||
|
dwell_time_passive = DIV_ROUND_UP(c->dwell_time_passive, 1000);
|
||||||
|
dwell_time_dfs = DIV_ROUND_UP(c->dwell_time_dfs, 1000);
|
||||||
|
|
||||||
for (i = 0, j = start;
|
for (i = 0, j = start;
|
||||||
i < req->n_channels && j < max_channels;
|
i < req->n_channels && j < max_channels;
|
||||||
|
@ -440,21 +457,24 @@ wl1271_scan_get_sched_scan_channels(struct wl1271 *wl,
|
||||||
req->channels[i]->flags);
|
req->channels[i]->flags);
|
||||||
wl1271_debug(DEBUG_SCAN, "max_power %d",
|
wl1271_debug(DEBUG_SCAN, "max_power %d",
|
||||||
req->channels[i]->max_power);
|
req->channels[i]->max_power);
|
||||||
|
wl1271_debug(DEBUG_SCAN, "min_dwell_time %d max dwell time %d",
|
||||||
|
min_dwell_time_active,
|
||||||
|
max_dwell_time_active);
|
||||||
|
|
||||||
if (flags & IEEE80211_CHAN_RADAR) {
|
if (flags & IEEE80211_CHAN_RADAR) {
|
||||||
channels[j].flags |= SCAN_CHANNEL_FLAGS_DFS;
|
channels[j].flags |= SCAN_CHANNEL_FLAGS_DFS;
|
||||||
|
|
||||||
channels[j].passive_duration =
|
channels[j].passive_duration =
|
||||||
cpu_to_le16(c->dwell_time_dfs);
|
cpu_to_le16(dwell_time_dfs);
|
||||||
} else {
|
} else {
|
||||||
channels[j].passive_duration =
|
channels[j].passive_duration =
|
||||||
cpu_to_le16(c->dwell_time_passive);
|
cpu_to_le16(dwell_time_passive);
|
||||||
}
|
}
|
||||||
|
|
||||||
channels[j].min_duration =
|
channels[j].min_duration =
|
||||||
cpu_to_le16(c->min_dwell_time_active);
|
cpu_to_le16(min_dwell_time_active);
|
||||||
channels[j].max_duration =
|
channels[j].max_duration =
|
||||||
cpu_to_le16(c->max_dwell_time_active);
|
cpu_to_le16(max_dwell_time_active);
|
||||||
|
|
||||||
channels[j].tx_power_att = req->channels[i]->max_power;
|
channels[j].tx_power_att = req->channels[i]->max_power;
|
||||||
channels[j].channel = req->channels[i]->hw_value;
|
channels[j].channel = req->channels[i]->hw_value;
|
|
@ -24,7 +24,7 @@
|
||||||
#ifndef __SCAN_H__
|
#ifndef __SCAN_H__
|
||||||
#define __SCAN_H__
|
#define __SCAN_H__
|
||||||
|
|
||||||
#include "wl12xx.h"
|
#include "wlcore.h"
|
||||||
|
|
||||||
int wl1271_scan(struct wl1271 *wl, struct ieee80211_vif *vif,
|
int wl1271_scan(struct wl1271 *wl, struct ieee80211_vif *vif,
|
||||||
const u8 *ssid, size_t ssid_len,
|
const u8 *ssid, size_t ssid_len,
|
||||||
|
@ -55,7 +55,7 @@ void wl1271_scan_sched_scan_results(struct wl1271 *wl);
|
||||||
#define WL1271_SCAN_BAND_2_4_GHZ 0
|
#define WL1271_SCAN_BAND_2_4_GHZ 0
|
||||||
#define WL1271_SCAN_BAND_5_GHZ 1
|
#define WL1271_SCAN_BAND_5_GHZ 1
|
||||||
|
|
||||||
#define WL1271_SCAN_TIMEOUT 10000 /* msec */
|
#define WL1271_SCAN_TIMEOUT 30000 /* msec */
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
WL1271_SCAN_STATE_IDLE,
|
WL1271_SCAN_STATE_IDLE,
|
|
@ -33,7 +33,7 @@
|
||||||
#include <linux/wl12xx.h>
|
#include <linux/wl12xx.h>
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
|
|
||||||
#include "wl12xx.h"
|
#include "wlcore.h"
|
||||||
#include "wl12xx_80211.h"
|
#include "wl12xx_80211.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ static void wl12xx_sdio_raw_read(struct device *child, int addr, void *buf,
|
||||||
|
|
||||||
sdio_claim_host(func);
|
sdio_claim_host(func);
|
||||||
|
|
||||||
if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) {
|
if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG)) {
|
||||||
((u8 *)buf)[0] = sdio_f0_readb(func, addr, &ret);
|
((u8 *)buf)[0] = sdio_f0_readb(func, addr, &ret);
|
||||||
dev_dbg(child->parent, "sdio read 52 addr 0x%x, byte 0x%02x\n",
|
dev_dbg(child->parent, "sdio read 52 addr 0x%x, byte 0x%02x\n",
|
||||||
addr, ((u8 *)buf)[0]);
|
addr, ((u8 *)buf)[0]);
|
||||||
|
@ -105,7 +105,7 @@ static void wl12xx_sdio_raw_write(struct device *child, int addr, void *buf,
|
||||||
|
|
||||||
sdio_claim_host(func);
|
sdio_claim_host(func);
|
||||||
|
|
||||||
if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) {
|
if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG)) {
|
||||||
sdio_f0_writeb(func, ((u8 *)buf)[0], addr, &ret);
|
sdio_f0_writeb(func, ((u8 *)buf)[0], addr, &ret);
|
||||||
dev_dbg(child->parent, "sdio write 52 addr 0x%x, byte 0x%02x\n",
|
dev_dbg(child->parent, "sdio write 52 addr 0x%x, byte 0x%02x\n",
|
||||||
addr, ((u8 *)buf)[0]);
|
addr, ((u8 *)buf)[0]);
|
|
@ -30,12 +30,10 @@
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
|
||||||
#include "wl12xx.h"
|
#include "wlcore.h"
|
||||||
#include "wl12xx_80211.h"
|
#include "wl12xx_80211.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
|
|
||||||
#include "reg.h"
|
|
||||||
|
|
||||||
#define WSPI_CMD_READ 0x40000000
|
#define WSPI_CMD_READ 0x40000000
|
||||||
#define WSPI_CMD_WRITE 0x00000000
|
#define WSPI_CMD_WRITE 0x00000000
|
||||||
#define WSPI_CMD_FIXED 0x20000000
|
#define WSPI_CMD_FIXED 0x20000000
|
|
@ -25,10 +25,9 @@
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <net/genetlink.h>
|
#include <net/genetlink.h>
|
||||||
|
|
||||||
#include "wl12xx.h"
|
#include "wlcore.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "acx.h"
|
#include "acx.h"
|
||||||
#include "reg.h"
|
|
||||||
#include "ps.h"
|
#include "ps.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
|
|
|
@ -25,13 +25,19 @@
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/etherdevice.h>
|
#include <linux/etherdevice.h>
|
||||||
|
|
||||||
#include "wl12xx.h"
|
#include "wlcore.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "reg.h"
|
|
||||||
#include "ps.h"
|
#include "ps.h"
|
||||||
#include "tx.h"
|
#include "tx.h"
|
||||||
#include "event.h"
|
#include "event.h"
|
||||||
|
#include "hw_ops.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: this is here just for now, it must be removed when the data
|
||||||
|
* operations are in place.
|
||||||
|
*/
|
||||||
|
#include "../wl12xx/reg.h"
|
||||||
|
|
||||||
static int wl1271_set_default_wep_key(struct wl1271 *wl,
|
static int wl1271_set_default_wep_key(struct wl1271 *wl,
|
||||||
struct wl12xx_vif *wlvif, u8 id)
|
struct wl12xx_vif *wlvif, u8 id)
|
||||||
|
@ -56,8 +62,8 @@ static int wl1271_alloc_tx_id(struct wl1271 *wl, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
int id;
|
int id;
|
||||||
|
|
||||||
id = find_first_zero_bit(wl->tx_frames_map, ACX_TX_DESCRIPTORS);
|
id = find_first_zero_bit(wl->tx_frames_map, wl->num_tx_desc);
|
||||||
if (id >= ACX_TX_DESCRIPTORS)
|
if (id >= wl->num_tx_desc)
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
__set_bit(id, wl->tx_frames_map);
|
__set_bit(id, wl->tx_frames_map);
|
||||||
|
@ -69,7 +75,7 @@ static int wl1271_alloc_tx_id(struct wl1271 *wl, struct sk_buff *skb)
|
||||||
static void wl1271_free_tx_id(struct wl1271 *wl, int id)
|
static void wl1271_free_tx_id(struct wl1271 *wl, int id)
|
||||||
{
|
{
|
||||||
if (__test_and_clear_bit(id, wl->tx_frames_map)) {
|
if (__test_and_clear_bit(id, wl->tx_frames_map)) {
|
||||||
if (unlikely(wl->tx_frames_cnt == ACX_TX_DESCRIPTORS))
|
if (unlikely(wl->tx_frames_cnt == wl->num_tx_desc))
|
||||||
clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
|
clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
|
||||||
|
|
||||||
wl->tx_frames[id] = NULL;
|
wl->tx_frames[id] = NULL;
|
||||||
|
@ -167,14 +173,15 @@ u8 wl12xx_tx_get_hlid(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||||
return wlvif->dev_hlid;
|
return wlvif->dev_hlid;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int wl12xx_calc_packet_alignment(struct wl1271 *wl,
|
unsigned int wlcore_calc_packet_alignment(struct wl1271 *wl,
|
||||||
unsigned int packet_length)
|
unsigned int packet_length)
|
||||||
{
|
{
|
||||||
if (wl->quirks & WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT)
|
if (wl->quirks & WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN)
|
||||||
return ALIGN(packet_length, WL1271_TX_ALIGN_TO);
|
|
||||||
else
|
|
||||||
return ALIGN(packet_length, WL12XX_BUS_BLOCK_SIZE);
|
return ALIGN(packet_length, WL12XX_BUS_BLOCK_SIZE);
|
||||||
|
else
|
||||||
|
return ALIGN(packet_length, WL1271_TX_ALIGN_TO);
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL(wlcore_calc_packet_alignment);
|
||||||
|
|
||||||
static int wl1271_tx_allocate(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
static int wl1271_tx_allocate(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||||
struct sk_buff *skb, u32 extra, u32 buf_offset,
|
struct sk_buff *skb, u32 extra, u32 buf_offset,
|
||||||
|
@ -182,10 +189,9 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||||
{
|
{
|
||||||
struct wl1271_tx_hw_descr *desc;
|
struct wl1271_tx_hw_descr *desc;
|
||||||
u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra;
|
u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra;
|
||||||
u32 len;
|
|
||||||
u32 total_blocks;
|
u32 total_blocks;
|
||||||
int id, ret = -EBUSY, ac;
|
int id, ret = -EBUSY, ac;
|
||||||
u32 spare_blocks = wl->tx_spare_blocks;
|
u32 spare_blocks = wl->normal_tx_spare;
|
||||||
bool is_dummy = false;
|
bool is_dummy = false;
|
||||||
|
|
||||||
if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE)
|
if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE)
|
||||||
|
@ -196,30 +202,19 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||||
if (id < 0)
|
if (id < 0)
|
||||||
return id;
|
return id;
|
||||||
|
|
||||||
/* approximate the number of blocks required for this packet
|
if (unlikely(wl12xx_is_dummy_packet(wl, skb)))
|
||||||
in the firmware */
|
|
||||||
len = wl12xx_calc_packet_alignment(wl, total_len);
|
|
||||||
|
|
||||||
/* in case of a dummy packet, use default amount of spare mem blocks */
|
|
||||||
if (unlikely(wl12xx_is_dummy_packet(wl, skb))) {
|
|
||||||
is_dummy = true;
|
is_dummy = true;
|
||||||
spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
|
else if (wlvif->is_gem)
|
||||||
}
|
spare_blocks = wl->gem_tx_spare;
|
||||||
|
|
||||||
total_blocks = (len + TX_HW_BLOCK_SIZE - 1) / TX_HW_BLOCK_SIZE +
|
total_blocks = wlcore_hw_calc_tx_blocks(wl, total_len, spare_blocks);
|
||||||
spare_blocks;
|
|
||||||
|
|
||||||
if (total_blocks <= wl->tx_blocks_available) {
|
if (total_blocks <= wl->tx_blocks_available) {
|
||||||
desc = (struct wl1271_tx_hw_descr *)skb_push(
|
desc = (struct wl1271_tx_hw_descr *)skb_push(
|
||||||
skb, total_len - skb->len);
|
skb, total_len - skb->len);
|
||||||
|
|
||||||
/* HW descriptor fields change between wl127x and wl128x */
|
wlcore_hw_set_tx_desc_blocks(wl, desc, total_blocks,
|
||||||
if (wl->chip.id == CHIP_ID_1283_PG20) {
|
spare_blocks);
|
||||||
desc->wl128x_mem.total_mem_blocks = total_blocks;
|
|
||||||
} else {
|
|
||||||
desc->wl127x_mem.extra_blocks = spare_blocks;
|
|
||||||
desc->wl127x_mem.total_mem_blocks = total_blocks;
|
|
||||||
}
|
|
||||||
|
|
||||||
desc->id = id;
|
desc->id = id;
|
||||||
|
|
||||||
|
@ -256,7 +251,7 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||||
{
|
{
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
struct wl1271_tx_hw_descr *desc;
|
struct wl1271_tx_hw_descr *desc;
|
||||||
int aligned_len, ac, rate_idx;
|
int ac, rate_idx;
|
||||||
s64 hosttime;
|
s64 hosttime;
|
||||||
u16 tx_attr = 0;
|
u16 tx_attr = 0;
|
||||||
__le16 frame_control;
|
__le16 frame_control;
|
||||||
|
@ -329,44 +324,16 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||||
}
|
}
|
||||||
|
|
||||||
tx_attr |= rate_idx << TX_HW_ATTR_OFST_RATE_POLICY;
|
tx_attr |= rate_idx << TX_HW_ATTR_OFST_RATE_POLICY;
|
||||||
desc->reserved = 0;
|
|
||||||
|
|
||||||
aligned_len = wl12xx_calc_packet_alignment(wl, skb->len);
|
|
||||||
|
|
||||||
if (wl->chip.id == CHIP_ID_1283_PG20) {
|
|
||||||
desc->wl128x_mem.extra_bytes = aligned_len - skb->len;
|
|
||||||
desc->length = cpu_to_le16(aligned_len >> 2);
|
|
||||||
|
|
||||||
wl1271_debug(DEBUG_TX, "tx_fill_hdr: hlid: %d "
|
|
||||||
"tx_attr: 0x%x len: %d life: %d mem: %d",
|
|
||||||
desc->hlid, tx_attr,
|
|
||||||
le16_to_cpu(desc->length),
|
|
||||||
le16_to_cpu(desc->life_time),
|
|
||||||
desc->wl128x_mem.total_mem_blocks);
|
|
||||||
} else {
|
|
||||||
int pad;
|
|
||||||
|
|
||||||
/* Store the aligned length in terms of words */
|
|
||||||
desc->length = cpu_to_le16(aligned_len >> 2);
|
|
||||||
|
|
||||||
/* calculate number of padding bytes */
|
|
||||||
pad = aligned_len - skb->len;
|
|
||||||
tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD;
|
|
||||||
|
|
||||||
wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d hlid: %d "
|
|
||||||
"tx_attr: 0x%x len: %d life: %d mem: %d", pad,
|
|
||||||
desc->hlid, tx_attr,
|
|
||||||
le16_to_cpu(desc->length),
|
|
||||||
le16_to_cpu(desc->life_time),
|
|
||||||
desc->wl127x_mem.total_mem_blocks);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* for WEP shared auth - no fw encryption is needed */
|
/* for WEP shared auth - no fw encryption is needed */
|
||||||
if (ieee80211_is_auth(frame_control) &&
|
if (ieee80211_is_auth(frame_control) &&
|
||||||
ieee80211_has_protected(frame_control))
|
ieee80211_has_protected(frame_control))
|
||||||
tx_attr |= TX_HW_ATTR_HOST_ENCRYPT;
|
tx_attr |= TX_HW_ATTR_HOST_ENCRYPT;
|
||||||
|
|
||||||
|
desc->reserved = 0;
|
||||||
desc->tx_attr = cpu_to_le16(tx_attr);
|
desc->tx_attr = cpu_to_le16(tx_attr);
|
||||||
|
|
||||||
|
wlcore_hw_set_tx_desc_data_len(wl, desc, skb);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* caller must hold wl->mutex */
|
/* caller must hold wl->mutex */
|
||||||
|
@ -432,7 +399,7 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||||
* In special cases, we want to align to a specific block size
|
* In special cases, we want to align to a specific block size
|
||||||
* (eg. for wl128x with SDIO we align to 256).
|
* (eg. for wl128x with SDIO we align to 256).
|
||||||
*/
|
*/
|
||||||
total_len = wl12xx_calc_packet_alignment(wl, skb->len);
|
total_len = wlcore_calc_packet_alignment(wl, skb->len);
|
||||||
|
|
||||||
memcpy(wl->aggr_buf + buf_offset, skb->data, skb->len);
|
memcpy(wl->aggr_buf + buf_offset, skb->data, skb->len);
|
||||||
memset(wl->aggr_buf + buf_offset + skb->len, 0, total_len - skb->len);
|
memset(wl->aggr_buf + buf_offset + skb->len, 0, total_len - skb->len);
|
||||||
|
@ -718,7 +685,7 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
|
||||||
* Flush buffer and try again.
|
* Flush buffer and try again.
|
||||||
*/
|
*/
|
||||||
wl1271_skb_queue_head(wl, wlvif, skb);
|
wl1271_skb_queue_head(wl, wlvif, skb);
|
||||||
wl1271_write(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf,
|
wlcore_write_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf,
|
||||||
buf_offset, true);
|
buf_offset, true);
|
||||||
sent_packets = true;
|
sent_packets = true;
|
||||||
buf_offset = 0;
|
buf_offset = 0;
|
||||||
|
@ -753,7 +720,7 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
|
||||||
|
|
||||||
out_ack:
|
out_ack:
|
||||||
if (buf_offset) {
|
if (buf_offset) {
|
||||||
wl1271_write(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf,
|
wlcore_write_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf,
|
||||||
buf_offset, true);
|
buf_offset, true);
|
||||||
sent_packets = true;
|
sent_packets = true;
|
||||||
}
|
}
|
||||||
|
@ -762,8 +729,8 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
|
||||||
* Interrupt the firmware with the new packets. This is only
|
* Interrupt the firmware with the new packets. This is only
|
||||||
* required for older hardware revisions
|
* required for older hardware revisions
|
||||||
*/
|
*/
|
||||||
if (wl->quirks & WL12XX_QUIRK_END_OF_TRANSACTION)
|
if (wl->quirks & WLCORE_QUIRK_END_OF_TRANSACTION)
|
||||||
wl1271_write32(wl, WL1271_HOST_WR_ACCESS,
|
wl1271_write32(wl, WL12XX_HOST_WR_ACCESS,
|
||||||
wl->tx_packets_count);
|
wl->tx_packets_count);
|
||||||
|
|
||||||
wl1271_handle_tx_low_watermark(wl);
|
wl1271_handle_tx_low_watermark(wl);
|
||||||
|
@ -792,11 +759,20 @@ static u8 wl1271_tx_get_rate_flags(u8 rate_class_index)
|
||||||
{
|
{
|
||||||
u8 flags = 0;
|
u8 flags = 0;
|
||||||
|
|
||||||
if (rate_class_index >= CONF_HW_RXTX_RATE_MCS_MIN &&
|
/*
|
||||||
rate_class_index <= CONF_HW_RXTX_RATE_MCS_MAX)
|
* TODO: use wl12xx constants when this code is moved to wl12xx, as
|
||||||
|
* only it uses Tx-completion.
|
||||||
|
*/
|
||||||
|
if (rate_class_index <= 8)
|
||||||
flags |= IEEE80211_TX_RC_MCS;
|
flags |= IEEE80211_TX_RC_MCS;
|
||||||
if (rate_class_index == CONF_HW_RXTX_RATE_MCS7_SGI)
|
|
||||||
|
/*
|
||||||
|
* TODO: use wl12xx constants when this code is moved to wl12xx, as
|
||||||
|
* only it uses Tx-completion.
|
||||||
|
*/
|
||||||
|
if (rate_class_index == 0)
|
||||||
flags |= IEEE80211_TX_RC_SHORT_GI;
|
flags |= IEEE80211_TX_RC_SHORT_GI;
|
||||||
|
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -813,7 +789,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
|
||||||
u8 retries = 0;
|
u8 retries = 0;
|
||||||
|
|
||||||
/* check for id legality */
|
/* check for id legality */
|
||||||
if (unlikely(id >= ACX_TX_DESCRIPTORS || wl->tx_frames[id] == NULL)) {
|
if (unlikely(id >= wl->num_tx_desc || wl->tx_frames[id] == NULL)) {
|
||||||
wl1271_warning("TX result illegal id: %d", id);
|
wl1271_warning("TX result illegal id: %d", id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -834,7 +810,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
|
||||||
if (result->status == TX_SUCCESS) {
|
if (result->status == TX_SUCCESS) {
|
||||||
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
|
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
|
||||||
info->flags |= IEEE80211_TX_STAT_ACK;
|
info->flags |= IEEE80211_TX_STAT_ACK;
|
||||||
rate = wl1271_rate_to_idx(result->rate_class_index,
|
rate = wlcore_rate_to_idx(wl, result->rate_class_index,
|
||||||
wlvif->band);
|
wlvif->band);
|
||||||
rate_flags = wl1271_tx_get_rate_flags(result->rate_class_index);
|
rate_flags = wl1271_tx_get_rate_flags(result->rate_class_index);
|
||||||
retries = result->ack_failures;
|
retries = result->ack_failures;
|
||||||
|
@ -929,6 +905,7 @@ void wl1271_tx_complete(struct wl1271 *wl)
|
||||||
wl->tx_results_count++;
|
wl->tx_results_count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL(wl1271_tx_complete);
|
||||||
|
|
||||||
void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid)
|
void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid)
|
||||||
{
|
{
|
||||||
|
@ -1006,7 +983,7 @@ void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
|
||||||
if (reset_tx_queues)
|
if (reset_tx_queues)
|
||||||
wl1271_handle_tx_low_watermark(wl);
|
wl1271_handle_tx_low_watermark(wl);
|
||||||
|
|
||||||
for (i = 0; i < ACX_TX_DESCRIPTORS; i++) {
|
for (i = 0; i < wl->num_tx_desc; i++) {
|
||||||
if (wl->tx_frames[i] == NULL)
|
if (wl->tx_frames[i] == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -25,9 +25,6 @@
|
||||||
#ifndef __TX_H__
|
#ifndef __TX_H__
|
||||||
#define __TX_H__
|
#define __TX_H__
|
||||||
|
|
||||||
#define TX_HW_BLOCK_SPARE_DEFAULT 1
|
|
||||||
#define TX_HW_BLOCK_SIZE 252
|
|
||||||
|
|
||||||
#define TX_HW_MGMT_PKT_LIFETIME_TU 2000
|
#define TX_HW_MGMT_PKT_LIFETIME_TU 2000
|
||||||
#define TX_HW_AP_MODE_PKT_LIFETIME_TU 8000
|
#define TX_HW_AP_MODE_PKT_LIFETIME_TU 8000
|
||||||
|
|
||||||
|
@ -212,7 +209,7 @@ void wl1271_tx_complete(struct wl1271 *wl);
|
||||||
void wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif);
|
void wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif);
|
||||||
void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues);
|
void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues);
|
||||||
void wl1271_tx_flush(struct wl1271 *wl);
|
void wl1271_tx_flush(struct wl1271 *wl);
|
||||||
u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band);
|
u8 wlcore_rate_to_idx(struct wl1271 *wl, u8 rate, enum ieee80211_band band);
|
||||||
u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set,
|
u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set,
|
||||||
enum ieee80211_band rate_band);
|
enum ieee80211_band rate_band);
|
||||||
u32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set);
|
u32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set);
|
||||||
|
@ -224,6 +221,8 @@ void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid);
|
||||||
void wl1271_handle_tx_low_watermark(struct wl1271 *wl);
|
void wl1271_handle_tx_low_watermark(struct wl1271 *wl);
|
||||||
bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb);
|
bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb);
|
||||||
void wl12xx_rearm_rx_streaming(struct wl1271 *wl, unsigned long *active_hlids);
|
void wl12xx_rearm_rx_streaming(struct wl1271 *wl, unsigned long *active_hlids);
|
||||||
|
unsigned int wlcore_calc_packet_alignment(struct wl1271 *wl,
|
||||||
|
unsigned int packet_length);
|
||||||
|
|
||||||
/* from main.c */
|
/* from main.c */
|
||||||
void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid);
|
void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid);
|
|
@ -89,8 +89,6 @@
|
||||||
#define WL1271_AP_BSS_INDEX 0
|
#define WL1271_AP_BSS_INDEX 0
|
||||||
#define WL1271_AP_DEF_BEACON_EXP 20
|
#define WL1271_AP_DEF_BEACON_EXP 20
|
||||||
|
|
||||||
#define ACX_TX_DESCRIPTORS 16
|
|
||||||
|
|
||||||
#define WL1271_AGGR_BUFFER_SIZE (4 * PAGE_SIZE)
|
#define WL1271_AGGR_BUFFER_SIZE (4 * PAGE_SIZE)
|
||||||
|
|
||||||
enum wl1271_state {
|
enum wl1271_state {
|
||||||
|
@ -105,26 +103,6 @@ enum wl12xx_fw_type {
|
||||||
WL12XX_FW_TYPE_PLT,
|
WL12XX_FW_TYPE_PLT,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum wl1271_partition_type {
|
|
||||||
PART_DOWN,
|
|
||||||
PART_WORK,
|
|
||||||
PART_DRPW,
|
|
||||||
|
|
||||||
PART_TABLE_LEN
|
|
||||||
};
|
|
||||||
|
|
||||||
struct wl1271_partition {
|
|
||||||
u32 size;
|
|
||||||
u32 start;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct wl1271_partition_set {
|
|
||||||
struct wl1271_partition mem;
|
|
||||||
struct wl1271_partition reg;
|
|
||||||
struct wl1271_partition mem2;
|
|
||||||
struct wl1271_partition mem3;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct wl1271;
|
struct wl1271;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
@ -167,8 +145,21 @@ struct wl1271_stats {
|
||||||
|
|
||||||
#define AP_MAX_STATIONS 8
|
#define AP_MAX_STATIONS 8
|
||||||
|
|
||||||
|
struct wl_fw_packet_counters {
|
||||||
|
/* Cumulative counter of released packets per AC */
|
||||||
|
u8 tx_released_pkts[NUM_TX_QUEUES];
|
||||||
|
|
||||||
|
/* Cumulative counter of freed packets per HLID */
|
||||||
|
u8 tx_lnk_free_pkts[WL12XX_MAX_LINKS];
|
||||||
|
|
||||||
|
/* Cumulative counter of released Voice memory blocks */
|
||||||
|
u8 tx_voice_released_blks;
|
||||||
|
|
||||||
|
u8 padding[3];
|
||||||
|
} __packed;
|
||||||
|
|
||||||
/* FW status registers */
|
/* FW status registers */
|
||||||
struct wl12xx_fw_status {
|
struct wl_fw_status {
|
||||||
__le32 intr;
|
__le32 intr;
|
||||||
u8 fw_rx_counter;
|
u8 fw_rx_counter;
|
||||||
u8 drv_rx_counter;
|
u8 drv_rx_counter;
|
||||||
|
@ -195,16 +186,12 @@ struct wl12xx_fw_status {
|
||||||
/* Size (in Memory Blocks) of TX pool */
|
/* Size (in Memory Blocks) of TX pool */
|
||||||
__le32 tx_total;
|
__le32 tx_total;
|
||||||
|
|
||||||
/* Cumulative counter of released packets per AC */
|
struct wl_fw_packet_counters counters;
|
||||||
u8 tx_released_pkts[NUM_TX_QUEUES];
|
|
||||||
|
|
||||||
/* Cumulative counter of freed packets per HLID */
|
|
||||||
u8 tx_lnk_free_pkts[WL12XX_MAX_LINKS];
|
|
||||||
|
|
||||||
/* Cumulative counter of released Voice memory blocks */
|
|
||||||
u8 tx_voice_released_blks;
|
|
||||||
u8 padding_1[3];
|
|
||||||
__le32 log_start_addr;
|
__le32 log_start_addr;
|
||||||
|
|
||||||
|
/* Private status to be used by the lower drivers */
|
||||||
|
u8 priv[0];
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
struct wl1271_rx_mem_pool_addr {
|
struct wl1271_rx_mem_pool_addr {
|
||||||
|
@ -292,214 +279,6 @@ struct wl1271_link {
|
||||||
u8 ba_bitmap;
|
u8 ba_bitmap;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct wl1271 {
|
|
||||||
struct ieee80211_hw *hw;
|
|
||||||
bool mac80211_registered;
|
|
||||||
|
|
||||||
struct device *dev;
|
|
||||||
|
|
||||||
void *if_priv;
|
|
||||||
|
|
||||||
struct wl1271_if_operations *if_ops;
|
|
||||||
|
|
||||||
void (*set_power)(bool enable);
|
|
||||||
int irq;
|
|
||||||
int ref_clock;
|
|
||||||
|
|
||||||
spinlock_t wl_lock;
|
|
||||||
|
|
||||||
enum wl1271_state state;
|
|
||||||
enum wl12xx_fw_type fw_type;
|
|
||||||
bool plt;
|
|
||||||
u8 last_vif_count;
|
|
||||||
struct mutex mutex;
|
|
||||||
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
struct wl1271_partition_set part;
|
|
||||||
|
|
||||||
struct wl1271_chip chip;
|
|
||||||
|
|
||||||
int cmd_box_addr;
|
|
||||||
int event_box_addr;
|
|
||||||
|
|
||||||
u8 *fw;
|
|
||||||
size_t fw_len;
|
|
||||||
void *nvs;
|
|
||||||
size_t nvs_len;
|
|
||||||
|
|
||||||
s8 hw_pg_ver;
|
|
||||||
|
|
||||||
/* address read from the fuse ROM */
|
|
||||||
u32 fuse_oui_addr;
|
|
||||||
u32 fuse_nic_addr;
|
|
||||||
|
|
||||||
/* we have up to 2 MAC addresses */
|
|
||||||
struct mac_address addresses[2];
|
|
||||||
int channel;
|
|
||||||
u8 system_hlid;
|
|
||||||
|
|
||||||
unsigned long links_map[BITS_TO_LONGS(WL12XX_MAX_LINKS)];
|
|
||||||
unsigned long roles_map[BITS_TO_LONGS(WL12XX_MAX_ROLES)];
|
|
||||||
unsigned long roc_map[BITS_TO_LONGS(WL12XX_MAX_ROLES)];
|
|
||||||
unsigned long rate_policies_map[
|
|
||||||
BITS_TO_LONGS(WL12XX_MAX_RATE_POLICIES)];
|
|
||||||
|
|
||||||
struct list_head wlvif_list;
|
|
||||||
|
|
||||||
u8 sta_count;
|
|
||||||
u8 ap_count;
|
|
||||||
|
|
||||||
struct wl1271_acx_mem_map *target_mem_map;
|
|
||||||
|
|
||||||
/* Accounting for allocated / available TX blocks on HW */
|
|
||||||
u32 tx_blocks_freed;
|
|
||||||
u32 tx_blocks_available;
|
|
||||||
u32 tx_allocated_blocks;
|
|
||||||
u32 tx_results_count;
|
|
||||||
|
|
||||||
/* amount of spare TX blocks to use */
|
|
||||||
u32 tx_spare_blocks;
|
|
||||||
|
|
||||||
/* Accounting for allocated / available Tx packets in HW */
|
|
||||||
u32 tx_pkts_freed[NUM_TX_QUEUES];
|
|
||||||
u32 tx_allocated_pkts[NUM_TX_QUEUES];
|
|
||||||
|
|
||||||
/* Transmitted TX packets counter for chipset interface */
|
|
||||||
u32 tx_packets_count;
|
|
||||||
|
|
||||||
/* Time-offset between host and chipset clocks */
|
|
||||||
s64 time_offset;
|
|
||||||
|
|
||||||
/* Frames scheduled for transmission, not handled yet */
|
|
||||||
int tx_queue_count[NUM_TX_QUEUES];
|
|
||||||
long stopped_queues_map;
|
|
||||||
|
|
||||||
/* Frames received, not handled yet by mac80211 */
|
|
||||||
struct sk_buff_head deferred_rx_queue;
|
|
||||||
|
|
||||||
/* Frames sent, not returned yet to mac80211 */
|
|
||||||
struct sk_buff_head deferred_tx_queue;
|
|
||||||
|
|
||||||
struct work_struct tx_work;
|
|
||||||
struct workqueue_struct *freezable_wq;
|
|
||||||
|
|
||||||
/* Pending TX frames */
|
|
||||||
unsigned long tx_frames_map[BITS_TO_LONGS(ACX_TX_DESCRIPTORS)];
|
|
||||||
struct sk_buff *tx_frames[ACX_TX_DESCRIPTORS];
|
|
||||||
int tx_frames_cnt;
|
|
||||||
|
|
||||||
/* FW Rx counter */
|
|
||||||
u32 rx_counter;
|
|
||||||
|
|
||||||
/* Rx memory pool address */
|
|
||||||
struct wl1271_rx_mem_pool_addr rx_mem_pool_addr;
|
|
||||||
|
|
||||||
/* Intermediate buffer, used for packet aggregation */
|
|
||||||
u8 *aggr_buf;
|
|
||||||
|
|
||||||
/* Reusable dummy packet template */
|
|
||||||
struct sk_buff *dummy_packet;
|
|
||||||
|
|
||||||
/* Network stack work */
|
|
||||||
struct work_struct netstack_work;
|
|
||||||
|
|
||||||
/* FW log buffer */
|
|
||||||
u8 *fwlog;
|
|
||||||
|
|
||||||
/* Number of valid bytes in the FW log buffer */
|
|
||||||
ssize_t fwlog_size;
|
|
||||||
|
|
||||||
/* Sysfs FW log entry readers wait queue */
|
|
||||||
wait_queue_head_t fwlog_waitq;
|
|
||||||
|
|
||||||
/* Hardware recovery work */
|
|
||||||
struct work_struct recovery_work;
|
|
||||||
|
|
||||||
/* The mbox event mask */
|
|
||||||
u32 event_mask;
|
|
||||||
|
|
||||||
/* Mailbox pointers */
|
|
||||||
u32 mbox_ptr[2];
|
|
||||||
|
|
||||||
/* Are we currently scanning */
|
|
||||||
struct ieee80211_vif *scan_vif;
|
|
||||||
struct wl1271_scan scan;
|
|
||||||
struct delayed_work scan_complete_work;
|
|
||||||
|
|
||||||
bool sched_scanning;
|
|
||||||
|
|
||||||
/* The current band */
|
|
||||||
enum ieee80211_band band;
|
|
||||||
|
|
||||||
struct completion *elp_compl;
|
|
||||||
struct delayed_work elp_work;
|
|
||||||
|
|
||||||
/* in dBm */
|
|
||||||
int power_level;
|
|
||||||
|
|
||||||
struct wl1271_stats stats;
|
|
||||||
|
|
||||||
__le32 buffer_32;
|
|
||||||
u32 buffer_cmd;
|
|
||||||
u32 buffer_busyword[WL1271_BUSY_WORD_CNT];
|
|
||||||
|
|
||||||
struct wl12xx_fw_status *fw_status;
|
|
||||||
struct wl1271_tx_hw_res_if *tx_res_if;
|
|
||||||
|
|
||||||
/* Current chipset configuration */
|
|
||||||
struct conf_drv_settings conf;
|
|
||||||
|
|
||||||
bool sg_enabled;
|
|
||||||
|
|
||||||
bool enable_11a;
|
|
||||||
|
|
||||||
/* Most recently reported noise in dBm */
|
|
||||||
s8 noise;
|
|
||||||
|
|
||||||
/* bands supported by this instance of wl12xx */
|
|
||||||
struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS];
|
|
||||||
|
|
||||||
int tcxo_clock;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* wowlan trigger was configured during suspend.
|
|
||||||
* (currently, only "ANY" trigger is supported)
|
|
||||||
*/
|
|
||||||
bool wow_enabled;
|
|
||||||
bool irq_wake_enabled;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* AP-mode - links indexed by HLID. The global and broadcast links
|
|
||||||
* are always active.
|
|
||||||
*/
|
|
||||||
struct wl1271_link links[WL12XX_MAX_LINKS];
|
|
||||||
|
|
||||||
/* AP-mode - a bitmap of links currently in PS mode according to FW */
|
|
||||||
u32 ap_fw_ps_map;
|
|
||||||
|
|
||||||
/* AP-mode - a bitmap of links currently in PS mode in mac80211 */
|
|
||||||
unsigned long ap_ps_map;
|
|
||||||
|
|
||||||
/* Quirks of specific hardware revisions */
|
|
||||||
unsigned int quirks;
|
|
||||||
|
|
||||||
/* Platform limitations */
|
|
||||||
unsigned int platform_quirks;
|
|
||||||
|
|
||||||
/* number of currently active RX BA sessions */
|
|
||||||
int ba_rx_session_count;
|
|
||||||
|
|
||||||
/* AP-mode - number of currently connected stations */
|
|
||||||
int active_sta_count;
|
|
||||||
|
|
||||||
/* last wlvif we transmitted from */
|
|
||||||
struct wl12xx_vif *last_wlvif;
|
|
||||||
|
|
||||||
/* work to fire when Tx is stuck */
|
|
||||||
struct delayed_work tx_watchdog_work;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct wl1271_station {
|
struct wl1271_station {
|
||||||
u8 hlid;
|
u8 hlid;
|
||||||
};
|
};
|
||||||
|
@ -605,6 +384,9 @@ struct wl12xx_vif {
|
||||||
struct work_struct rx_streaming_disable_work;
|
struct work_struct rx_streaming_disable_work;
|
||||||
struct timer_list rx_streaming_timer;
|
struct timer_list rx_streaming_timer;
|
||||||
|
|
||||||
|
/* does the current role use GEM for encryption (AP or STA) */
|
||||||
|
bool is_gem;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This struct must be last!
|
* This struct must be last!
|
||||||
* data that has to be saved acrossed reconfigs (e.g. recovery)
|
* data that has to be saved acrossed reconfigs (e.g. recovery)
|
||||||
|
@ -679,17 +461,6 @@ size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen);
|
||||||
#define HW_BG_RATES_MASK 0xffff
|
#define HW_BG_RATES_MASK 0xffff
|
||||||
#define HW_HT_RATES_OFFSET 16
|
#define HW_HT_RATES_OFFSET 16
|
||||||
|
|
||||||
/* Quirks */
|
|
||||||
|
|
||||||
/* Each RX/TX transaction requires an end-of-transaction transfer */
|
|
||||||
#define WL12XX_QUIRK_END_OF_TRANSACTION BIT(0)
|
|
||||||
|
|
||||||
/* wl127x and SPI don't support SDIO block size alignment */
|
|
||||||
#define WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT BIT(2)
|
|
||||||
|
|
||||||
/* Older firmwares did not implement the FW logger over bus feature */
|
|
||||||
#define WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED BIT(4)
|
|
||||||
|
|
||||||
#define WL12XX_HW_BLOCK_SIZE 256
|
#define WL12XX_HW_BLOCK_SIZE 256
|
||||||
|
|
||||||
#endif
|
#endif
|
448
drivers/net/wireless/ti/wlcore/wlcore.h
Normal file
448
drivers/net/wireless/ti/wlcore/wlcore.h
Normal file
|
@ -0,0 +1,448 @@
|
||||||
|
/*
|
||||||
|
* 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__ */
|
|
@ -1,48 +0,0 @@
|
||||||
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
|
|
|
@ -1,15 +0,0 @@
|
||||||
wl12xx-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
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
# small builtin driver bit
|
|
||||||
obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx_platform_data.o
|
|
||||||
|
|
||||||
ccflags-y += -D__CHECK_ENDIAN__
|
|
|
@ -1,786 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of wl1271
|
|
||||||
*
|
|
||||||
* Copyright (C) 2008-2010 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
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/slab.h>
|
|
||||||
#include <linux/wl12xx.h>
|
|
||||||
#include <linux/export.h>
|
|
||||||
|
|
||||||
#include "debug.h"
|
|
||||||
#include "acx.h"
|
|
||||||
#include "reg.h"
|
|
||||||
#include "boot.h"
|
|
||||||
#include "io.h"
|
|
||||||
#include "event.h"
|
|
||||||
#include "rx.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);
|
|
||||||
|
|
||||||
/* 10.5.1 run the firmware (II) */
|
|
||||||
cpu_ctrl |= flag;
|
|
||||||
wl1271_write32(wl, ACX_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)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = sscanf(wl->chip.fw_ver_str + 4, "%u.%u.%u.%u.%u",
|
|
||||||
&wl->chip.fw_ver[0], &wl->chip.fw_ver[1],
|
|
||||||
&wl->chip.fw_ver[2], &wl->chip.fw_ver[3],
|
|
||||||
&wl->chip.fw_ver[4]);
|
|
||||||
|
|
||||||
if (ret != 5) {
|
|
||||||
wl1271_warning("fw version incorrect value");
|
|
||||||
memset(wl->chip.fw_ver, 0, sizeof(wl->chip.fw_ver));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check if any quirks are needed with older fw versions */
|
|
||||||
wl->quirks |= wl12xx_get_fw_ver_quirks(wl);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void wl1271_boot_fw_version(struct wl1271 *wl)
|
|
||||||
{
|
|
||||||
struct wl1271_static_data static_data;
|
|
||||||
|
|
||||||
wl1271_read(wl, wl->cmd_box_addr, &static_data, sizeof(static_data),
|
|
||||||
false);
|
|
||||||
|
|
||||||
strncpy(wl->chip.fw_ver_str, static_data.fw_version,
|
|
||||||
sizeof(wl->chip.fw_ver_str));
|
|
||||||
|
|
||||||
/* 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
|
|
||||||
size_t fw_data_len, u32 dest)
|
|
||||||
{
|
|
||||||
struct wl1271_partition_set partition;
|
|
||||||
int addr, chunk_num, partition_limit;
|
|
||||||
u8 *p, *chunk;
|
|
||||||
|
|
||||||
/* whal_FwCtrl_LoadFwImageSm() */
|
|
||||||
|
|
||||||
wl1271_debug(DEBUG_BOOT, "starting firmware upload");
|
|
||||||
|
|
||||||
wl1271_debug(DEBUG_BOOT, "fw_data_len %zd chunk_size %d",
|
|
||||||
fw_data_len, CHUNK_SIZE);
|
|
||||||
|
|
||||||
if ((fw_data_len % 4) != 0) {
|
|
||||||
wl1271_error("firmware length not multiple of four");
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
chunk = kmalloc(CHUNK_SIZE, GFP_KERNEL);
|
|
||||||
if (!chunk) {
|
|
||||||
wl1271_error("allocation for firmware upload chunk failed");
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(&partition, &wl12xx_part_table[PART_DOWN], sizeof(partition));
|
|
||||||
partition.mem.start = dest;
|
|
||||||
wl1271_set_partition(wl, &partition);
|
|
||||||
|
|
||||||
/* 10.1 set partition limit and chunk num */
|
|
||||||
chunk_num = 0;
|
|
||||||
partition_limit = wl12xx_part_table[PART_DOWN].mem.size;
|
|
||||||
|
|
||||||
while (chunk_num < fw_data_len / CHUNK_SIZE) {
|
|
||||||
/* 10.2 update partition, if needed */
|
|
||||||
addr = dest + (chunk_num + 2) * CHUNK_SIZE;
|
|
||||||
if (addr > partition_limit) {
|
|
||||||
addr = dest + chunk_num * CHUNK_SIZE;
|
|
||||||
partition_limit = chunk_num * CHUNK_SIZE +
|
|
||||||
wl12xx_part_table[PART_DOWN].mem.size;
|
|
||||||
partition.mem.start = addr;
|
|
||||||
wl1271_set_partition(wl, &partition);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 10.3 upload the chunk */
|
|
||||||
addr = dest + chunk_num * CHUNK_SIZE;
|
|
||||||
p = buf + chunk_num * CHUNK_SIZE;
|
|
||||||
memcpy(chunk, p, CHUNK_SIZE);
|
|
||||||
wl1271_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x",
|
|
||||||
p, addr);
|
|
||||||
wl1271_write(wl, addr, chunk, CHUNK_SIZE, false);
|
|
||||||
|
|
||||||
chunk_num++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 10.4 upload the last chunk */
|
|
||||||
addr = dest + chunk_num * CHUNK_SIZE;
|
|
||||||
p = buf + chunk_num * CHUNK_SIZE;
|
|
||||||
memcpy(chunk, p, fw_data_len % CHUNK_SIZE);
|
|
||||||
wl1271_debug(DEBUG_BOOT, "uploading fw last chunk (%zd B) 0x%p to 0x%x",
|
|
||||||
fw_data_len % CHUNK_SIZE, p, addr);
|
|
||||||
wl1271_write(wl, addr, chunk, fw_data_len % CHUNK_SIZE, false);
|
|
||||||
|
|
||||||
kfree(chunk);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int wl1271_boot_upload_firmware(struct wl1271 *wl)
|
|
||||||
{
|
|
||||||
u32 chunks, addr, len;
|
|
||||||
int ret = 0;
|
|
||||||
u8 *fw;
|
|
||||||
|
|
||||||
fw = wl->fw;
|
|
||||||
chunks = be32_to_cpup((__be32 *) fw);
|
|
||||||
fw += sizeof(u32);
|
|
||||||
|
|
||||||
wl1271_debug(DEBUG_BOOT, "firmware chunks to be uploaded: %u", chunks);
|
|
||||||
|
|
||||||
while (chunks--) {
|
|
||||||
addr = be32_to_cpup((__be32 *) fw);
|
|
||||||
fw += sizeof(u32);
|
|
||||||
len = be32_to_cpup((__be32 *) fw);
|
|
||||||
fw += sizeof(u32);
|
|
||||||
|
|
||||||
if (len > 300000) {
|
|
||||||
wl1271_info("firmware chunk too long: %u", len);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
wl1271_debug(DEBUG_BOOT, "chunk %d addr 0x%x len %u",
|
|
||||||
chunks, addr, len);
|
|
||||||
ret = wl1271_boot_upload_firmware_chunk(wl, fw, len, addr);
|
|
||||||
if (ret != 0)
|
|
||||||
break;
|
|
||||||
fw += len;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int wl1271_boot_upload_nvs(struct wl1271 *wl)
|
|
||||||
{
|
|
||||||
size_t nvs_len, burst_len;
|
|
||||||
int i;
|
|
||||||
u32 dest_addr, val;
|
|
||||||
u8 *nvs_ptr, *nvs_aligned;
|
|
||||||
|
|
||||||
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 {
|
|
||||||
struct wl1271_nvs_file *nvs =
|
|
||||||
(struct wl1271_nvs_file *)wl->nvs;
|
|
||||||
/*
|
|
||||||
* FIXME: the LEGACY NVS image support (NVS's missing the 5GHz
|
|
||||||
* band configurations) can be removed when those NVS files stop
|
|
||||||
* floating around.
|
|
||||||
*/
|
|
||||||
if (wl->nvs_len == sizeof(struct wl1271_nvs_file) ||
|
|
||||||
wl->nvs_len == WL1271_INI_LEGACY_NVS_FILE_SIZE) {
|
|
||||||
if (nvs->general_params.dual_mode_select)
|
|
||||||
wl->enable_11a = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wl->nvs_len != sizeof(struct wl1271_nvs_file) &&
|
|
||||||
(wl->nvs_len != WL1271_INI_LEGACY_NVS_FILE_SIZE ||
|
|
||||||
wl->enable_11a)) {
|
|
||||||
wl1271_error("nvs size is not as expected: %zu != %zu",
|
|
||||||
wl->nvs_len, sizeof(struct wl1271_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 */
|
|
||||||
nvs_ptr[11] = wl->addresses[0].addr[0];
|
|
||||||
nvs_ptr[10] = wl->addresses[0].addr[1];
|
|
||||||
nvs_ptr[6] = wl->addresses[0].addr[2];
|
|
||||||
nvs_ptr[5] = wl->addresses[0].addr[3];
|
|
||||||
nvs_ptr[4] = wl->addresses[0].addr[4];
|
|
||||||
nvs_ptr[3] = wl->addresses[0].addr[5];
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Layout before the actual NVS tables:
|
|
||||||
* 1 byte : burst length.
|
|
||||||
* 2 bytes: destination address.
|
|
||||||
* n bytes: data to burst copy.
|
|
||||||
*
|
|
||||||
* This is ended by a 0 length, then the NVS tables.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* FIXME: Do we need to check here whether the LSB is 1? */
|
|
||||||
while (nvs_ptr[0]) {
|
|
||||||
burst_len = nvs_ptr[0];
|
|
||||||
dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Due to our new wl1271_translate_reg_addr function,
|
|
||||||
* we need to add the REGISTER_BASE to the destination
|
|
||||||
*/
|
|
||||||
dest_addr += REGISTERS_BASE;
|
|
||||||
|
|
||||||
/* We move our pointer to the data */
|
|
||||||
nvs_ptr += 3;
|
|
||||||
|
|
||||||
for (i = 0; i < burst_len; i++) {
|
|
||||||
if (nvs_ptr + 3 >= (u8 *) wl->nvs + nvs_len)
|
|
||||||
goto out_badnvs;
|
|
||||||
|
|
||||||
val = (nvs_ptr[0] | (nvs_ptr[1] << 8)
|
|
||||||
| (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24));
|
|
||||||
|
|
||||||
wl1271_debug(DEBUG_BOOT,
|
|
||||||
"nvs burst write 0x%x: 0x%x",
|
|
||||||
dest_addr, val);
|
|
||||||
wl1271_write32(wl, dest_addr, val);
|
|
||||||
|
|
||||||
nvs_ptr += 4;
|
|
||||||
dest_addr += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nvs_ptr >= (u8 *) wl->nvs + nvs_len)
|
|
||||||
goto out_badnvs;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We've reached the first zero length, the first NVS table
|
|
||||||
* is located at an aligned offset which is at least 7 bytes further.
|
|
||||||
* NOTE: The wl->nvs->nvs element must be first, in order to
|
|
||||||
* simplify the casting, we assume it is at the beginning of
|
|
||||||
* the wl->nvs structure.
|
|
||||||
*/
|
|
||||||
nvs_ptr = (u8 *)wl->nvs +
|
|
||||||
ALIGN(nvs_ptr - (u8 *)wl->nvs + 7, 4);
|
|
||||||
|
|
||||||
if (nvs_ptr >= (u8 *) wl->nvs + nvs_len)
|
|
||||||
goto out_badnvs;
|
|
||||||
|
|
||||||
nvs_len -= nvs_ptr - (u8 *)wl->nvs;
|
|
||||||
|
|
||||||
/* Now we must set the partition correctly */
|
|
||||||
wl1271_set_partition(wl, &wl12xx_part_table[PART_WORK]);
|
|
||||||
|
|
||||||
/* Copy the NVS tables to a new block to ensure alignment */
|
|
||||||
nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL);
|
|
||||||
if (!nvs_aligned)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
/* And finally we upload the NVS tables */
|
|
||||||
wl1271_write(wl, CMD_MBOX_ADDRESS, nvs_aligned, nvs_len, false);
|
|
||||||
|
|
||||||
kfree(nvs_aligned);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
out_badnvs:
|
|
||||||
wl1271_error("nvs data is malformed");
|
|
||||||
return -EILSEQ;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 loop, ret;
|
|
||||||
u32 chip_id, intr;
|
|
||||||
|
|
||||||
wl1271_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT);
|
|
||||||
|
|
||||||
chip_id = wl1271_read32(wl, CHIP_ID_B);
|
|
||||||
|
|
||||||
wl1271_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id);
|
|
||||||
|
|
||||||
if (chip_id != wl->chip.id) {
|
|
||||||
wl1271_error("chip id doesn't match after firmware boot");
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* wait for init to complete */
|
|
||||||
loop = 0;
|
|
||||||
while (loop++ < INIT_LOOP) {
|
|
||||||
udelay(INIT_LOOP_DELAY);
|
|
||||||
intr = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
|
|
||||||
|
|
||||||
if (intr == 0xffffffff) {
|
|
||||||
wl1271_error("error reading hardware complete "
|
|
||||||
"init indication");
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
/* 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);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (loop > INIT_LOOP) {
|
|
||||||
wl1271_error("timeout waiting for the hardware to "
|
|
||||||
"complete initialization");
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* get hardware config command mail box */
|
|
||||||
wl->cmd_box_addr = wl1271_read32(wl, REG_COMMAND_MAILBOX_PTR);
|
|
||||||
|
|
||||||
/* get hardware config event mail box */
|
|
||||||
wl->event_box_addr = wl1271_read32(wl, REG_EVENT_MAILBOX_PTR);
|
|
||||||
|
|
||||||
/* set the working partition to its "running" mode offset */
|
|
||||||
wl1271_set_partition(wl, &wl12xx_part_table[PART_WORK]);
|
|
||||||
|
|
||||||
wl1271_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x",
|
|
||||||
wl->cmd_box_addr, wl->event_box_addr);
|
|
||||||
|
|
||||||
wl1271_boot_fw_version(wl);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* in case of full asynchronous mode the firmware event must be
|
|
||||||
* ready to receive event from the command mailbox
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* unmask required mbox events */
|
|
||||||
wl->event_mask = BSS_LOSE_EVENT_ID |
|
|
||||||
SCAN_COMPLETE_EVENT_ID |
|
|
||||||
ROLE_STOP_COMPLETE_EVENT_ID |
|
|
||||||
RSSI_SNR_TRIGGER_0_EVENT_ID |
|
|
||||||
PSPOLL_DELIVERY_FAILURE_EVENT_ID |
|
|
||||||
SOFT_GEMINI_SENSE_EVENT_ID |
|
|
||||||
PERIODIC_SCAN_REPORT_EVENT_ID |
|
|
||||||
PERIODIC_SCAN_COMPLETE_EVENT_ID |
|
|
||||||
DUMMY_PACKET_EVENT_ID |
|
|
||||||
PEER_REMOVE_COMPLETE_EVENT_ID |
|
|
||||||
BA_SESSION_RX_CONSTRAINT_EVENT_ID |
|
|
||||||
REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID |
|
|
||||||
INACTIVE_STA_EVENT_ID |
|
|
||||||
MAX_TX_RETRY_EVENT_ID |
|
|
||||||
CHANNEL_SWITCH_COMPLETE_EVENT_ID;
|
|
||||||
|
|
||||||
ret = wl1271_event_unmask(wl);
|
|
||||||
if (ret < 0) {
|
|
||||||
wl1271_error("EVENT mask setting failed");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
wl1271_event_mbox_config(wl);
|
|
||||||
|
|
||||||
/* 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;
|
|
||||||
}
|
|
|
@ -1,120 +0,0 @@
|
||||||
/*
|
|
||||||
* 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
|
|
Loading…
Reference in a new issue