summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy Green <andy.green@linaro.org>2014-12-20 21:06:46 +0800
committerAndy Green <andy.green@linaro.org>2015-01-06 21:47:34 +0800
commit675a2ae1edfadf01f62a781b4d34d845a5d6f4a8 (patch)
tree9dd6dd83fd121603984859db105445ac1e0d85ea
parent87949a0b30bd42c9be5d55dabb213350e1e868ee (diff)
Signed-off-by: Andy Green <andy.green@linaro.org>
-rw-r--r--arch/arm/boot/dts/msm8916.dtsi61
-rw-r--r--arch/arm/configs/msm8916-qrd_defconfig6
-rw-r--r--arch/arm/mach-qcom/board.c1
-rw-r--r--arch/arm/mach-qcom/scm.c1
-rw-r--r--drivers/net/wireless/ath/wcn36xx/Makefile2
-rw-r--r--drivers/net/wireless/ath/wcn36xx/dxe.c2
-rw-r--r--drivers/net/wireless/ath/wcn36xx/dxe.h7
-rw-r--r--drivers/net/wireless/ath/wcn36xx/hal.h2
-rw-r--r--drivers/net/wireless/ath/wcn36xx/main.c9
-rw-r--r--drivers/net/wireless/ath/wcn36xx/smd.c19
-rw-r--r--drivers/net/wireless/ath/wcn36xx/wcn36xx-msm.c429
-rw-r--r--drivers/net/wireless/ath/wcn36xx/wcn36xx.h1
-rw-r--r--drivers/net/wireless/wcnss/wcnss_wlan.c4
-rw-r--r--drivers/soc/qcom/peripheral-loader.c5
14 files changed, 529 insertions, 20 deletions
diff --git a/arch/arm/boot/dts/msm8916.dtsi b/arch/arm/boot/dts/msm8916.dtsi
index f9751860ed73..02207bb07e6a 100644
--- a/arch/arm/boot/dts/msm8916.dtsi
+++ b/arch/arm/boot/dts/msm8916.dtsi
@@ -748,8 +748,66 @@
};
+ qcom,wcn36xx@0a000000 {
+ compatible = "qcom,wcn36xx";
+ reg = <0x0a000000 0x280000>,
+ <0xb011008 0x04>,
+ <0x0a21b000 0x3000>,
+ <0x03204000 0x00000100>,
+ <0x03200800 0x00000200>,
+ <0x0A100400 0x00000200>,
+ <0x0A205050 0x00000200>,
+ <0x0A219000 0x00000020>,
+ <0x0A080488 0x00000008>,
+ <0x0A080fb0 0x00000008>,
+ <0x0A08040c 0x00000008>,
+ <0x0A0120a8 0x00000008>,
+ <0x0A012448 0x00000008>,
+ <0x0A080c00 0x00000001>;
+
+ reg-names = "wcnss_mmio", "wcnss_fiq",
+ "pronto_phy_base", "riva_phy_base",
+ "riva_ccu_base", "pronto_a2xb_base",
+ "pronto_ccpu_base", "pronto_saw2_base",
+ "wlan_tx_phy_aborts","wlan_brdg_err_source",
+ "wlan_tx_status", "alarms_txctl",
+ "alarms_tactl", "pronto_mcu_base";
+
+ interrupts = <0 145 0 0 146 0>;
+ interrupt-names = "wcnss_wlantx_irq", "wcnss_wlanrx_irq";
+
+ qcom,pronto-vddmx-supply = <&pm8916_l3>;
+ qcom,pronto-vddcx-supply = <&pm8916_s1_corner>;
+ qcom,pronto-vddpx-supply = <&pm8916_l7>;
+ qcom,iris-vddxo-supply = <&pm8916_l7>;
+ qcom,iris-vddrfa-supply = <&pm8916_s3>;
+ qcom,iris-vddpa-supply = <&pm8916_l9>;
+ qcom,iris-vdddig-supply = <&pm8916_l5>;
+
+ pinctrl-names = "wcnss_default", "wcnss_sleep",
+ "wcnss_gpio_default";
+ pinctrl-0 = <&wcnss_default>;
+ pinctrl-1 = <&wcnss_sleep>;
+ pinctrl-2 = <&wcnss_gpio_default>;
+
+ gpios = <&msm_gpio 40 0>, <&msm_gpio 41 0>, <&msm_gpio 42 0>,
+ <&msm_gpio 43 0>, <&msm_gpio 44 0>;
+
+ clocks = <&clock_rpm clk_xo_wlan_clk>,
+ <&clock_rpm clk_rf_clk2>,
+ <&clock_debug clk_gcc_debug_mux>,
+ <&clock_gcc clk_wcnss_m_clk>;
+ clock-names = "xo", "rf_clk", "measure", "wcnss_debug";
+
+ qcom,has-autodetect-xo;
+ qcom,wlan-rx-buff-count = <512>;
+ qcom,is-pronto-vt;
+ qcom,has-pronto-hw;
+ qcom,wcnss-adc_tm = <&pm8916_adc_tm>;
+ };
+
qcom,wcnss-wlan@0a000000 {
- compatible = "qcom,wcnss_wlan";
+ compatible = "qcom,wcnss_wlan";
reg = <0x0a000000 0x280000>,
<0xb011008 0x04>,
<0x0a21b000 0x3000>,
@@ -806,6 +864,7 @@
qcom,wcnss-adc_tm = <&pm8916_adc_tm>;
};
+
qcom,pronto@a21b000 {
compatible = "qcom,pil-tz-generic";
reg = <0x0a21b000 0x3000>;
diff --git a/arch/arm/configs/msm8916-qrd_defconfig b/arch/arm/configs/msm8916-qrd_defconfig
index 2d3702ce6ac5..e595f9608705 100644
--- a/arch/arm/configs/msm8916-qrd_defconfig
+++ b/arch/arm/configs/msm8916-qrd_defconfig
@@ -69,6 +69,9 @@ CONFIG_INET_ESP=y
# CONFIG_INET_LRO is not set
CONFIG_IPV6=y
CONFIG_CFG80211=y
+CONFIG_NL80211_TESTMODE=y
+CONFIG_CFG80211_INTERNAL_REGDB=y
+CONFIG_CFG80211_WEXT=y
CONFIG_MAC80211=y
# CONFIG_MAC80211_RC_MINSTREL is not set
CONFIG_RFKILL=y
@@ -95,8 +98,11 @@ CONFIG_DUMMY=y
# CONFIG_USB_NET_DRIVERS is not set
CONFIG_WCNSS_CORE=y
CONFIG_WCNSS_CORE_PRONTO=y
+CONFIG_WCNSS_MEM_PRE_ALLOC=y
CONFIG_ATH_CARDS=y
CONFIG_ATH_DEBUG=y
+CONFIG_WCN36XX=m
+CONFIG_WCN36XX_DEBUGFS=y
# CONFIG_RTL_CARDS is not set
CONFIG_SERIAL_MSM=y
CONFIG_SERIAL_MSM_CONSOLE=y
diff --git a/arch/arm/mach-qcom/board.c b/arch/arm/mach-qcom/board.c
index 5a5b9eb48f90..235666188eb1 100644
--- a/arch/arm/mach-qcom/board.c
+++ b/arch/arm/mach-qcom/board.c
@@ -79,7 +79,6 @@ static void __init msm8916_init(void)
msm_spm_device_init();
qpnp_regulator_init();
msm_pm_sleep_status_init();
-
}
#ifdef CONFIG_ARCH_MSM8916
static struct map_desc msm8916_io_desc[] __initdata = {
diff --git a/arch/arm/mach-qcom/scm.c b/arch/arm/mach-qcom/scm.c
index eae84a9b1ed5..5ae63f912306 100644
--- a/arch/arm/mach-qcom/scm.c
+++ b/arch/arm/mach-qcom/scm.c
@@ -180,6 +180,7 @@ static inline void *scm_get_response_buffer(const struct scm_response *rsp)
static int scm_remap_error(int err)
{
+ pr_err("%s: smc world returned his own code %d\n", __func__, err);
switch (err) {
case SCM_ERROR:
return -EIO;
diff --git a/drivers/net/wireless/ath/wcn36xx/Makefile b/drivers/net/wireless/ath/wcn36xx/Makefile
index 50c43b4382ba..e889f2c30199 100644
--- a/drivers/net/wireless/ath/wcn36xx/Makefile
+++ b/drivers/net/wireless/ath/wcn36xx/Makefile
@@ -1,4 +1,4 @@
-obj-$(CONFIG_WCN36XX) := wcn36xx.o
+obj-$(CONFIG_WCN36XX) := wcn36xx.o wcn36xx-msm.o
wcn36xx-y += main.o \
dxe.o \
txrx.o \
diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c
index 73f12f196f14..334f26531ec5 100644
--- a/drivers/net/wireless/ath/wcn36xx/dxe.c
+++ b/drivers/net/wireless/ath/wcn36xx/dxe.c
@@ -46,7 +46,7 @@ static void wcn36xx_dxe_write_register(struct wcn36xx *wcn, int addr, int data)
#define wcn36xx_dxe_write_register_x(wcn, reg, reg_data) \
do { \
- if (wcn->chip_version == WCN36XX_CHIP_3680) \
+ if (wcn->chip_version != WCN36XX_CHIP_3660) \
wcn36xx_dxe_write_register(wcn, reg ## _3680, reg_data); \
else \
wcn36xx_dxe_write_register(wcn, reg ## _3660, reg_data); \
diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.h b/drivers/net/wireless/ath/wcn36xx/dxe.h
index 35ee7e966bd2..6173b6f00d6e 100644
--- a/drivers/net/wireless/ath/wcn36xx/dxe.h
+++ b/drivers/net/wireless/ath/wcn36xx/dxe.h
@@ -34,6 +34,13 @@ H2H_TEST_RX_TX = DMA2
#define WCN36XX_DXE_REG_CCU_INT_3660 0x200b10
#define WCN36XX_DXE_REG_CCU_INT_3680 0x2050dc
+
+#define WLANDXE_CCU_DXE_INT_SELECT 0x2050dc
+#define WLANDXE_CCU_DXE_INT_SELECT_STAT 0x2050e0
+#define WLANDXE_CCU_ASIC_INT_ENABLE 0x2050e4
+#define WLANDXE_CCU_SOFT_RESET 0x204010
+
+
/* TODO This must calculated properly but not hardcoded */
#define WCN36XX_DXE_CTRL_TX_L 0x328a44
#define WCN36XX_DXE_CTRL_TX_H 0x32ce44
diff --git a/drivers/net/wireless/ath/wcn36xx/hal.h b/drivers/net/wireless/ath/wcn36xx/hal.h
index a1f1127d7808..b947de0fb2e5 100644
--- a/drivers/net/wireless/ath/wcn36xx/hal.h
+++ b/drivers/net/wireless/ath/wcn36xx/hal.h
@@ -345,6 +345,8 @@ enum wcn36xx_hal_host_msg_type {
WCN36XX_HAL_DHCP_START_IND = 189,
WCN36XX_HAL_DHCP_STOP_IND = 190,
+ WCN36XX_HAL_AVOID_FREQ_RANGE_IND = 233,
+
WCN36XX_HAL_MSG_MAX = WCN36XX_HAL_MSG_TYPE_MAX_ENUM_SIZE
};
diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c
index 7dd8873f757e..cbda7b68156e 100644
--- a/drivers/net/wireless/ath/wcn36xx/main.c
+++ b/drivers/net/wireless/ath/wcn36xx/main.c
@@ -21,7 +21,7 @@
#include <linux/platform_device.h>
#include "wcn36xx.h"
-unsigned int wcn36xx_dbg_mask;
+unsigned int wcn36xx_dbg_mask; // = 0xffff;
module_param_named(debug_mask, wcn36xx_dbg_mask, uint, 0644);
MODULE_PARM_DESC(debug_mask, "Debugging mask");
@@ -223,6 +223,7 @@ static void wcn36xx_feat_caps_info(struct wcn36xx *wcn)
static void wcn36xx_detect_chip_version(struct wcn36xx *wcn)
{
+/*
if (get_feat_caps(wcn->fw_feat_caps, DOT11AC)) {
wcn36xx_info("Chip is 3680\n");
wcn->chip_version = WCN36XX_CHIP_3680;
@@ -230,6 +231,8 @@ static void wcn36xx_detect_chip_version(struct wcn36xx *wcn)
wcn36xx_info("Chip is 3660\n");
wcn->chip_version = WCN36XX_CHIP_3660;
}
+*/
+ wcn->chip_version = WCN36XX_CHIP_3620;
}
static int wcn36xx_start(struct ieee80211_hw *hw)
@@ -265,13 +268,13 @@ static int wcn36xx_start(struct ieee80211_hw *hw)
ret = -ENOMEM;
goto out_free_dxe_ctl;
}
-
+//#if 0
ret = wcn36xx_smd_load_nv(wcn);
if (ret) {
wcn36xx_err("Failed to push NV to chip\n");
goto out_free_smd_buf;
}
-
+//#endif
ret = wcn36xx_smd_start(wcn);
if (ret) {
wcn36xx_err("Failed to start chip\n");
diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c
index 63986931829e..7178870b43ab 100644
--- a/drivers/net/wireless/ath/wcn36xx/smd.c
+++ b/drivers/net/wireless/ath/wcn36xx/smd.c
@@ -257,6 +257,8 @@ int wcn36xx_smd_load_nv(struct wcn36xx *wcn)
int ret;
u16 fm_offset = 0;
+ pr_err("%s: load fw %s\n", __func__, WLAN_NV_FILE);
+
if (!wcn->nv) {
ret = request_firmware(&wcn->nv, WLAN_NV_FILE, wcn->dev);
if (ret) {
@@ -321,13 +323,17 @@ static int wcn36xx_smd_start_rsp(struct wcn36xx *wcn, void *buf, size_t len)
{
struct wcn36xx_hal_mac_start_rsp_msg *rsp;
- if (len < sizeof(*rsp))
+ if (len < sizeof(*rsp)) {
+ wcn36xx_err("%s: smd returned len %d not %d\n", __func__, len, sizeof(*rsp));
return -EIO;
+ }
rsp = (struct wcn36xx_hal_mac_start_rsp_msg *)buf;
- if (WCN36XX_FW_MSG_RESULT_SUCCESS != rsp->start_rsp_params.status)
+ if (WCN36XX_FW_MSG_RESULT_SUCCESS != rsp->start_rsp_params.status) {
+ wcn36xx_err("%s: smd result %d\n", __func__, rsp->start_rsp_params.status);
return -EIO;
+ }
memcpy(wcn->crm_version, rsp->start_rsp_params.crm_version,
WCN36XX_HAL_VERSION_LENGTH);
@@ -1886,7 +1892,7 @@ int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index)
}
ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
if (ret) {
- wcn36xx_err("hal_trigger_ba response failed err=%d\n", ret);
+ wcn36xx_info("hal_trigger_ba response failed err=%x\n", ret);
goto out;
}
out:
@@ -2061,6 +2067,7 @@ static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len)
complete(&wcn->hal_rsp_compl);
break;
+ case WCN36XX_HAL_AVOID_FREQ_RANGE_IND:
case WCN36XX_HAL_OTA_TX_COMPL_IND:
case WCN36XX_HAL_MISSED_BEACON_IND:
case WCN36XX_HAL_DELETE_STA_CONTEXT_IND:
@@ -2087,7 +2094,7 @@ nomem:
wcn36xx_dbg(WCN36XX_DBG_HAL, "indication arrived\n");
break;
default:
- wcn36xx_err("SMD_EVENT (%d) not supported\n",
+ wcn36xx_err("%s: SMD_EVENT (%d) not supported\n", __func__,
msg_header->msg_type);
}
}
@@ -2107,6 +2114,8 @@ static void wcn36xx_ind_smd_work(struct work_struct *work)
msg_header = (struct wcn36xx_hal_msg_header *)hal_ind_msg->msg;
switch (msg_header->msg_type) {
+ case WCN36XX_HAL_AVOID_FREQ_RANGE_IND:
+ break;
case WCN36XX_HAL_OTA_TX_COMPL_IND:
wcn36xx_smd_tx_compl_ind(wcn,
hal_ind_msg->msg,
@@ -2123,7 +2132,7 @@ static void wcn36xx_ind_smd_work(struct work_struct *work)
hal_ind_msg->msg_len);
break;
default:
- wcn36xx_err("SMD_EVENT (%d) not supported\n",
+ wcn36xx_err("%s: SMD_EVENT (%d) not supported\n", __func__,
msg_header->msg_type);
}
list_del(wcn->hal_ind_queue.next);
diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx-msm.c b/drivers/net/wireless/ath/wcn36xx/wcn36xx-msm.c
new file mode 100644
index 000000000000..774dc8837111
--- /dev/null
+++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx-msm.c
@@ -0,0 +1,429 @@
+/*
+ * * Copyright (c) 2013 Eugene Krasnikov <k.eugene.e@gmail.com>
+ * * Copyright (c) 2013 Qualcomm Atheros, Inc.
+ * *
+ * * Permission to use, copy, modify, and/or distribute this software for any
+ * * purpose with or without fee is hereby granted, provided that the above
+ * * copyright notice and this permission notice appear in all copies.
+ * *
+ * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * */
+
+#include <linux/completion.h>
+#include <linux/firmware.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/rpm-smd-regulator.h>
+#include <soc/qcom/smd.h>
+#include <soc/qcom/smsm.h>
+#include "wcn36xx.h"
+
+#include <soc/qcom/subsystem_restart.h>
+#include <soc/qcom/subsystem_notif.h>
+
+#define MAC_ADDR_0 "wlan/macaddr0"
+#define WCNSS_PIL_DEVICE "wcnss"
+
+struct wcn36xx_msm {
+ struct wcn36xx_platform_ctrl_ops ctrl_ops;
+ struct platform_device *core;
+ void *drv_priv;
+ void (*rsp_cb)(void *drv_priv, void *buf, size_t len);
+ /* SMD related */
+ struct workqueue_struct *wq;
+ struct work_struct smd_work;
+ struct completion smd_compl;
+ smd_channel_t *smd_ch;
+} wmsm;
+
+struct vregs_info {
+ const char * const name;
+ int state;
+ const int nominal_min;
+ const int low_power_min;
+ const int max_voltage;
+ const int uA_load;
+ struct regulator *regulator;
+};
+
+#define VREG_NULL_CONFIG 0x0000
+#define VREG_GET_REGULATOR_MASK 0x0001
+#define VREG_SET_VOLTAGE_MASK 0x0002
+#define VREG_OPTIMUM_MODE_MASK 0x0004
+#define VREG_ENABLE_MASK 0x0008
+
+/* WCNSS regulators for Pronto v2 hardware */
+static struct vregs_info pronto_vregs_pronto_v2[] = {
+ {"qcom,pronto-vddmx", VREG_NULL_CONFIG, 1287500, 0,
+ 1287500, 0, NULL},
+ {"qcom,pronto-vddcx", VREG_NULL_CONFIG, RPM_REGULATOR_CORNER_NORMAL,
+ RPM_REGULATOR_CORNER_NONE, RPM_REGULATOR_CORNER_SUPER_TURBO,
+ 0, NULL},
+ {"qcom,pronto-vddpx", VREG_NULL_CONFIG, 1800000, 0,
+ 1800000, 0, NULL},
+};
+
+/* IRIS regulators for Pronto v2 hardware */
+static struct vregs_info iris_vregs_pronto_v2[] = {
+ {"qcom,iris-vddxo", VREG_NULL_CONFIG, 1800000, 0,
+ 1800000, 10000, NULL},
+ {"qcom,iris-vddrfa", VREG_NULL_CONFIG, 1300000, 0,
+ 1300000, 100000, NULL},
+ {"qcom,iris-vddpa", VREG_NULL_CONFIG, 3300000, 0,
+ 3300000, 515000, NULL},
+ {"qcom,iris-vdddig", VREG_NULL_CONFIG, 1800000, 0,
+ 1800000, 10000, NULL},
+};
+
+
+/* Common helper routine to turn on all WCNSS & IRIS vregs */
+static int wcnss_vregs_on(struct device *dev,
+ struct vregs_info regulators[], uint size)
+{
+ int i, rc = 0, reg_cnt;
+
+ for (i = 0; i < size; i++) {
+ /* Get regulator source */
+ regulators[i].regulator =
+ regulator_get(dev, regulators[i].name);
+ if (IS_ERR(regulators[i].regulator)) {
+ rc = PTR_ERR(regulators[i].regulator);
+ pr_err("regulator get of %s failed (%d)\n",
+ regulators[i].name, rc);
+ goto fail;
+ }
+ regulators[i].state |= VREG_GET_REGULATOR_MASK;
+ reg_cnt = regulator_count_voltages(regulators[i].regulator);
+ /* Set voltage to nominal. Exclude swtiches e.g. LVS */
+ if ((regulators[i].nominal_min || regulators[i].max_voltage)
+ && (reg_cnt > 0)) {
+ rc = regulator_set_voltage(regulators[i].regulator,
+ regulators[i].nominal_min,
+ regulators[i].max_voltage);
+ if (rc) {
+ pr_err("regulator_set_voltage(%s) failed (%d)\n",
+ regulators[i].name, rc);
+ goto fail;
+ }
+ regulators[i].state |= VREG_SET_VOLTAGE_MASK;
+ }
+
+ /* Vote for PWM/PFM mode if needed */
+ if (regulators[i].uA_load && (reg_cnt > 0)) {
+ rc = regulator_set_optimum_mode(regulators[i].regulator,
+ regulators[i].uA_load);
+ if (rc < 0) {
+ pr_err("regulator_set_optimum_mode(%s) failed (%d)\n",
+ regulators[i].name, rc);
+ goto fail;
+ }
+ regulators[i].state |= VREG_OPTIMUM_MODE_MASK;
+ }
+
+ /* Enable the regulator */
+ rc = regulator_enable(regulators[i].regulator);
+ if (rc) {
+ pr_err("vreg %s enable failed (%d)\n",
+ regulators[i].name, rc);
+ goto fail;
+ }
+ regulators[i].state |= VREG_ENABLE_MASK;
+ }
+
+ return rc;
+
+fail:
+// wcnss_vregs_off(regulators, size);
+ return rc;
+
+}
+
+
+static int wcn36xx_msm_smsm_change_state(u32 clear_mask, u32 set_mask)
+{
+ return smsm_change_state(SMSM_APPS_STATE, clear_mask, set_mask);
+}
+
+static int wcn36xx_msm_get_hw_mac(u8 *addr)
+{
+ const struct firmware *addr_file = NULL;
+ int status;
+ u8 tmp[18];
+ static const u8 qcom_oui[3] = {0x00, 0x0A, 0xF5};
+ static const char *files = {MAC_ADDR_0};
+
+ status = request_firmware(&addr_file, files, &wmsm.core->dev);
+
+ if (status < 0) {
+ /* Assign a random mac with Qualcomm oui */
+ dev_err(&wmsm.core->dev, "Failed (%d) to read macaddress file %s, using a random address instead", status,
+ files);
+ memcpy(addr, qcom_oui, 3);
+ get_random_bytes(addr + 3, 3);
+ } else {
+ memset(tmp, 0, sizeof(tmp));
+ memcpy(tmp, addr_file->data, sizeof(tmp) - 1);
+ sscanf(tmp, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
+ &addr[0],
+ &addr[1],
+ &addr[2],
+ &addr[3],
+ &addr[4],
+ &addr[5]);
+
+ release_firmware(addr_file);
+ }
+
+ return 0;
+}
+
+static int wcn36xx_msm_smd_send_and_wait(char *buf, size_t len)
+{
+ int avail;
+ int ret = 0;
+
+ avail = smd_write_avail(wmsm.smd_ch);
+
+ if (avail >= len) {
+ avail = smd_write(wmsm.smd_ch, buf, len);
+ if (avail != len) {
+ dev_err(&wmsm.core->dev,
+ "Cannot write to SMD channel\n");
+ ret = -EAGAIN;
+ goto out;
+ }
+ } else {
+ dev_err(&wmsm.core->dev,
+ "SMD channel can accept only %d bytes\n", avail);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+static void wcn36xx_msm_smd_notify(void *data, unsigned event)
+{
+ struct wcn36xx_msm *wmsm_priv = (struct wcn36xx_msm *)data;
+
+ switch (event) {
+ case SMD_EVENT_OPEN:
+ complete(&wmsm_priv->smd_compl);
+ break;
+ case SMD_EVENT_DATA:
+ queue_work(wmsm_priv->wq, &wmsm_priv->smd_work);
+ break;
+ case SMD_EVENT_CLOSE:
+ break;
+ case SMD_EVENT_STATUS:
+ break;
+ case SMD_EVENT_REOPEN_READY:
+ break;
+ default:
+ dev_err(&wmsm_priv->core->dev,
+ "%s: SMD_EVENT (%d) not supported\n", __func__, event);
+ break;
+ }
+}
+
+static void wcn36xx_msm_smd_work(struct work_struct *work)
+{
+ int avail;
+ int msg_len;
+ void *msg;
+ int ret;
+ struct wcn36xx_msm *wmsm_priv =
+ container_of(work, struct wcn36xx_msm, smd_work);
+
+ while (1) {
+ msg_len = smd_cur_packet_size(wmsm_priv->smd_ch);
+ if (0 == msg_len) {
+ return;
+ }
+ avail = smd_read_avail(wmsm_priv->smd_ch);
+ if (avail < msg_len) {
+ return;
+ }
+ msg = kmalloc(msg_len, GFP_KERNEL);
+ if (NULL == msg) {
+ return;
+ }
+
+ ret = smd_read(wmsm_priv->smd_ch, msg, msg_len);
+ if (ret != msg_len) {
+ return;
+ }
+ wmsm_priv->rsp_cb(wmsm_priv->drv_priv, msg, msg_len);
+ kfree(msg);
+ }
+}
+
+int wcn36xx_msm_smd_open(void *drv_priv, void *rsp_cb)
+{
+ int ret, left;
+ wmsm.drv_priv = drv_priv;
+ wmsm.rsp_cb = rsp_cb;
+ INIT_WORK(&wmsm.smd_work, wcn36xx_msm_smd_work);
+ init_completion(&wmsm.smd_compl);
+
+ wmsm.wq = create_workqueue("wcn36xx_msm_smd_wq");
+ if (!wmsm.wq) {
+ dev_err(&wmsm.core->dev, "failed to allocate wq");
+ ret = -ENOMEM;
+ return ret;
+ }
+
+ ret = smd_named_open_on_edge("WLAN_CTRL", SMD_APPS_WCNSS,
+ &wmsm.smd_ch, &wmsm, wcn36xx_msm_smd_notify);
+ if (ret) {
+ dev_err(&wmsm.core->dev,
+ "smd_named_open_on_edge failed: %d\n", ret);
+ return ret;
+ }
+
+ left = wait_for_completion_interruptible_timeout(&wmsm.smd_compl,
+ msecs_to_jiffies(HAL_MSG_TIMEOUT));
+ if (left <= 0) {
+ dev_err(&wmsm.core->dev,
+ "timeout waiting for smd open: %d\n", ret);
+ return left;
+ }
+
+ /* Not to receive INT until the whole buf from SMD is read */
+ smd_disable_read_intr(wmsm.smd_ch);
+
+ return 0;
+}
+
+void wcn36xx_msm_smd_close(void)
+{
+ smd_close(wmsm.smd_ch);
+ flush_workqueue(wmsm.wq);
+ destroy_workqueue(wmsm.wq);
+}
+
+int wcn36xx_msm_shutdown(const struct subsys_desc *desc, bool force_stop)
+{
+ return 0;
+}
+int wcn36xx_msm_powerup(const struct subsys_desc *desc)
+{
+ return 0;
+}
+
+static int wcn36xx_msm_probe(struct platform_device *pdev)
+{
+ int ret, pil_retry = 0;
+ struct resource *wcnss_memory;
+ struct resource *tx_irq;
+ struct resource *rx_irq;
+ struct resource res[3];
+ void *pil;
+
+ wmsm.core = platform_device_alloc("wcn36xx", -1);
+
+ dev_err(&pdev->dev, "%s starting\n", __func__);
+
+ memset(res, 0x00, sizeof(res));
+ wmsm.ctrl_ops.open = wcn36xx_msm_smd_open;
+ wmsm.ctrl_ops.close = wcn36xx_msm_smd_close;
+ wmsm.ctrl_ops.tx = wcn36xx_msm_smd_send_and_wait;
+ wmsm.ctrl_ops.get_hw_mac = wcn36xx_msm_get_hw_mac;
+ wmsm.ctrl_ops.smsm_change_state = wcn36xx_msm_smsm_change_state;
+ wcnss_memory =
+ platform_get_resource_byname(pdev,
+ IORESOURCE_MEM,
+ "wcnss_mmio");
+ if (wcnss_memory == NULL) {
+ dev_err(&wmsm.core->dev,
+ "Failed to get wcnss wlan memory map.\n");
+ ret = -ENOMEM;
+ return ret;
+ }
+ memcpy(&res[0], wcnss_memory, sizeof(*wcnss_memory));
+
+ tx_irq = platform_get_resource_byname(pdev,
+ IORESOURCE_IRQ,
+ "wcnss_wlantx_irq");
+ if (tx_irq == NULL) {
+ dev_err(&wmsm.core->dev, "Failed to get wcnss tx_irq");
+ ret = -ENOMEM;
+ return ret;
+ }
+ memcpy(&res[1], tx_irq, sizeof(*tx_irq));
+
+ rx_irq = platform_get_resource_byname(pdev,
+ IORESOURCE_IRQ,
+ "wcnss_wlanrx_irq");
+ if (rx_irq == NULL) {
+ dev_err(&wmsm.core->dev, "Failed to get wcnss rx_irq");
+ ret = -ENOMEM;
+ return ret;
+ }
+ memcpy(&res[2], rx_irq, sizeof(*rx_irq));
+
+ platform_device_add_resources(wmsm.core, res, ARRAY_SIZE(res));
+
+ ret = platform_device_add_data(wmsm.core, &wmsm.ctrl_ops,
+ sizeof(wmsm.ctrl_ops));
+ if (ret) {
+ dev_err(&wmsm.core->dev, "Can't add platform data\n");
+ ret = -ENOMEM;
+ return ret;
+ }
+
+ platform_device_add(wmsm.core);
+
+ dev_err(&pdev->dev, "%s initialized\n", __func__);
+
+ return 0;
+}
+static int wcn36xx_msm_remove(struct platform_device *pdev)
+{
+ platform_device_del(wmsm.core);
+ platform_device_put(wmsm.core);
+
+ return 0;
+}
+
+static const struct of_device_id wcn36xx_msm_match_table[] = {
+ { .compatible = "qcom,wcn36xx" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, wcn36xx_msm_match_table);
+
+static struct platform_driver wcn36xx_msm_driver = {
+ .probe = wcn36xx_msm_probe,
+ .remove = wcn36xx_msm_remove,
+ .driver = {
+ .name = "wcn36xx-msm",
+ .owner = THIS_MODULE,
+ .of_match_table = wcn36xx_msm_match_table,
+ },
+};
+
+static int __init wcn36xx_msm_init(void)
+{
+ return platform_driver_register(&wcn36xx_msm_driver);
+}
+module_init(wcn36xx_msm_init);
+
+static void __exit wcn36xx_msm_exit(void)
+{
+ platform_driver_unregister(&wcn36xx_msm_driver);
+}
+module_exit(wcn36xx_msm_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Eugene Krasnikov k.eugene.e@gmail.com");
+MODULE_FIRMWARE(MAC_ADDR_0);
+
diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
index f0fb81dfd17b..4b0bdb547f67 100644
--- a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
+++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
@@ -229,6 +229,7 @@ struct wcn36xx {
#define WCN36XX_CHIP_3660 0
#define WCN36XX_CHIP_3680 1
+#define WCN36XX_CHIP_3620 2
static inline bool wcn36xx_is_fw_version(struct wcn36xx *wcn,
u8 major,
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index 788d10385cea..c6f5cf4f3b50 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -41,8 +41,6 @@
#include <soc/qcom/smd.h>
-#define DEBUG
-
#define MSM_APCS_GCC_BASE IOMEM(0xFA006000)
//#include <mach/msm_iomap.h>
@@ -2453,7 +2451,7 @@ wcnss_trigger_config(struct platform_device *pdev)
goto fail_ioremap;
}
penv->msm_wcnss_base = (void *)
- devm_ioremap_resource(&pdev->dev, res);
+ ioremap(res->start, res->end - res->start - 1);
} else {
pr_err("is riva\n");
res = platform_get_resource_byname(pdev,
diff --git a/drivers/soc/qcom/peripheral-loader.c b/drivers/soc/qcom/peripheral-loader.c
index c774b33bafa5..d2e1b7e8f978 100644
--- a/drivers/soc/qcom/peripheral-loader.c
+++ b/drivers/soc/qcom/peripheral-loader.c
@@ -545,11 +545,6 @@ static int pil_load_seg(struct pil_desc *desc, struct pil_seg *seg)
fw_name);
return ret;
}
- if (fw->size != seg->filesz) {
- pil_err(desc, "Blob size %u doesn't match %lu\n",
- ret, seg->filesz);
- return -EPERM;
- }
//pr_err("%s: memcpy to PA 0x%x len 0x%x\n", __func__,
//(u32)seg->paddr, (u32)seg->filesz);