Commit ba94c753 authored by Govind Singh's avatar Govind Singh Committed by Kalle Valo

ath10k: add QMI message handshake for wcn3990 client

Add WCN3990 QMI client handshakes for Q6 integrated WLAN connectivity
subsystem. This layer is responsible for communicating qmi control
messages to wifi fw QMI service using QMI messaging protocol.

Qualcomm MSM Interface(QMI) is a messaging format used to communicate
between components running between remote processors with underlying
transport layer based on integrated chipset(shared memory) or
discrete chipset(PCI/USB/SDIO/UART).
Signed-off-by: default avatarGovind Singh <govinds@codeaurora.org>
Reviewed-by: default avatarBjorn Andersson <bjorn.andersson@linaro.org>
Acked-by: default avatarNiklas Cassel <niklas.cassel@linaro.org>
Reviewed-by: default avatarBrian Norris <briannorris@chromium.org>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent 35a66576
......@@ -44,6 +44,7 @@ config ATH10K_SNOC
tristate "Qualcomm ath10k SNOC support (EXPERIMENTAL)"
depends on ATH10K
depends on ARCH_QCOM || COMPILE_TEST
select QCOM_QMI_HELPERS
---help---
This module adds support for integrated WCN3990 chip connected
to system NOC(SNOC). Currently work in progress and will not
......
......@@ -36,7 +36,9 @@ obj-$(CONFIG_ATH10K_USB) += ath10k_usb.o
ath10k_usb-y += usb.o
obj-$(CONFIG_ATH10K_SNOC) += ath10k_snoc.o
ath10k_snoc-y += snoc.o
ath10k_snoc-y += qmi.o \
qmi_wlfw_v01.o \
snoc.o
# for tracing framework to find trace.h
CFLAGS_trace.o := -I$(src)
......@@ -989,7 +989,7 @@ static int ath10k_download_fw(struct ath10k *ar)
data, data_len);
}
static void ath10k_core_free_board_files(struct ath10k *ar)
void ath10k_core_free_board_files(struct ath10k *ar)
{
if (!IS_ERR(ar->normal_mode_fw.board))
release_firmware(ar->normal_mode_fw.board);
......@@ -1004,6 +1004,7 @@ static void ath10k_core_free_board_files(struct ath10k *ar)
ar->normal_mode_fw.ext_board_data = NULL;
ar->normal_mode_fw.ext_board_len = 0;
}
EXPORT_SYMBOL(ath10k_core_free_board_files);
static void ath10k_core_free_firmware_files(struct ath10k *ar)
{
......@@ -1367,7 +1368,7 @@ static int ath10k_core_create_eboard_name(struct ath10k *ar, char *name,
return -1;
}
static int ath10k_core_fetch_board_file(struct ath10k *ar, int bd_ie_type)
int ath10k_core_fetch_board_file(struct ath10k *ar, int bd_ie_type)
{
char boardname[100], fallback_boardname[100];
int ret;
......@@ -1415,6 +1416,7 @@ static int ath10k_core_fetch_board_file(struct ath10k *ar, int bd_ie_type)
ath10k_dbg(ar, ATH10K_DBG_BOOT, "using board api %d\n", ar->bd_api);
return 0;
}
EXPORT_SYMBOL(ath10k_core_fetch_board_file);
static int ath10k_core_get_ext_board_id_from_otp(struct ath10k *ar)
{
......
......@@ -1218,5 +1218,7 @@ void ath10k_core_stop(struct ath10k *ar);
int ath10k_core_register(struct ath10k *ar,
const struct ath10k_bus_params *bus_params);
void ath10k_core_unregister(struct ath10k *ar);
int ath10k_core_fetch_board_file(struct ath10k *ar, int bd_ie_type);
void ath10k_core_free_board_files(struct ath10k *ar);
#endif /* _CORE_H_ */
This diff is collapsed.
/*
* Copyright (c) 2018 The Linux Foundation. All rights reserved.
*
* 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.
*/
#ifndef _ATH10K_QMI_H_
#define _ATH10K_QMI_H_
#include <linux/soc/qcom/qmi.h>
#include <linux/qrtr.h>
#include "qmi_wlfw_v01.h"
#define MAX_NUM_MEMORY_REGIONS 2
#define MAX_TIMESTAMP_LEN 32
#define MAX_BUILD_ID_LEN 128
#define MAX_NUM_CAL_V01 5
enum ath10k_qmi_driver_event_type {
ATH10K_QMI_EVENT_SERVER_ARRIVE,
ATH10K_QMI_EVENT_SERVER_EXIT,
ATH10K_QMI_EVENT_FW_READY_IND,
ATH10K_QMI_EVENT_FW_DOWN_IND,
ATH10K_QMI_EVENT_MSA_READY_IND,
ATH10K_QMI_EVENT_MAX,
};
struct ath10k_msa_mem_info {
phys_addr_t addr;
u32 size;
bool secure;
};
struct ath10k_qmi_chip_info {
u32 chip_id;
u32 chip_family;
};
struct ath10k_qmi_board_info {
u32 board_id;
};
struct ath10k_qmi_soc_info {
u32 soc_id;
};
struct ath10k_qmi_cal_data {
u32 cal_id;
u32 total_size;
u8 *data;
};
struct ath10k_tgt_pipe_cfg {
__le32 pipe_num;
__le32 pipe_dir;
__le32 nentries;
__le32 nbytes_max;
__le32 flags;
__le32 reserved;
};
struct ath10k_svc_pipe_cfg {
__le32 service_id;
__le32 pipe_dir;
__le32 pipe_num;
};
struct ath10k_shadow_reg_cfg {
__le16 ce_id;
__le16 reg_offset;
};
struct ath10k_qmi_wlan_enable_cfg {
u32 num_ce_tgt_cfg;
struct ath10k_tgt_pipe_cfg *ce_tgt_cfg;
u32 num_ce_svc_pipe_cfg;
struct ath10k_svc_pipe_cfg *ce_svc_cfg;
u32 num_shadow_reg_cfg;
struct ath10k_shadow_reg_cfg *shadow_reg_cfg;
};
struct ath10k_qmi_driver_event {
struct list_head list;
enum ath10k_qmi_driver_event_type type;
void *data;
};
struct ath10k_qmi {
struct ath10k *ar;
struct qmi_handle qmi_hdl;
struct sockaddr_qrtr sq;
struct work_struct event_work;
struct workqueue_struct *event_wq;
struct list_head event_list;
spinlock_t event_lock; /* spinlock for qmi event list */
u32 nr_mem_region;
struct ath10k_msa_mem_info mem_region[MAX_NUM_MEMORY_REGIONS];
dma_addr_t msa_pa;
u32 msa_mem_size;
void *msa_va;
struct ath10k_qmi_chip_info chip_info;
struct ath10k_qmi_board_info board_info;
struct ath10k_qmi_soc_info soc_info;
char fw_build_id[MAX_BUILD_ID_LEN + 1];
u32 fw_version;
bool fw_ready;
char fw_build_timestamp[MAX_TIMESTAMP_LEN + 1];
struct ath10k_qmi_cal_data cal_data[MAX_NUM_CAL_V01];
};
int ath10k_qmi_wlan_enable(struct ath10k *ar,
struct ath10k_qmi_wlan_enable_cfg *config,
enum wlfw_driver_mode_enum_v01 mode,
const char *version);
int ath10k_qmi_wlan_disable(struct ath10k *ar);
int ath10k_qmi_register_service_notifier(struct notifier_block *nb);
int ath10k_qmi_init(struct ath10k *ar, u32 msa_size);
int ath10k_qmi_deinit(struct ath10k *ar);
#endif /* ATH10K_QMI_H */
......@@ -67,6 +67,72 @@ static void ath10k_snoc_pktlog_rx_cb(struct ath10k_ce_pipe *ce_state);
static const struct ath10k_snoc_drv_priv drv_priv = {
.hw_rev = ATH10K_HW_WCN3990,
.dma_mask = DMA_BIT_MASK(37),
.msa_size = 0x100000,
};
#define WCN3990_SRC_WR_IDX_OFFSET 0x3C
#define WCN3990_DST_WR_IDX_OFFSET 0x40
static struct ath10k_shadow_reg_cfg target_shadow_reg_cfg_map[] = {
{
.ce_id = __cpu_to_le16(0),
.reg_offset = __cpu_to_le16(WCN3990_SRC_WR_IDX_OFFSET),
},
{
.ce_id = __cpu_to_le16(3),
.reg_offset = __cpu_to_le16(WCN3990_SRC_WR_IDX_OFFSET),
},
{
.ce_id = __cpu_to_le16(4),
.reg_offset = __cpu_to_le16(WCN3990_SRC_WR_IDX_OFFSET),
},
{
.ce_id = __cpu_to_le16(5),
.reg_offset = __cpu_to_le16(WCN3990_SRC_WR_IDX_OFFSET),
},
{
.ce_id = __cpu_to_le16(7),
.reg_offset = __cpu_to_le16(WCN3990_SRC_WR_IDX_OFFSET),
},
{
.ce_id = __cpu_to_le16(1),
.reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),
},
{
.ce_id = __cpu_to_le16(2),
.reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),
},
{
.ce_id = __cpu_to_le16(7),
.reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),
},
{
.ce_id = __cpu_to_le16(8),
.reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),
},
{
.ce_id = __cpu_to_le16(9),
.reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),
},
{
.ce_id = __cpu_to_le16(10),
.reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),
},
{
.ce_id = __cpu_to_le16(11),
.reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),
},
};
static struct ce_attr host_ce_config_wlan[] = {
......@@ -176,6 +242,128 @@ static struct ce_attr host_ce_config_wlan[] = {
},
};
static struct ce_pipe_config target_ce_config_wlan[] = {
/* CE0: host->target HTC control and raw streams */
{
.pipenum = __cpu_to_le32(0),
.pipedir = __cpu_to_le32(PIPEDIR_OUT),
.nentries = __cpu_to_le32(32),
.nbytes_max = __cpu_to_le32(2048),
.flags = __cpu_to_le32(CE_ATTR_FLAGS),
.reserved = __cpu_to_le32(0),
},
/* CE1: target->host HTT + HTC control */
{
.pipenum = __cpu_to_le32(1),
.pipedir = __cpu_to_le32(PIPEDIR_IN),
.nentries = __cpu_to_le32(32),
.nbytes_max = __cpu_to_le32(2048),
.flags = __cpu_to_le32(CE_ATTR_FLAGS),
.reserved = __cpu_to_le32(0),
},
/* CE2: target->host WMI */
{
.pipenum = __cpu_to_le32(2),
.pipedir = __cpu_to_le32(PIPEDIR_IN),
.nentries = __cpu_to_le32(64),
.nbytes_max = __cpu_to_le32(2048),
.flags = __cpu_to_le32(CE_ATTR_FLAGS),
.reserved = __cpu_to_le32(0),
},
/* CE3: host->target WMI */
{
.pipenum = __cpu_to_le32(3),
.pipedir = __cpu_to_le32(PIPEDIR_OUT),
.nentries = __cpu_to_le32(32),
.nbytes_max = __cpu_to_le32(2048),
.flags = __cpu_to_le32(CE_ATTR_FLAGS),
.reserved = __cpu_to_le32(0),
},
/* CE4: host->target HTT */
{
.pipenum = __cpu_to_le32(4),
.pipedir = __cpu_to_le32(PIPEDIR_OUT),
.nentries = __cpu_to_le32(256),
.nbytes_max = __cpu_to_le32(256),
.flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR),
.reserved = __cpu_to_le32(0),
},
/* CE5: target->host HTT (HIF->HTT) */
{
.pipenum = __cpu_to_le32(5),
.pipedir = __cpu_to_le32(PIPEDIR_OUT),
.nentries = __cpu_to_le32(1024),
.nbytes_max = __cpu_to_le32(64),
.flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR),
.reserved = __cpu_to_le32(0),
},
/* CE6: Reserved for target autonomous hif_memcpy */
{
.pipenum = __cpu_to_le32(6),
.pipedir = __cpu_to_le32(PIPEDIR_INOUT),
.nentries = __cpu_to_le32(32),
.nbytes_max = __cpu_to_le32(16384),
.flags = __cpu_to_le32(CE_ATTR_FLAGS),
.reserved = __cpu_to_le32(0),
},
/* CE7 used only by Host */
{
.pipenum = __cpu_to_le32(7),
.pipedir = __cpu_to_le32(4),
.nentries = __cpu_to_le32(0),
.nbytes_max = __cpu_to_le32(0),
.flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR),
.reserved = __cpu_to_le32(0),
},
/* CE8 Target to uMC */
{
.pipenum = __cpu_to_le32(8),
.pipedir = __cpu_to_le32(PIPEDIR_IN),
.nentries = __cpu_to_le32(32),
.nbytes_max = __cpu_to_le32(2048),
.flags = __cpu_to_le32(0),
.reserved = __cpu_to_le32(0),
},
/* CE9 target->host HTT */
{
.pipenum = __cpu_to_le32(9),
.pipedir = __cpu_to_le32(PIPEDIR_IN),
.nentries = __cpu_to_le32(32),
.nbytes_max = __cpu_to_le32(2048),
.flags = __cpu_to_le32(CE_ATTR_FLAGS),
.reserved = __cpu_to_le32(0),
},
/* CE10 target->host HTT */
{
.pipenum = __cpu_to_le32(10),
.pipedir = __cpu_to_le32(PIPEDIR_IN),
.nentries = __cpu_to_le32(32),
.nbytes_max = __cpu_to_le32(2048),
.flags = __cpu_to_le32(CE_ATTR_FLAGS),
.reserved = __cpu_to_le32(0),
},
/* CE11 target autonomous qcache memcpy */
{
.pipenum = __cpu_to_le32(11),
.pipedir = __cpu_to_le32(PIPEDIR_IN),
.nentries = __cpu_to_le32(32),
.nbytes_max = __cpu_to_le32(2048),
.flags = __cpu_to_le32(CE_ATTR_FLAGS),
.reserved = __cpu_to_le32(0),
},
};
static struct service_to_pipe target_service_to_ce_map_wlan[] = {
{
__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VO),
......@@ -766,11 +954,47 @@ static int ath10k_snoc_init_pipes(struct ath10k *ar)
static int ath10k_snoc_wlan_enable(struct ath10k *ar)
{
return 0;
struct ath10k_tgt_pipe_cfg tgt_cfg[CE_COUNT_MAX];
struct ath10k_qmi_wlan_enable_cfg cfg;
enum wlfw_driver_mode_enum_v01 mode;
int pipe_num;
for (pipe_num = 0; pipe_num < CE_COUNT_MAX; pipe_num++) {
tgt_cfg[pipe_num].pipe_num =
target_ce_config_wlan[pipe_num].pipenum;
tgt_cfg[pipe_num].pipe_dir =
target_ce_config_wlan[pipe_num].pipedir;
tgt_cfg[pipe_num].nentries =
target_ce_config_wlan[pipe_num].nentries;
tgt_cfg[pipe_num].nbytes_max =
target_ce_config_wlan[pipe_num].nbytes_max;
tgt_cfg[pipe_num].flags =
target_ce_config_wlan[pipe_num].flags;
tgt_cfg[pipe_num].reserved = 0;
}
cfg.num_ce_tgt_cfg = sizeof(target_ce_config_wlan) /
sizeof(struct ath10k_tgt_pipe_cfg);
cfg.ce_tgt_cfg = (struct ath10k_tgt_pipe_cfg *)
&tgt_cfg;
cfg.num_ce_svc_pipe_cfg = sizeof(target_service_to_ce_map_wlan) /
sizeof(struct ath10k_svc_pipe_cfg);
cfg.ce_svc_cfg = (struct ath10k_svc_pipe_cfg *)
&target_service_to_ce_map_wlan;
cfg.num_shadow_reg_cfg = sizeof(target_shadow_reg_cfg_map) /
sizeof(struct ath10k_shadow_reg_cfg);
cfg.shadow_reg_cfg = (struct ath10k_shadow_reg_cfg *)
&target_shadow_reg_cfg_map;
mode = QMI_WLFW_MISSION_V01;
return ath10k_qmi_wlan_enable(ar, &cfg, mode,
NULL);
}
static void ath10k_snoc_wlan_disable(struct ath10k *ar)
{
ath10k_qmi_wlan_disable(ar);
}
static void ath10k_snoc_hif_power_down(struct ath10k *ar)
......@@ -957,6 +1181,32 @@ static int ath10k_snoc_resource_init(struct ath10k *ar)
return ret;
}
int ath10k_snoc_fw_indication(struct ath10k *ar, u64 type)
{
struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
struct ath10k_bus_params bus_params;
int ret;
switch (type) {
case ATH10K_QMI_EVENT_FW_READY_IND:
bus_params.dev_type = ATH10K_DEV_TYPE_LL;
bus_params.chip_id = ar_snoc->target_info.soc_version;
ret = ath10k_core_register(ar, &bus_params);
if (ret) {
ath10k_err(ar, "failed to register driver core: %d\n",
ret);
}
break;
case ATH10K_QMI_EVENT_FW_DOWN_IND:
break;
default:
ath10k_err(ar, "invalid fw indication: %llx\n", type);
return -EINVAL;
}
return 0;
}
static int ath10k_snoc_setup_resource(struct ath10k *ar)
{
struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
......@@ -1281,9 +1531,9 @@ static int ath10k_snoc_probe(struct platform_device *pdev)
struct ath10k_snoc *ar_snoc;
struct device *dev;
struct ath10k *ar;
u32 msa_size;
int ret;
u32 i;
struct ath10k_bus_params bus_params;
of_id = of_match_device(ath10k_snoc_dt_match, &pdev->dev);
if (!of_id) {
......@@ -1313,6 +1563,7 @@ static int ath10k_snoc_probe(struct platform_device *pdev)
ar_snoc->ar = ar;
ar_snoc->ce.bus_ops = &ath10k_snoc_bus_ops;
ar->ce_priv = &ar_snoc->ce;
msa_size = drv_data->msa_size;
ret = ath10k_snoc_resource_init(ar);
if (ret) {
......@@ -1351,12 +1602,10 @@ static int ath10k_snoc_probe(struct platform_device *pdev)
goto err_free_irq;
}
bus_params.dev_type = ATH10K_DEV_TYPE_LL;
bus_params.chip_id = drv_data->hw_rev;
ret = ath10k_core_register(ar, &bus_params);
ret = ath10k_qmi_init(ar, msa_size);
if (ret) {
ath10k_err(ar, "failed to register driver core: %d\n", ret);
goto err_hw_power_off;
ath10k_warn(ar, "failed to register wlfw qmi client: %d\n", ret);
goto err_core_destroy;
}
ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc probe\n");
......@@ -1364,9 +1613,6 @@ static int ath10k_snoc_probe(struct platform_device *pdev)
return 0;
err_hw_power_off:
ath10k_hw_power_off(ar);
err_free_irq:
ath10k_snoc_free_irq(ar);
......@@ -1388,6 +1634,7 @@ static int ath10k_snoc_remove(struct platform_device *pdev)
ath10k_hw_power_off(ar);
ath10k_snoc_free_irq(ar);
ath10k_snoc_release_resource(ar);
ath10k_qmi_deinit(ar);
ath10k_core_destroy(ar);
return 0;
......
......@@ -19,10 +19,12 @@
#include "hw.h"
#include "ce.h"
#include "qmi.h"
struct ath10k_snoc_drv_priv {
enum ath10k_hw_rev hw_rev;
u64 dma_mask;
u32 msa_size;
};
struct snoc_state {
......@@ -81,6 +83,7 @@ struct ath10k_snoc {
struct timer_list rx_post_retry;
struct ath10k_wcn3990_vreg_info *vreg;
struct ath10k_wcn3990_clk_info *clk;
struct ath10k_qmi *qmi;
};
static inline struct ath10k_snoc *ath10k_snoc_priv(struct ath10k *ar)
......@@ -90,5 +93,6 @@ static inline struct ath10k_snoc *ath10k_snoc_priv(struct ath10k *ar)
void ath10k_snoc_write32(struct ath10k *ar, u32 offset, u32 value);
u32 ath10k_snoc_read32(struct ath10k *ar, u32 offset);
int ath10k_snoc_fw_indication(struct ath10k *ar, u64 type);
#endif /* _SNOC_H_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment