icnss2: Add support for direct QMP to communicate with AOP
Add support for direct QMP to communicate with AOP. There are two ways to communicate with AOP: mailbox, and direct QMP, Based on property set in the device tree use either direct QMP or mailbox to send messages to AOP. Change-Id: Iae8302fd2e40181a192a2c9afaebdb807b7cf1c3 CRs-Fixed: 3571108
This commit is contained in:
@@ -4753,7 +4753,7 @@ static int icnss_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
init_completion(&priv->smp2p_soc_wake_wait);
|
init_completion(&priv->smp2p_soc_wake_wait);
|
||||||
icnss_runtime_pm_init(priv);
|
icnss_runtime_pm_init(priv);
|
||||||
icnss_aop_mbox_init(priv);
|
icnss_aop_interface_init(priv);
|
||||||
set_bit(ICNSS_COLD_BOOT_CAL, &priv->state);
|
set_bit(ICNSS_COLD_BOOT_CAL, &priv->state);
|
||||||
priv->bdf_download_support = true;
|
priv->bdf_download_support = true;
|
||||||
register_trace_android_vh_rproc_recovery_set(rproc_restart_level_notifier, NULL);
|
register_trace_android_vh_rproc_recovery_set(rproc_restart_level_notifier, NULL);
|
||||||
@@ -4865,8 +4865,6 @@ static int icnss_remove(struct platform_device *pdev)
|
|||||||
priv->device_id == WCN6450_DEVICE_ID) {
|
priv->device_id == WCN6450_DEVICE_ID) {
|
||||||
icnss_genl_exit();
|
icnss_genl_exit();
|
||||||
icnss_runtime_pm_deinit(priv);
|
icnss_runtime_pm_deinit(priv);
|
||||||
if (!IS_ERR_OR_NULL(priv->mbox_chan))
|
|
||||||
mbox_free_channel(priv->mbox_chan);
|
|
||||||
unregister_trace_android_vh_rproc_recovery_set(rproc_restart_level_notifier, NULL);
|
unregister_trace_android_vh_rproc_recovery_set(rproc_restart_level_notifier, NULL);
|
||||||
complete_all(&priv->smp2p_soc_wake_wait);
|
complete_all(&priv->smp2p_soc_wake_wait);
|
||||||
icnss_destroy_ramdump_device(priv->m3_dump_phyareg);
|
icnss_destroy_ramdump_device(priv->m3_dump_phyareg);
|
||||||
@@ -4876,6 +4874,7 @@ static int icnss_remove(struct platform_device *pdev)
|
|||||||
icnss_destroy_ramdump_device(priv->m3_dump_phyapdmem);
|
icnss_destroy_ramdump_device(priv->m3_dump_phyapdmem);
|
||||||
if (priv->soc_wake_wq)
|
if (priv->soc_wake_wq)
|
||||||
destroy_workqueue(priv->soc_wake_wq);
|
destroy_workqueue(priv->soc_wake_wq);
|
||||||
|
icnss_aop_interface_deinit(priv);
|
||||||
}
|
}
|
||||||
|
|
||||||
class_destroy(priv->icnss_ramdump_class);
|
class_destroy(priv->icnss_ramdump_class);
|
||||||
|
@@ -12,6 +12,10 @@
|
|||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/ipc_logging.h>
|
#include <linux/ipc_logging.h>
|
||||||
#include <linux/power_supply.h>
|
#include <linux/power_supply.h>
|
||||||
|
#if IS_ENABLED(CONFIG_MSM_QMP)
|
||||||
|
#include <linux/mailbox/qmp.h>
|
||||||
|
#include <linux/soc/qcom/qcom_aoss.h>
|
||||||
|
#endif
|
||||||
#ifdef CONFIG_CNSS_OUT_OF_TREE
|
#ifdef CONFIG_CNSS_OUT_OF_TREE
|
||||||
#include "icnss2.h"
|
#include "icnss2.h"
|
||||||
#else
|
#else
|
||||||
@@ -485,6 +489,10 @@ struct icnss_priv {
|
|||||||
bool root_pd_shutdown;
|
bool root_pd_shutdown;
|
||||||
struct mbox_client mbox_client_data;
|
struct mbox_client mbox_client_data;
|
||||||
struct mbox_chan *mbox_chan;
|
struct mbox_chan *mbox_chan;
|
||||||
|
#if IS_ENABLED(CONFIG_MSM_QMP)
|
||||||
|
struct qmp *qmp;
|
||||||
|
#endif
|
||||||
|
bool use_direct_qmp;
|
||||||
u32 wlan_en_delay_ms;
|
u32 wlan_en_delay_ms;
|
||||||
u32 wlan_en_delay_ms_user;
|
u32 wlan_en_delay_ms_user;
|
||||||
struct class *icnss_ramdump_class;
|
struct class *icnss_ramdump_class;
|
||||||
@@ -542,7 +550,8 @@ int icnss_get_iova_ipa(struct icnss_priv *priv, u64 *addr, u64 *size);
|
|||||||
int icnss_update_cpr_info(struct icnss_priv *priv);
|
int icnss_update_cpr_info(struct icnss_priv *priv);
|
||||||
void icnss_add_fw_prefix_name(struct icnss_priv *priv, char *prefix_name,
|
void icnss_add_fw_prefix_name(struct icnss_priv *priv, char *prefix_name,
|
||||||
char *name);
|
char *name);
|
||||||
int icnss_aop_mbox_init(struct icnss_priv *priv);
|
int icnss_aop_interface_init(struct icnss_priv *priv);
|
||||||
|
void icnss_aop_interface_deinit(struct icnss_priv *priv);
|
||||||
void icnss_recovery_timeout_hdlr(struct timer_list *t);
|
void icnss_recovery_timeout_hdlr(struct timer_list *t);
|
||||||
void icnss_wpss_ssr_timeout_hdlr(struct timer_list *t);
|
void icnss_wpss_ssr_timeout_hdlr(struct timer_list *t);
|
||||||
#endif
|
#endif
|
||||||
|
102
icnss2/power.c
102
icnss2/power.c
@@ -5,9 +5,6 @@
|
|||||||
*/
|
*/
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#if IS_ENABLED(CONFIG_MSM_QMP)
|
|
||||||
#include <linux/mailbox/qmp.h>
|
|
||||||
#endif
|
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/pinctrl/consumer.h>
|
#include <linux/pinctrl/consumer.h>
|
||||||
#include <linux/regulator/consumer.h>
|
#include <linux/regulator/consumer.h>
|
||||||
@@ -736,7 +733,18 @@ void icnss_put_resources(struct icnss_priv *priv)
|
|||||||
icnss_put_vreg(priv);
|
icnss_put_vreg(priv);
|
||||||
}
|
}
|
||||||
|
|
||||||
int icnss_aop_mbox_init(struct icnss_priv *priv)
|
|
||||||
|
#if IS_ENABLED(CONFIG_MSM_QMP)
|
||||||
|
/**
|
||||||
|
* icnss_aop_interface_init: Initialize AOP interface: either mbox channel or direct QMP
|
||||||
|
* @priv: Pointer to icnss platform data
|
||||||
|
*
|
||||||
|
* Device tree file should have either mbox or qmp configured, but not both.
|
||||||
|
* Based on device tree configuration setup mbox channel or QMP
|
||||||
|
*
|
||||||
|
* Return: 0 for success, otherwise error code
|
||||||
|
*/
|
||||||
|
int icnss_aop_interface_init(struct icnss_priv *priv)
|
||||||
{
|
{
|
||||||
struct mbox_client *mbox = &priv->mbox_client_data;
|
struct mbox_client *mbox = &priv->mbox_client_data;
|
||||||
struct mbox_chan *chan;
|
struct mbox_chan *chan;
|
||||||
@@ -756,19 +764,50 @@ int icnss_aop_mbox_init(struct icnss_priv *priv)
|
|||||||
mbox->knows_txdone = false;
|
mbox->knows_txdone = false;
|
||||||
|
|
||||||
priv->mbox_chan = NULL;
|
priv->mbox_chan = NULL;
|
||||||
|
priv->qmp = NULL;
|
||||||
|
priv->use_direct_qmp = false;
|
||||||
|
/* First try to get mbox channel, if it fails then try qmp_get
|
||||||
|
* In device tree file there should be either mboxes or qmp,
|
||||||
|
* cannot have both properties at the same time.
|
||||||
|
*/
|
||||||
chan = mbox_request_channel(mbox, 0);
|
chan = mbox_request_channel(mbox, 0);
|
||||||
if (IS_ERR(chan)) {
|
if (IS_ERR(chan)) {
|
||||||
ret = PTR_ERR(chan);
|
ret = PTR_ERR(chan);
|
||||||
icnss_pr_err("Failed to get mbox channel with err %d\n", ret);
|
icnss_pr_dbg("Failed to get mbox channel with err %d\n", ret);
|
||||||
return ret;
|
priv->qmp = qmp_get(&priv->pdev->dev);
|
||||||
|
if (IS_ERR(priv->qmp)) {
|
||||||
|
icnss_pr_err("Failed to get qmp\n");
|
||||||
|
return PTR_ERR(priv->qmp);
|
||||||
|
} else {
|
||||||
|
priv->use_direct_qmp = true;
|
||||||
|
icnss_pr_dbg("QMP initialized\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
priv->mbox_chan = chan;
|
||||||
|
icnss_pr_dbg("Mbox channel initialized\n");
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cnss_aop_interface_deinit: Cleanup AOP interface
|
||||||
|
* @priv: Pointer to icnss platform data
|
||||||
|
*
|
||||||
|
* Cleanup mbox channel or QMP whichever was configured during initialization.
|
||||||
|
*
|
||||||
|
* Return: None
|
||||||
|
*/
|
||||||
|
void icnss_aop_interface_deinit(struct icnss_priv *priv)
|
||||||
|
{
|
||||||
|
if (!IS_ERR_OR_NULL(priv->mbox_chan))
|
||||||
|
mbox_free_channel(priv->mbox_chan);
|
||||||
|
|
||||||
|
if (!IS_ERR_OR_NULL(priv->qmp)) {
|
||||||
|
qmp_put(priv->qmp);
|
||||||
|
priv->use_direct_qmp = false;
|
||||||
}
|
}
|
||||||
priv->mbox_chan = chan;
|
|
||||||
|
|
||||||
icnss_pr_dbg("Mbox channel initialized\n");
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_MSM_QMP)
|
|
||||||
static int icnss_aop_set_vreg_param(struct icnss_priv *priv,
|
static int icnss_aop_set_vreg_param(struct icnss_priv *priv,
|
||||||
const char *vreg_name,
|
const char *vreg_name,
|
||||||
enum icnss_vreg_param param,
|
enum icnss_vreg_param param,
|
||||||
@@ -786,21 +825,38 @@ static int icnss_aop_set_vreg_param(struct icnss_priv *priv,
|
|||||||
snprintf(mbox_msg, ICNSS_MBOX_MSG_MAX_LEN,
|
snprintf(mbox_msg, ICNSS_MBOX_MSG_MAX_LEN,
|
||||||
"{class: wlan_pdc, res: %s.%s, %s: %d}", vreg_name,
|
"{class: wlan_pdc, res: %s.%s, %s: %d}", vreg_name,
|
||||||
vreg_param_str[param], tcs_seq_str[seq], val);
|
vreg_param_str[param], tcs_seq_str[seq], val);
|
||||||
|
if (priv->use_direct_qmp) {
|
||||||
|
icnss_pr_dbg("Sending AOP QMP msg: %s\n", mbox_msg);
|
||||||
|
ret = qmp_send(priv->qmp, mbox_msg, ICNSS_MBOX_MSG_MAX_LEN);
|
||||||
|
if (ret < 0)
|
||||||
|
icnss_pr_err("Failed to send AOP QMP msg: %s\n", mbox_msg);
|
||||||
|
else
|
||||||
|
ret = 0;
|
||||||
|
} else {
|
||||||
|
icnss_pr_dbg("Sending AOP Mbox msg: %s\n", mbox_msg);
|
||||||
|
pkt.size = ICNSS_MBOX_MSG_MAX_LEN;
|
||||||
|
pkt.data = mbox_msg;
|
||||||
|
|
||||||
icnss_pr_dbg("Sending AOP Mbox msg: %s\n", mbox_msg);
|
ret = mbox_send_message(priv->mbox_chan, &pkt);
|
||||||
pkt.size = ICNSS_MBOX_MSG_MAX_LEN;
|
if (ret < 0)
|
||||||
pkt.data = mbox_msg;
|
icnss_pr_err("Failed to send AOP mbox msg: %s,ret: %d\n",
|
||||||
|
mbox_msg, ret);
|
||||||
ret = mbox_send_message(priv->mbox_chan, &pkt);
|
else
|
||||||
if (ret < 0)
|
ret = 0;
|
||||||
icnss_pr_err("Failed to send AOP mbox msg: %s,ret: %d\n",
|
}
|
||||||
mbox_msg, ret);
|
|
||||||
else
|
|
||||||
ret = 0;
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
int icnss_aop_interface_init(struct icnss_priv *priv)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void icnss_aop_interface_deinit(struct icnss_priv *priv)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
static int icnss_aop_set_vreg_param(struct icnss_priv *priv,
|
static int icnss_aop_set_vreg_param(struct icnss_priv *priv,
|
||||||
const char *vreg_name,
|
const char *vreg_name,
|
||||||
enum icnss_vreg_param param,
|
enum icnss_vreg_param param,
|
||||||
@@ -814,8 +870,8 @@ int icnss_update_cpr_info(struct icnss_priv *priv)
|
|||||||
{
|
{
|
||||||
struct icnss_cpr_info *cpr_info = &priv->cpr_info;
|
struct icnss_cpr_info *cpr_info = &priv->cpr_info;
|
||||||
|
|
||||||
if (!cpr_info->vreg_ol_cpr || !priv->mbox_chan) {
|
if (!cpr_info->vreg_ol_cpr || (!priv->mbox_chan && !priv->qmp)) {
|
||||||
icnss_pr_dbg("Mbox channel / OL CPR Vreg not configured\n");
|
icnss_pr_dbg("Mbox channel / QMP / OL CPR Vreg not configured\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user