diff options
author | Andy Green <andy.green@linaro.org> | 2014-12-20 21:06:46 +0800 |
---|---|---|
committer | Andy Green <andy.green@linaro.org> | 2015-01-06 21:47:34 +0800 |
commit | 675a2ae1edfadf01f62a781b4d34d845a5d6f4a8 (patch) | |
tree | 9dd6dd83fd121603984859db105445ac1e0d85ea | |
parent | 87949a0b30bd42c9be5d55dabb213350e1e868ee (diff) |
wcn36xx mainlinemainline-basis-test-2015-01-06-3
Signed-off-by: Andy Green <andy.green@linaro.org>
-rw-r--r-- | arch/arm/boot/dts/msm8916.dtsi | 61 | ||||
-rw-r--r-- | arch/arm/configs/msm8916-qrd_defconfig | 6 | ||||
-rw-r--r-- | arch/arm/mach-qcom/board.c | 1 | ||||
-rw-r--r-- | arch/arm/mach-qcom/scm.c | 1 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wcn36xx/Makefile | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wcn36xx/dxe.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wcn36xx/dxe.h | 7 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wcn36xx/hal.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wcn36xx/main.c | 9 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wcn36xx/smd.c | 19 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wcn36xx/wcn36xx-msm.c | 429 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wcn36xx/wcn36xx.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/wcnss/wcnss_wlan.c | 4 | ||||
-rw-r--r-- | drivers/soc/qcom/peripheral-loader.c | 5 |
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); |