ASoC: qcom: qdsp6v2: configure apr using the device tree

APR services can be implemented on the adsp block which may be present
on modem/lpass depending on the msm architecture.
This change will enable the apr driver to read from device tree,
the hardware block on which APR services are implemented and expose them
to other modules

Change-Id: I967c29a6c60df600b0b5c9e0de58a5491c31a478
Signed-off-by: Aravind Kumar <akumark@codeaurora.org>
This commit is contained in:
Aravind Kumar 2015-03-07 02:53:00 +05:30 committed by Gerrit - the friendly Code Review server
parent 68345d49fd
commit 09fdf383ee
20 changed files with 345 additions and 53 deletions

View file

@ -1,5 +1,17 @@
Qualcomm audio devices for ALSA sound SoC
* msmapr-audio
Required properties:
- compatible : "qcom,msmapr-audio"
- qcom,apr-dest-type : Name of hardware module to which apr packets
are routed."MDSP" indicates that apr module is in modem
"ADSP" indicates that apr module is in adsp.
"Dynamic" indicates using service registry to discover
services.
* msm-pcm
Required properties:

View file

@ -5233,6 +5233,11 @@
asoc-codec-names = "msm-stub-codec.1";
};
qcom,msmapr-audio {
compatible = "qcom,msmapr-audio";
qcom,apr-dest-type = "ADSP";
};
qcom,msm-adsp-loader {
compatible = "qcom,adsp-loader";
qcom,adsp-state = <0>;

View file

@ -1067,6 +1067,11 @@
qcom,adsp-state = <0>;
};
qcom,msmapr-audio {
compatible = "qcom,msmapr-audio";
qcom,apr-dest-type = "ADSP";
};
pcm0: qcom,msm-pcm {
compatible = "qcom,msm-pcm-dsp";
qcom,msm-pcm-dsp-id = <0>;

View file

@ -517,6 +517,11 @@
qcom,tapan-codec-9302;
};
qcom,msmapr-audio {
compatible = "qcom,msmapr-audio";
qcom,apr-dest-type = "ADSP";
};
qcom,msm-pcm {
compatible = "qcom,msm-pcm-dsp";
qcom,msm-pcm-dsp-id = <0>;

View file

@ -759,6 +759,11 @@
qcom,model = "msm8x10-snd-card";
};
qcom,msmapr-audio {
compatible = "qcom,msmapr-audio";
qcom,apr-dest-type = "ADSP";
};
qcom,msm-pcm {
compatible = "qcom,msm-pcm-dsp";
qcom,msm-pcm-dsp-id = <0>;

View file

@ -1505,6 +1505,11 @@
qcom,proc-img-to-load = "modem";
};
qcom,msmapr-audio {
compatible = "qcom,msmapr-audio";
qcom,apr-dest-type = "MDSP";
};
qcom,avtimer@770600c {
compatible = "qcom,avtimer";
reg = <0x0770600C 0x4>,

View file

@ -672,6 +672,11 @@
qcom,proc-img-to-load = "modem";
};
qcom,msmapr-audio {
compatible = "qcom,msmapr-audio";
qcom,apr-dest-type = "MDSP";
};
qcom_crypto: qcrypto@720000 {
compatible = "qcom,qcrypto";
reg = <0x720000 0x20000>,

View file

@ -663,6 +663,11 @@
qcom,proc-img-to-load = "modem";
};
qcom,msmapr-audio {
compatible = "qcom,msmapr-audio";
qcom,apr-dest-type = "MDSP";
};
qcom_crypto: qcrypto@720000 {
compatible = "qcom,qcrypto";
reg = <0x720000 0x20000>,

View file

@ -1674,6 +1674,11 @@
qcom,adsp-state = <0>;
};
qcom,msmapr-audio {
compatible = "qcom,msmapr-audio";
qcom,apr-dest-type = "ADSP";
};
qcom,msm-audio-ion {
compatible = "qcom,msm-audio-ion";
};

View file

@ -1429,6 +1429,11 @@
qcom,adsp-state = <0>;
};
qcom,msmapr-audio {
compatible = "qcom,msmapr-audio";
qcom,apr-dest-type = "ADSP";
};
qcom,msm-audio-ion {
compatible = "qcom,msm-audio-ion";
};

View file

@ -2522,6 +2522,11 @@
qcom,master-id = <86>;
};
qcom,msmapr-audio {
compatible = "qcom,msmapr-audio";
qcom,apr-dest-type = "ADSP";
};
sound {
compatible = "qcom,msm8994-asoc-snd";
qcom,model = "msm8994-tomtom-snd-card";

View file

@ -99,7 +99,7 @@ config ARCH_MSM8909
select ARM_TICKET_LOCKS
select ARM_HAS_SG_CHAIN
select ARCH_WANT_KMAP_ATOMIC_FLUSH
select MSM_QDSP6_APRV3
select MSM_QDSP6_APRV2
select MSM_QDSP6V2_CODECS
select MSM_AUDIO_QDSP6V2 if SND_SOC
select CPU_FREQ_MSM
@ -142,7 +142,6 @@ config ARCH_MSM8916
select MSM_BIMC_BWMON
select ARMBW_HWMON
select MSM_RPM_SMD
select MSM_QDSP6_APRV3
select MSM_QDSP6V2_CODECS
select MSM_AUDIO_QDSP6V2 if SND_SOC
select ARM_HAS_SG_CHAIN
@ -221,7 +220,6 @@ config ARCH_MDM9630
select PINCTRL
select PINCTRL_MSM_TLMM
select MSM_IRQ
select MSM_QDSP6_APRV2
select MSM_QDSP6V2_CODECS
select MSM_AUDIO_QDSP6V2 if SND_SOC
@ -244,7 +242,7 @@ config ARCH_MDM9640
select PCI
select MSM_IRQ
select MSM_JTAG_MM if CORESIGHT_ETM
select MSM_QDSP6_APRV3
select MSM_QDSP6_APRV2
select MSM_QDSP6V2_CODECS
select MSM_AUDIO_QDSP6V2 if SND_SOC
select MSM_CLK_CONTROLLER_V2

View file

@ -130,7 +130,7 @@ config KLM
config MSM_AVTIMER
tristate "Avtimer Driver"
depends on MSM_QDSP6_APRV2 || MSM_QDSP6_APRV3
depends on MSM_QDSP6_APRV2
help
This driver gets the Q6 out of power collapsed state and
exposes ioctl control to read avtimer tick.

View file

@ -310,19 +310,10 @@ config MSM_QDSP6_APRV2
used by audio driver to configure QDSP6's
ASM, ADM and AFE.
config MSM_QDSP6_APRV3
bool "Audio QDSP6 APRv3 support"
depends on MSM_SMD
help
Enable APRv2 IPC protocol support between
application processor and QDSP6. APR is
used by audio driver to configure QDSP6v2's
ASM, ADM and AFE.
config MSM_ADSP_LOADER
tristate "ADSP loader support"
select SND_SOC_MSM_APRV2_INTF
depends on MSM_QDSP6_APRV2 || MSM_QDSP6_APRV3
depends on MSM_QDSP6_APRV2
help
Enable ADSP image loader.
The ADSP loader brings ADSP out of reset

View file

@ -1,4 +1,3 @@
obj-$(CONFIG_MSM_QDSP6_APRV2) += apr.o apr_v2.o apr_tal.o voice_svc.o
obj-$(CONFIG_MSM_QDSP6_APRV3) += apr.o apr_v3.o apr_tal.o voice_svc.o
obj-$(CONFIG_MSM_QDSP6_APRV2) += apr.o apr_v2.o apr_v3.o apr_tal.o voice_svc.o
obj-$(CONFIG_SND_SOC_MSM_QDSP6V2_INTF) += msm_audio_ion.o
obj-$(CONFIG_MSM_ADSP_LOADER) += adsp-loader.o

View file

@ -26,6 +26,7 @@
#include <linux/sysfs.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <soc/qcom/subsystem_restart.h>
#include <soc/qcom/subsystem_notif.h>
#include <soc/qcom/scm.h>
@ -177,6 +178,25 @@ static struct apr_svc_table svc_tbl_voice[] = {
},
};
static struct apr_func_dsp apr_dsp_func;
static const char *apr_invalid = "invalid";
const char *apr_get_adsp_subsys_name(void)
{
if (apr_dsp_func.apr_get_adsp_subsys_name)
return apr_dsp_func.apr_get_adsp_subsys_name();
else
return apr_invalid;
}
enum apr_subsys_state apr_get_adsp_state(void)
{
if (apr_dsp_func.apr_get_adsp_state)
return apr_dsp_func.apr_get_adsp_state();
else
return APR_SUBSYS_DOWN;
}
enum apr_subsys_state apr_get_modem_state(void)
{
return atomic_read(&q6.modem_state);
@ -520,7 +540,7 @@ void apr_cb_func(void *buf, int len, void *priv)
}
src = apr_get_data_src(hdr);
if (src == APR_DEST_MAX)
if (src >= APR_DEST_MAX)
return;
pr_debug("src =%d clnt = %d\n", src, clnt);
@ -840,11 +860,134 @@ static struct notifier_block panic_nb = {
.notifier_call = panic_handler,
};
static int __init apr_init(void)
int apr_set_subsys_state(void)
{
int ret = 0;
if (apr_dsp_func.apr_set_subsys_state) {
apr_dsp_func.apr_set_subsys_state();
} else {
pr_err("%s: invalid function ptr\n", __func__);
ret = -EINVAL;
}
return ret;
}
uint16_t apr_get_data_src(struct apr_hdr *hdr)
{
u16 data_src = APR_DEST_MAX;
if (!hdr) {
pr_err("%s: Invalid param\n", __func__);
goto err;
}
if (apr_dsp_func.apr_get_data_src)
data_src = apr_dsp_func.apr_get_data_src(hdr);
else
pr_err("%s: Invalid function ptr\n", __func__);
err:
return data_src;
}
int apr_get_dest_id(char *dest)
{
int dest_id = APR_DEST_MAX;
if (!dest) {
pr_err("%s: Invalid params\n", __func__);
goto err;
}
if (apr_dsp_func.apr_get_dest_id)
dest_id = apr_dsp_func.apr_get_dest_id(dest);
else
pr_err("%s: Invalid func ptr\n", __func__);
err:
return dest_id;
}
int subsys_notif_register(struct notifier_block *mod_notif,
struct notifier_block *lp_notif)
{
int ret = 0;
if (apr_dsp_func.subsys_notif_register) {
apr_dsp_func.subsys_notif_register(mod_notif, lp_notif);
} else {
pr_err("%s: Invalid func ptr\n", __func__);
ret = -EINVAL;
}
return ret;
}
bool apr_register_voice_svc(void)
{
bool voice_svc = false;
if (apr_dsp_func.apr_register_voice_svc)
voice_svc = apr_dsp_func.apr_register_voice_svc();
else
pr_err("%s: invalid func ptr\n", __func__);
return voice_svc;
}
uint16_t apr_get_reset_domain(uint16_t proc)
{
u16 reset_domain = APR_DEST_MAX;
if (apr_dsp_func.apr_get_reset_domain)
reset_domain = apr_dsp_func.apr_get_reset_domain(proc);
else
pr_err("%s: invalid func ptr\n", __func__);
return reset_domain;
}
static void apr_cleanup(void)
{
int i, j, k;
memset(&apr_dsp_func, 0, sizeof(apr_dsp_func));
if (apr_reset_workqueue)
destroy_workqueue(apr_reset_workqueue);
mutex_destroy(&q6.lock);
for (i = 0; i < APR_DEST_MAX; i++) {
for (j = 0; j < APR_CLIENT_MAX; j++) {
mutex_destroy(&client[i][j].m_lock);
for (k = 0; k < APR_SVC_MAX; k++)
mutex_destroy(&client[i][j].svc[k].m_lock);
}
}
}
for (i = 0; i < APR_DEST_MAX; i++)
static int apr_probe(struct platform_device *pdev)
{
int i, j, k, ret;
const char *dsp_type = NULL;
ret = of_property_read_string(pdev->dev.of_node,
"qcom,apr-dest-type",
&dsp_type);
if (ret || !dsp_type) {
dev_err(&pdev->dev, "%s: Looking up %s property failed\n",
__func__, "qcom,apr-dest-type");
return -EINVAL;
}
if (!strcmp("ADSP", dsp_type)) {
dev_info(&pdev->dev, "%s: destination is ADSP\n", __func__);
ret = apr_get_v2_ops(&apr_dsp_func);
if (ret) {
dev_err(&pdev->dev, "%s error get adsp ops %d\n",
__func__, ret);
return ret;
}
} else if (!strcmp("MDSP", dsp_type)) {
dev_info(&pdev->dev, "%s: destination is modem\n", __func__);
ret = apr_get_v3_ops(&apr_dsp_func);
if (ret) {
dev_err(&pdev->dev, "%s: error get mdsp ops %d\n",
__func__, ret);
return ret;
}
} else if (!strcmp("Dynamic", dsp_type)) {
dev_info(&pdev->dev, "%s: using service registry\n", __func__);
} else {
dev_err(&pdev->dev, "%s: Invalid destination type\n",
__func__);
return -EINVAL;
}
for (i = 0; i < APR_DEST_MAX; i++) {
for (j = 0; j < APR_CLIENT_MAX; j++) {
mutex_init(&client[i][j].m_lock);
for (k = 0; k < APR_SVC_MAX; k++) {
@ -852,23 +995,51 @@ static int __init apr_init(void)
spin_lock_init(&client[i][j].svc[k].w_lock);
}
}
apr_set_subsys_state();
}
mutex_init(&q6.lock);
apr_reset_workqueue = create_singlethread_workqueue("apr_driver");
if (!apr_reset_workqueue)
if (!apr_reset_workqueue) {
pr_err("%s: work queue creation failed\n", __func__);
apr_cleanup();
return -ENOMEM;
}
ret = apr_set_subsys_state();
if (ret)
dev_err(&pdev->dev, "%s: apr_set_subsys_state failed ret = %d\n",
__func__, ret);
atomic_notifier_chain_register(&panic_notifier_list, &panic_nb);
return 0;
}
device_initcall(apr_init);
static int __init apr_late_init(void)
{
int ret = 0;
init_waitqueue_head(&dsp_wait);
init_waitqueue_head(&modem_wait);
subsys_notif_register(&mnb, &lnb);
return ret;
ret = subsys_notif_register(&mnb, &lnb);
if (ret) {
dev_err(&pdev->dev, "%s: subsys_notif_register failed ret = %d\n",
__func__, ret);
}
return 0;
}
late_initcall(apr_late_init);
static int apr_remove(struct platform_device *pdev)
{
apr_cleanup();
return 0;
}
static const struct of_device_id apr_machine_of_match[] = {
{ .compatible = "qcom,msmapr-audio", },
{},
};
static struct platform_driver apr_driver = {
.probe = apr_probe,
.remove = apr_remove,
.driver = {
.name = "apr",
.owner = THIS_MODULE,
.of_match_table = apr_machine_of_match,
}
};
module_platform_driver(apr_driver);
MODULE_DESCRIPTION("APR DRIVER");
MODULE_LICENSE("GPL v2");
MODULE_DEVICE_TABLE(of, apr_machine_of_match);

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012-2014 The Linux Foundation. All rights reserved.
* Copyright (c) 2012-2015 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
@ -21,18 +21,23 @@
static const char *lpass_subsys_name = "adsp";
void apr_set_subsys_state(void)
static void apr_set_subsys_state_v2(void)
{
apr_set_q6_state(APR_SUBSYS_DOWN);
apr_set_modem_state(APR_SUBSYS_UP);
}
enum apr_subsys_state apr_get_q6_state_v2(void)
{
return apr_get_q6_state();
}
const char *apr_get_lpass_subsys_name(void)
{
return lpass_subsys_name;
}
uint16_t apr_get_data_src(struct apr_hdr *hdr)
static uint16_t apr_get_data_src_v2(struct apr_hdr *hdr)
{
if (hdr->src_domain == APR_DOMAIN_MODEM)
return APR_DEST_MODEM;
@ -44,7 +49,7 @@ uint16_t apr_get_data_src(struct apr_hdr *hdr)
}
}
int apr_get_dest_id(char *dest)
static int apr_get_dest_id_v2(char *dest)
{
if (!strcmp(dest, "ADSP"))
return APR_DEST_QDSP6;
@ -52,19 +57,38 @@ int apr_get_dest_id(char *dest)
return APR_DEST_MODEM;
}
void subsys_notif_register(struct notifier_block *mod_notif,
static void subsys_notif_register_v2(struct notifier_block *mod_notif,
struct notifier_block *lp_notif)
{
subsys_notif_register_notifier("modem", mod_notif);
subsys_notif_register_notifier(apr_get_lpass_subsys_name(), lp_notif);
}
uint16_t apr_get_reset_domain(uint16_t proc)
static uint16_t apr_get_reset_domain_v2(uint16_t proc)
{
return proc;
}
bool apr_register_voice_svc()
static bool apr_register_voice_svc_v2(void)
{
return true;
}
int apr_get_v2_ops(struct apr_func_dsp *ops)
{
int ret = 0;
if (ops) {
ops->apr_get_data_src = apr_get_data_src_v2;
ops->apr_get_dest_id = apr_get_dest_id_v2;
ops->apr_get_reset_domain = apr_get_reset_domain_v2;
ops->apr_register_voice_svc = apr_register_voice_svc_v2;
ops->apr_set_subsys_state = apr_set_subsys_state_v2;
ops->apr_get_adsp_state = apr_get_q6_state_v2;
ops->apr_get_adsp_subsys_name = apr_get_lpass_subsys_name;
ops->subsys_notif_register = subsys_notif_register_v2;
} else {
pr_err("%s: Invalid params\n", __func__);
ret = -EINVAL;
}
return ret;
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
* Copyright (c) 2013-2015, 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
@ -20,34 +20,64 @@
#include <linux/qdsp6v2/dsp_debug.h>
#define DEST_ID APR_DEST_MODEM
static const char *modem_subsys_name = "modem";
void apr_set_subsys_state(void)
static void apr_set_subsys_state_v3(void)
{
apr_set_modem_state(APR_SUBSYS_DOWN);
}
uint16_t apr_get_data_src(struct apr_hdr *hdr)
enum apr_subsys_state apr_get_modem_state_v3(void)
{
return apr_get_modem_state();
}
const char *apr_get_modem_subsys_name(void)
{
return modem_subsys_name;
}
static uint16_t apr_get_data_src_v3(struct apr_hdr *hdr)
{
return DEST_ID;
}
int apr_get_dest_id(char *dest)
static int apr_get_dest_id_v3(char *dest)
{
return DEST_ID;
}
void subsys_notif_register(struct notifier_block *mod_notif,
static void subsys_notif_register_v3(struct notifier_block *mod_notif,
struct notifier_block *lp_notif)
{
subsys_notif_register_notifier("modem", mod_notif);
}
uint16_t apr_get_reset_domain(uint16_t proc)
static uint16_t apr_get_reset_domain_v3(uint16_t proc)
{
return APR_DEST_QDSP6;
}
bool apr_register_voice_svc()
static bool apr_register_voice_svc_v3(void)
{
return false;
}
int apr_get_v3_ops(struct apr_func_dsp *ops)
{
int ret = 0;
if (ops) {
ops->apr_get_data_src = apr_get_data_src_v3;
ops->apr_get_dest_id = apr_get_dest_id_v3;
ops->apr_get_reset_domain = apr_get_reset_domain_v3;
ops->apr_register_voice_svc = apr_register_voice_svc_v3;
ops->apr_set_subsys_state = apr_set_subsys_state_v3;
ops->apr_get_adsp_state = apr_get_modem_state_v3;
ops->apr_get_adsp_subsys_name = apr_get_modem_subsys_name;
ops->subsys_notif_register = subsys_notif_register_v3;
} else {
pr_err("%s: Invalid params\n", __func__);
ret = -EINVAL;
}
return ret;
}

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2010-2014, The Linux Foundation. All rights reserved.
/* Copyright (c) 2010-2015, 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
@ -147,6 +147,18 @@ struct apr_client {
struct apr_svc svc[APR_SVC_MAX];
};
struct apr_func_dsp {
void (*apr_set_subsys_state)(void);
enum apr_subsys_state (*apr_get_adsp_state)(void);
const char * (*apr_get_adsp_subsys_name)(void);
u16 (*apr_get_data_src)(struct apr_hdr *hdr);
int (*apr_get_dest_id)(char *dest);
void (*subsys_notif_register)(struct notifier_block *mod_notif,
struct notifier_block *lp_notif);
u16 (*apr_get_reset_domain)(u16 proc);
bool (*apr_register_voice_svc)(void);
};
int apr_load_adsp_image(void);
struct apr_client *apr_get_client(int dest_id, int client_id);
int apr_wait_for_device_up(int dest_id);
@ -161,7 +173,7 @@ inline int apr_fill_hdr(void *handle, uint32_t *buf, uint16_t src_port,
int apr_send_pkt(void *handle, uint32_t *buf);
int apr_deregister(void *handle);
void subsys_notif_register(struct notifier_block *mod_notif,
int subsys_notif_register(struct notifier_block *mod_notif,
struct notifier_block *lp_notif);
int apr_get_dest_id(char *dest);
uint16_t apr_get_data_src(struct apr_hdr *hdr);
@ -172,8 +184,12 @@ enum apr_subsys_state apr_get_modem_state(void);
void apr_set_modem_state(enum apr_subsys_state state);
enum apr_subsys_state apr_get_q6_state(void);
int apr_set_q6_state(enum apr_subsys_state state);
void apr_set_subsys_state(void);
int apr_set_subsys_state(void);
enum apr_subsys_state apr_get_adsp_state(void);
const char *apr_get_lpass_subsys_name(void);
bool apr_register_voice_svc(void);
uint16_t apr_get_reset_domain(uint16_t proc);
int apr_get_v2_ops(struct apr_func_dsp *ops);
int apr_get_v3_ops(struct apr_func_dsp *ops);
const char *apr_get_adsp_subsys_name(void);
#endif

View file

@ -261,7 +261,7 @@ config SND_SOC_MSM8X16
select DTS_SRS_TM
select DOLBY_DAP
select DOLBY_DS2
select MSM_QDSP6_APRV3
select MSM_QDSP6_APRV2
select MSM_QDSP6V2_CODECS
select SND_SOC_CPE
select SND_HWDEP
@ -285,7 +285,7 @@ config SND_SOC_MSM8909
select QTI_PP
select DTS_SRS_TM
select DOLBY_DAP
select MSM_QDSP6_APRV3
select MSM_QDSP6_APRV2
select MSM_QDSP6V2_CODECS
select SND_HWDEP
select DOLBY_DS2
@ -304,6 +304,7 @@ config SND_SOC_MDM9630
select SND_SOC_WCD9320
select SND_SOC_MSM_HOSTLESS_PCM
select SND_DYNAMIC_MINORS
select MSM_QDSP6_APRV2
help
To add support for SoC audio on MDM9630 boards.
@ -340,7 +341,7 @@ config SND_SOC_MDM9640
select SND_SOC_WCD9330
select SND_SOC_MSM_HOSTLESS_PCM
select SND_DYNAMIC_MINORS
select MSM_QDSP6_APRV3
select MSM_QDSP6_APRV2
select MSM_QDSP6V2_CODECS
select SND_HWDEP
help