Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f4284d7a authored by Yuanyuan Liu's avatar Yuanyuan Liu
Browse files

icnss: Add icnss platform driver support for WLAN



This is a snapshot of the icnss driver and
associated files as of msm-4.4 commit:
commit cc193eec69d7 ("icnss: Use fixed memory region
for WLAN MSA0 memory").

CRs-Fixed: 2073915
Change-Id: I062769b437cc2d03d2e2ce160365e76fd745e36f
Signed-off-by: default avatarYuanyuan Liu <yuanliu@codeaurora.org>
parent 09a43fc1
Loading
Loading
Loading
Loading
+62 −0
Original line number Diff line number Diff line
* Qualcomm Technologies Inc Q6 Integrated connectivity Platform Driver

This platform driver adds support for the Integrated WLAN that runs
on Q6 based platforms. WLAN FW on these architecture runs on Q6. This
platform driver communicates with WLAN FW over QMI, WLAN on/off messages
to FW are communicated thru this interface. This driver also listens to
WLAN PD restart notifications.

Required properties:
  - compatible: "qcom,icnss"
  - reg: Memory regions defined as starting address and size
  - reg-names: Names of the memory regions defined in reg entry
  - interrupts: Copy engine interrupt table
  - qcom,wlan-msa-memory: MSA memory size
  - clocks: List of clock phandles
  - clock-names: List of clock names corresponding to the "clocks" property
  - iommus: SMMUs and corresponding Stream IDs needed by WLAN
  - qcom,wlan-smmu-iova-address: I/O virtual address range as <start length>
    format to be used for allocations associated between WLAN and SMMU

Optional properties:
  - <supply-name>-supply: phandle to the regulator device tree node
			   optional "supply-name" is "vdd-0.8-cx-mx".
  - qcom,<supply>-config: Specifies voltage levels for supply. Should be
			   specified in pairs (min, max), units uV.  There can
			   be optional load in uA and Regulator settle delay in
			   uS.
  - qcom,icnss-vadc: VADC handle for vph_pwr read APIs.
  - qcom,icnss-adc_tm: VADC handle for vph_pwr notification APIs.
  - qcom,smmu-s1-bypass: Boolean context flag to set SMMU to S1 bypass
  - qcom,wlan-msa-fixed-region: phandle, specifier pairs to children of /reserved-memory

Example:

    qcom,icnss@0a000000 {
        compatible = "qcom,icnss";
        reg = <0x0a000000 0x1000000>;
        reg-names = "membase";
        clocks = <&clock_gcc clk_aggre2_noc_clk>;
        clock-names = "smmu_aggre2_noc_clk";
        iommus = <&anoc2_smmu 0x1900>,
                 <&anoc2_smmu 0x1901>;
        qcom,wlan-smmu-iova-address = <0 0x10000000>;
        interrupts =
		   <0 130 0 /* CE0 */ >,
		   <0 131 0 /* CE1 */ >,
		   <0 132 0 /* CE2 */ >,
		   <0 133 0 /* CE3 */ >,
		   <0 134 0 /* CE4 */ >,
		   <0 135 0 /* CE5 */ >,
		   <0 136 0 /* CE6 */ >,
		   <0 137 0 /* CE7 */ >,
		   <0 138 0 /* CE8 */ >,
		   <0 139 0 /* CE9 */ >,
		   <0 140 0 /* CE10 */ >,
		   <0 141 0 /* CE11 */ >;
        qcom,wlan-msa-memory = <0x200000>;
	qcom,wlan-msa-fixed-region = <&wlan_msa_mem>;
	qcom,smmu-s1-bypass;
	vdd-0.8-cx-mx-supply = <&pm8998_l5>;
	qcom,vdd-0.8-cx-mx-config = <800000 800000 2400 1000>;
    };
+18 −0
Original line number Diff line number Diff line
@@ -150,3 +150,21 @@ config QCOM_SECURE_BUFFER
	 memory buffers. This ensures that only the correct clients can
	 use this memory and no unauthorized access is made to the
	 buffer

config ICNSS
	tristate "Platform driver for Q6 integrated connectivity"
	select CNSS_UTILS
	---help---
	  This module adds support for Q6 integrated WLAN connectivity
	  subsystem. This module is responsible for communicating WLAN on/off
	  control messages to FW over QMI channel. It is also responsible for
	  handling WLAN PD restart notifications.

config ICNSS_DEBUG
	bool "ICNSS debug support"
	depends on ICNSS
	---help---
	  Say 'Y' here to enable ICNSS driver debug support. Debug support
	  primarily consists of logs consisting of information related to
	  hardware register access and enabling BUG_ON for certain cases to aid
	  the debugging.
+1 −0
Original line number Diff line number Diff line
@@ -17,3 +17,4 @@ obj-$(CONFIG_MSM_BOOT_STATS) += boot_stats.o
obj-$(CONFIG_MSM_CORE_HANG_DETECT) += core_hang_detect.o
obj-$(CONFIG_MSM_GLADIATOR_HANG_DETECT) += gladiator_hang_detect.o
obj-$(CONFIG_QCOM_SECURE_BUFFER) += secure_buffer.o
obj-$(CONFIG_ICNSS) += icnss.o wlan_firmware_service_v01.o icnss_utils.o
+4708 −0

File added.

Preview size limit exceeded, changes collapsed.

+154 −0
Original line number Diff line number Diff line
/* Copyright (c) 2016-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/slab.h>
#include <soc/qcom/icnss.h>

#define ICNSS_MAX_CH_NUM 45

static DEFINE_MUTEX(unsafe_channel_list_lock);
static DEFINE_SPINLOCK(dfs_nol_info_lock);
static int driver_load_cnt;
static enum cnss_cc_src icnss_cc_source = CNSS_SOURCE_CORE;

static struct icnss_unsafe_channel_list {
	u16 unsafe_ch_count;
	u16 unsafe_ch_list[ICNSS_MAX_CH_NUM];
} unsafe_channel_list;

static struct icnss_dfs_nol_info {
	void *dfs_nol_info;
	u16 dfs_nol_info_len;
} dfs_nol_info;

int icnss_set_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 ch_count)
{
	mutex_lock(&unsafe_channel_list_lock);
	if ((!unsafe_ch_list) || (ch_count > ICNSS_MAX_CH_NUM)) {
		mutex_unlock(&unsafe_channel_list_lock);
		return -EINVAL;
	}

	unsafe_channel_list.unsafe_ch_count = ch_count;

	if (ch_count != 0) {
		memcpy(
		       (char *)unsafe_channel_list.unsafe_ch_list,
		       (char *)unsafe_ch_list, ch_count * sizeof(u16));
	}
	mutex_unlock(&unsafe_channel_list_lock);

	return 0;
}
EXPORT_SYMBOL(icnss_set_wlan_unsafe_channel);

int icnss_get_wlan_unsafe_channel(u16 *unsafe_ch_list,
				  u16 *ch_count, u16 buf_len)
{
	mutex_lock(&unsafe_channel_list_lock);
	if (!unsafe_ch_list || !ch_count) {
		mutex_unlock(&unsafe_channel_list_lock);
		return -EINVAL;
	}

	if (buf_len < (unsafe_channel_list.unsafe_ch_count * sizeof(u16))) {
		mutex_unlock(&unsafe_channel_list_lock);
		return -ENOMEM;
	}

	*ch_count = unsafe_channel_list.unsafe_ch_count;
	memcpy(
		(char *)unsafe_ch_list,
		(char *)unsafe_channel_list.unsafe_ch_list,
		unsafe_channel_list.unsafe_ch_count * sizeof(u16));
	mutex_unlock(&unsafe_channel_list_lock);

	return 0;
}
EXPORT_SYMBOL(icnss_get_wlan_unsafe_channel);

int icnss_wlan_set_dfs_nol(const void *info, u16 info_len)
{
	void *temp;
	void *old_nol_info;
	struct icnss_dfs_nol_info *dfs_info;

	if (!info || !info_len)
		return -EINVAL;

	temp = kmalloc(info_len, GFP_ATOMIC);
	if (!temp)
		return -ENOMEM;

	memcpy(temp, info, info_len);
	spin_lock_bh(&dfs_nol_info_lock);
	dfs_info = &dfs_nol_info;
	old_nol_info = dfs_info->dfs_nol_info;
	dfs_info->dfs_nol_info = temp;
	dfs_info->dfs_nol_info_len = info_len;
	spin_unlock_bh(&dfs_nol_info_lock);
	kfree(old_nol_info);

	return 0;
}
EXPORT_SYMBOL(icnss_wlan_set_dfs_nol);

int icnss_wlan_get_dfs_nol(void *info, u16 info_len)
{
	int len;
	struct icnss_dfs_nol_info *dfs_info;

	if (!info || !info_len)
		return -EINVAL;

	spin_lock_bh(&dfs_nol_info_lock);

	dfs_info = &dfs_nol_info;
	if (dfs_info->dfs_nol_info == NULL ||
	    dfs_info->dfs_nol_info_len == 0) {
		spin_unlock_bh(&dfs_nol_info_lock);
		return -ENOENT;
	}

	len = min(info_len, dfs_info->dfs_nol_info_len);
	memcpy(info, dfs_info->dfs_nol_info, len);
	spin_unlock_bh(&dfs_nol_info_lock);

	return len;
}
EXPORT_SYMBOL(icnss_wlan_get_dfs_nol);

void icnss_increment_driver_load_cnt(void)
{
	++driver_load_cnt;
}
EXPORT_SYMBOL(icnss_increment_driver_load_cnt);

int icnss_get_driver_load_cnt(void)
{
	return driver_load_cnt;
}
EXPORT_SYMBOL(icnss_get_driver_load_cnt);


void icnss_set_cc_source(enum cnss_cc_src cc_source)
{
	icnss_cc_source = cc_source;
}
EXPORT_SYMBOL(icnss_set_cc_source);

enum cnss_cc_src icnss_get_cc_source(void)
{
	return icnss_cc_source;
}
EXPORT_SYMBOL(icnss_get_cc_source);
Loading