ath10k: platform driver for WCN3990 SNOC WLAN module

WCN3990 is integrated 802.11ac chipset with SNOC
bus interface. Add snoc layer driver registration
and associated ops.

CRs-Fixed: 1112488
Change-Id: I6106c617514609bd3fe41d9bbfbd34bf0588ef36
Signed-off-by: Govind Singh <govinds@codeaurora.org>
Signed-off-by: Sarada Prasanna Garnayak <sgarna@codeaurora.org>
This commit is contained in:
Govind Singh 2016-11-21 16:34:57 +05:30 committed by Sarada Prasanna Garnayak
parent 314869eb56
commit 3a27615253
3 changed files with 388 additions and 0 deletions

View file

@ -0,0 +1,16 @@
* Qualcomm Technologies, Inc. WCN3990 chipset WLAN platform Driver
This driver adds support for the Integrated WCN3990 WLAN module, WCN3990
is integrated 802.11ac chipset with SNOC bus interface. It also add support
for SNOC bus registration, copy engine configuration for the WCN3990 chipset,
shadow register configuration, create host to target communication interface
to interact with WLAN firmware, WLAN module interface control and data
receive(RX)/transmit(TX) control.
Required properties:
- compatible: "qcom,wcn3990-wifi";
Example:
qcom,msm_ath10k@18000000 {
compatible = "qcom,wcn3990-wifi";
};

View file

@ -0,0 +1,169 @@
/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only 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.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include "debug.h"
#include "hif.h"
#include "htc.h"
#include "ce.h"
#include "snoc.h"
#include <soc/qcom/icnss.h>
#include <linux/of.h>
#include <linux/platform_device.h>
void ath10k_snoc_write32(void *ar, u32 offset, u32 value)
{
}
u32 ath10k_snoc_read32(void *ar, u32 offset)
{
u32 val = 0;
return val;
}
static int ath10k_snoc_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
struct ath10k_hif_sg_item *items, int n_items)
{
return 0;
}
static u16 ath10k_snoc_hif_get_free_queue_number(struct ath10k *ar, u8 pipe)
{
return 0;
}
static void ath10k_snoc_hif_send_complete_check(struct ath10k *ar, u8 pipe,
int force)
{
}
static int ath10k_snoc_hif_map_service_to_pipe(struct ath10k *ar,
u16 service_id,
u8 *ul_pipe, u8 *dl_pipe)
{
return 0;
}
static void ath10k_snoc_hif_get_default_pipe(struct ath10k *ar,
u8 *ul_pipe, u8 *dl_pipe)
{
}
static void ath10k_snoc_hif_stop(struct ath10k *ar)
{
}
static void ath10k_snoc_hif_power_down(struct ath10k *ar)
{
}
static int ath10k_snoc_hif_start(struct ath10k *ar)
{
return 0;
}
static int ath10k_snoc_hif_power_up(struct ath10k *ar)
{
return 0;
}
static const struct ath10k_hif_ops ath10k_snoc_hif_ops = {
.tx_sg = ath10k_snoc_hif_tx_sg,
.start = ath10k_snoc_hif_start,
.stop = ath10k_snoc_hif_stop,
.map_service_to_pipe = ath10k_snoc_hif_map_service_to_pipe,
.get_default_pipe = ath10k_snoc_hif_get_default_pipe,
.send_complete_check = ath10k_snoc_hif_send_complete_check,
.get_free_queue_number = ath10k_snoc_hif_get_free_queue_number,
.power_up = ath10k_snoc_hif_power_up,
.power_down = ath10k_snoc_hif_power_down,
.read32 = ath10k_snoc_read32,
.write32 = ath10k_snoc_write32,
};
static int ath10k_snoc_probe(struct platform_device *pdev)
{
int ret = 0;
struct ath10k *ar;
struct ath10k_snoc *ar_snoc;
enum ath10k_hw_rev hw_rev;
struct device *dev;
dev = &pdev->dev;
hw_rev = ATH10K_HW_WCN3990;
ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(37));
ar = ath10k_core_create(sizeof(*ar_snoc), dev, ATH10K_BUS_SNOC,
hw_rev, &ath10k_snoc_hif_ops);
if (!ar) {
dev_err(dev, "failed to allocate core\n");
return -ENOMEM;
}
ath10k_dbg(ar, ATH10K_DBG_SNOC, "%s:WCN3990 probed\n", __func__);
return ret;
}
static int ath10k_snoc_remove(struct platform_device *pdev)
{
struct ath10k *ar = platform_get_drvdata(pdev);
struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
if (!ar)
return -EINVAL;
if (!ar_snoc)
return -EINVAL;
ath10k_core_destroy(ar);
ath10k_dbg(ar, ATH10K_DBG_SNOC, "%s:WCN3990 removed\n", __func__);
return 0;
}
static const struct of_device_id ath10k_snoc_dt_match[] = {
{.compatible = "qcom,wcn3990-wifi"},
{}
};
MODULE_DEVICE_TABLE(of, ath10k_snoc_dt_match);
static struct platform_driver ath10k_snoc_driver = {
.probe = ath10k_snoc_probe,
.remove = ath10k_snoc_remove,
.driver = {
.name = "ath10k_snoc",
.owner = THIS_MODULE,
.of_match_table = ath10k_snoc_dt_match,
},
};
static int __init ath10k_snoc_init(void)
{
int ret;
ret = platform_driver_register(&ath10k_snoc_driver);
if (ret)
pr_err("failed to register ath10k snoc driver: %d\n",
ret);
return ret;
}
module_init(ath10k_snoc_init);
static void __exit ath10k_snoc_exit(void)
{
platform_driver_unregister(&ath10k_snoc_driver);
}
module_exit(ath10k_snoc_exit);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Driver support for Atheros WCN3990 SNOC devices");

View file

@ -0,0 +1,203 @@
/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only 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.
*/
#ifndef _SNOC_H_
#define _SNOC_H_
#include "hw.h"
#include "ce.h"
#include "pci.h"
#define ATH10K_SNOC_RX_POST_RETRY_MS 50
/* struct snoc_state: SNOC target state
* @pipe_cfg_addr: pipe configuration address
* @svc_to_pipe_map: pipe services
*/
struct snoc_state {
u32 pipe_cfg_addr;
u32 svc_to_pipe_map;
};
/* struct ath10k_snoc_pipe: SNOC pipe configuration
* @ath10k_ce_pipe: pipe handle
* @pipe_num: pipe number
* @hif_ce_state: pointer to ce state
* @buf_sz: buffer size
* @pipe_lock: pipe lock
* @ar_snoc: snoc private structure
* @intr: tasklet structure
*/
struct ath10k_snoc_pipe {
struct ath10k_ce_pipe *ce_hdl;
u8 pipe_num;
struct ath10k *hif_ce_state;
size_t buf_sz;
/* protect ce info */
spinlock_t pipe_lock;
struct ath10k_snoc *ar_snoc;
struct tasklet_struct intr;
};
/* struct ath10k_snoc_supp_chip: supported chip set
* @dev_id: device id
* @rev_id: revison id
*/
struct ath10k_snoc_supp_chip {
u32 dev_id;
u32 rev_id;
};
/* struct ath10k_snoc_info: SNOC info struct
* @v_addr: base virtual address
* @p_addr: base physical address
* @chip_id: chip id
* @chip_family: chip family
* @board_id: board id
* @soc_id: soc id
* @fw_version: fw version
*/
struct ath10k_snoc_info {
void __iomem *v_addr;
phys_addr_t p_addr;
u32 chip_id;
u32 chip_family;
u32 board_id;
u32 soc_id;
u32 fw_version;
};
/* struct ath10k_target_info: SNOC target info
* @target_version: target version
* @target_type: target type
* @target_revision: target revision
* @soc_version: target soc version
*/
struct ath10k_target_info {
u32 target_version;
u32 target_type;
u32 target_revision;
u32 soc_version;
};
/* struct ath10k_snoc: SNOC info struct
* @dev: device structure
* @ar:ath10k base structure
* @mem: mem base virtual address
* @mem_pa: mem base physical address
* @target_info: snoc target info
* @mem_len: mempry map length
* @intr_tq: rx tasklet handle
* @pipe_info: pipe info struct
* @ce_lock: protect ce structures
* @ce_states: maps ce id to ce state
* @rx_post_retry: rx buffer post processing timer
* @vaddr_rri_on_ddr: virtual address for RRI
* @is_driver_probed: flag to indicate driver state
*/
struct ath10k_snoc {
struct device *dev;
struct ath10k *ar;
void __iomem *mem;
dma_addr_t mem_pa;
struct ath10k_target_info target_info;
size_t mem_len;
struct tasklet_struct intr_tq;
struct ath10k_snoc_pipe pipe_info[CE_COUNT_MAX];
/* protects CE info */
spinlock_t ce_lock;
struct ath10k_ce_pipe ce_states[CE_COUNT_MAX];
struct timer_list rx_post_retry;
u32 *vaddr_rri_on_ddr;
bool is_driver_probed;
};
/* struct ath10k_ce_tgt_pipe_cfg: target pipe configuration
* @pipe_num: pipe number
* @pipe_dir: pipe direction
* @nentries: entries in pipe
* @nbytes_max: pipe max size
* @flags: pipe flags
* @reserved: reserved
*/
struct ath10k_ce_tgt_pipe_cfg {
u32 pipe_num;
u32 pipe_dir;
u32 nentries;
u32 nbytes_max;
u32 flags;
u32 reserved;
};
/* struct ath10k_ce_svc_pipe_cfg: service pipe configuration
* @service_id: target version
* @pipe_dir: pipe direction
* @pipe_num: pipe number
*/
struct ath10k_ce_svc_pipe_cfg {
u32 service_id;
u32 pipe_dir;
u32 pipe_num;
};
/* struct ath10k_shadow_reg_cfg: shadow register configuration
* @ce_id: copy engine id
* @reg_offset: offset to copy engine
*/
struct ath10k_shadow_reg_cfg {
u16 ce_id;
u16 reg_offset;
};
/* struct ath10k_wlan_enable_cfg: wlan enable configuration
* @num_ce_tgt_cfg: no of ce target configuration
* @ce_tgt_cfg: target ce configuration
* @num_ce_svc_pipe_cfg: no of ce service configuration
* @ce_svc_cfg: ce service configuration
* @num_shadow_reg_cfg: no of shadow registers
* @shadow_reg_cfg: shadow register configuration
*/
struct ath10k_wlan_enable_cfg {
u32 num_ce_tgt_cfg;
struct ath10k_ce_tgt_pipe_cfg *ce_tgt_cfg;
u32 num_ce_svc_pipe_cfg;
struct ath10k_ce_svc_pipe_cfg *ce_svc_cfg;
u32 num_shadow_reg_cfg;
struct ath10k_shadow_reg_cfg *shadow_reg_cfg;
};
/* enum ath10k_driver_mode: ath10k driver mode
* @ATH10K_MISSION: mission mode
* @ATH10K_FTM: ftm mode
* @ATH10K_EPPING: epping mode
* @ATH10K_OFF: off mode
*/
enum ath10k_driver_mode {
ATH10K_MISSION,
ATH10K_FTM,
ATH10K_EPPING,
ATH10K_OFF
};
static inline struct ath10k_snoc *ath10k_snoc_priv(struct ath10k *ar)
{
return (struct ath10k_snoc *)ar->drv_priv;
}
void ath10k_snoc_write32(void *ar, u32 offset, u32 value);
void ath10k_snoc_soc_write32(struct ath10k *ar, u32 addr, u32 val);
void ath10k_snoc_reg_write32(struct ath10k *ar, u32 addr, u32 val);
u32 ath10k_snoc_read32(void *ar, u32 offset);
u32 ath10k_snoc_soc_read32(struct ath10k *ar, u32 addr);
u32 ath10k_snoc_reg_read32(struct ath10k *ar, u32 addr);
#endif /* _SNOC_H_ */