msm: APRv2: Add APRv2 support
The MSM platforms that turn off LPASS core by default have to bring up LPASS core prior to talk with it. Current implementation is during bootup, before the slimbus slave device is up, the slimbus master on apps would try to configure the slimbus hardware. Add APRv2 driver to let adsp loader to bring up LPASS core on and make slimbus driver to configure hardware after bringing up LPASS core. Change-Id: I9c45e229e6e4c5c142d8a327509d66d9662b52d4 Signed-off-by: Joonwoo Park <joonwoop@codeaurora.org>
This commit is contained in:
parent
f2b1901295
commit
b1aa9c2941
|
@ -256,7 +256,7 @@ config ARCH_MSM8974
|
|||
select MSM_RPM_SMD
|
||||
select REGULATOR
|
||||
select HAVE_ARM_ARCH_TIMER
|
||||
select MSM_QDSP6_APR
|
||||
select MSM_QDSP6_APRV2
|
||||
select MSM_QDSP6V2_CODECS
|
||||
select MSM_AUDIO_QDSP6V2 if SND_SOC
|
||||
select MSM_RPM_REGULATOR_SMD
|
||||
|
@ -2211,6 +2211,16 @@ config MSM_QDSP6_APR
|
|||
used by audio driver to configure QDSP6's
|
||||
ASM, ADM and AFE.
|
||||
|
||||
config MSM_QDSP6_APRV2
|
||||
bool "Audio QDSP6 APRv2 support"
|
||||
depends on MSM_SMD
|
||||
default n
|
||||
help
|
||||
Enable APRv2 IPC protocol support between
|
||||
application processor and QDSP6. APR is
|
||||
used by audio driver to configure QDSP6's
|
||||
ASM, ADM and AFE.
|
||||
|
||||
config MSM_QDSP6_CODECS
|
||||
bool "Audio Codecs on QDSP6 APR "
|
||||
depends on MSM_SMD
|
||||
|
|
|
@ -13,13 +13,18 @@
|
|||
#ifndef __APR_H_
|
||||
#define __APR_H_
|
||||
|
||||
#define APR_Q6_NOIMG 0
|
||||
#define APR_Q6_LOADING 1
|
||||
#define APR_Q6_LOADED 2
|
||||
#include <linux/mutex.h>
|
||||
|
||||
enum apr_subsys_state {
|
||||
APR_SUBSYS_DOWN,
|
||||
APR_SUBSYS_UP,
|
||||
APR_SUBSYS_LOADED,
|
||||
};
|
||||
|
||||
struct apr_q6 {
|
||||
void *pil;
|
||||
uint32_t state;
|
||||
atomic_t q6_state;
|
||||
atomic_t modem_state;
|
||||
struct mutex lock;
|
||||
};
|
||||
|
||||
|
@ -138,6 +143,12 @@ struct apr_client {
|
|||
struct apr_svc svc[APR_SVC_MAX];
|
||||
};
|
||||
|
||||
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);
|
||||
int apr_get_svc(const char *svc_name, int dest_id, int *client_id,
|
||||
int *svc_idx, int *svc_id);
|
||||
void apr_cb_func(void *buf, int len, void *priv);
|
||||
struct apr_svc *apr_register(char *dest, char *svc_name, apr_fn svc_fn,
|
||||
uint32_t src_port, void *priv);
|
||||
inline int apr_fill_hdr(void *handle, uint32_t *buf, uint16_t src_port,
|
||||
|
@ -149,4 +160,9 @@ int apr_deregister(void *handle);
|
|||
void change_q6_state(int state);
|
||||
void q6audio_dsp_not_responding(void);
|
||||
void apr_reset(void *handle);
|
||||
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);
|
||||
#endif
|
||||
|
|
|
@ -10,7 +10,8 @@ obj-y += snddev_hdmi.o
|
|||
obj-y += audio_mvs.o
|
||||
obj-$(CONFIG_FB_MSM_HDMI_MSM_PANEL) += lpa_if_hdmi.o
|
||||
endif
|
||||
obj-$(CONFIG_MSM_QDSP6_APR) += apr.o apr_tal.o q6core.o dsp_debug.o
|
||||
obj-$(CONFIG_MSM_QDSP6_APR) += apr.o apr_v1.o apr_tal.o q6core.o dsp_debug.o
|
||||
obj-$(CONFIG_MSM_QDSP6_APRV2) += apr.o apr_v2.o apr_tal.o q6core.o dsp_debug.o
|
||||
obj-y += audio_acdb.o
|
||||
ifdef CONFIG_ARCH_MSM9615
|
||||
obj-y += rtac.o
|
||||
|
@ -23,4 +24,5 @@ obj-$(CONFIG_MSM_QDSP6V2_CODECS) += aac_in.o qcelp_in.o evrc_in.o amrnb_in.o aud
|
|||
obj-$(CONFIG_MSM_QDSP6V2_CODECS) += audio_wma.o audio_wmapro.o audio_aac.o audio_multi_aac.o audio_utils_aio.o
|
||||
obj-$(CONFIG_MSM_QDSP6V2_CODECS) += rtac_v2.o q6audio_v2.o q6audio_v2_aio.o
|
||||
obj-$(CONFIG_MSM_QDSP6V2_CODECS) += audio_mp3.o audio_amrnb.o audio_amrwb.o audio_evrc.o audio_qcelp.o amrwb_in.o
|
||||
obj-$(CONFIG_MSM_ADSP_LOADER) += adsp-loader.o
|
||||
obj-$(CONFIG_MSM_ULTRASOUND) += ultrasound/
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/wait.h>
|
||||
|
@ -36,13 +35,11 @@
|
|||
#include <mach/subsystem_notif.h>
|
||||
#include <mach/subsystem_restart.h>
|
||||
|
||||
struct apr_q6 q6;
|
||||
struct apr_client client[APR_DEST_MAX][APR_CLIENT_MAX];
|
||||
static atomic_t dsp_state;
|
||||
static atomic_t modem_state;
|
||||
static struct apr_q6 q6;
|
||||
static struct apr_client client[APR_DEST_MAX][APR_CLIENT_MAX];
|
||||
|
||||
static wait_queue_head_t dsp_wait;
|
||||
static wait_queue_head_t modem_wait;
|
||||
static wait_queue_head_t dsp_wait;
|
||||
static wait_queue_head_t modem_wait;
|
||||
/* Subsystem restart: QDSP6 data, functions */
|
||||
static struct workqueue_struct *apr_reset_workqueue;
|
||||
static void apr_reset_deregister(struct work_struct *work);
|
||||
|
@ -51,6 +48,199 @@ struct apr_reset_work {
|
|||
struct work_struct work;
|
||||
};
|
||||
|
||||
struct apr_svc_table {
|
||||
char name[64];
|
||||
int idx;
|
||||
int id;
|
||||
int client_id;
|
||||
};
|
||||
|
||||
static const struct apr_svc_table svc_tbl_audio[] = {
|
||||
{
|
||||
.name = "AFE",
|
||||
.idx = 0,
|
||||
.id = APR_SVC_AFE,
|
||||
.client_id = APR_CLIENT_AUDIO,
|
||||
},
|
||||
{
|
||||
.name = "ASM",
|
||||
.idx = 1,
|
||||
.id = APR_SVC_ASM,
|
||||
.client_id = APR_CLIENT_AUDIO,
|
||||
},
|
||||
{
|
||||
.name = "ADM",
|
||||
.idx = 2,
|
||||
.id = APR_SVC_ADM,
|
||||
.client_id = APR_CLIENT_AUDIO,
|
||||
},
|
||||
{
|
||||
.name = "CORE",
|
||||
.idx = 3,
|
||||
.id = APR_SVC_ADSP_CORE,
|
||||
.client_id = APR_CLIENT_AUDIO,
|
||||
},
|
||||
{
|
||||
.name = "TEST",
|
||||
.idx = 4,
|
||||
.id = APR_SVC_TEST_CLIENT,
|
||||
.client_id = APR_CLIENT_AUDIO,
|
||||
},
|
||||
{
|
||||
.name = "MVM",
|
||||
.idx = 5,
|
||||
.id = APR_SVC_ADSP_MVM,
|
||||
.client_id = APR_CLIENT_AUDIO,
|
||||
},
|
||||
{
|
||||
.name = "CVS",
|
||||
.idx = 6,
|
||||
.id = APR_SVC_ADSP_CVS,
|
||||
.client_id = APR_CLIENT_AUDIO,
|
||||
},
|
||||
{
|
||||
.name = "CVP",
|
||||
.idx = 7,
|
||||
.id = APR_SVC_ADSP_CVP,
|
||||
.client_id = APR_CLIENT_AUDIO,
|
||||
},
|
||||
{
|
||||
.name = "USM",
|
||||
.idx = 8,
|
||||
.id = APR_SVC_USM,
|
||||
.client_id = APR_CLIENT_AUDIO,
|
||||
},
|
||||
};
|
||||
|
||||
static struct apr_svc_table svc_tbl_voice[] = {
|
||||
{
|
||||
.name = "VSM",
|
||||
.idx = 0,
|
||||
.id = APR_SVC_VSM,
|
||||
.client_id = APR_CLIENT_VOICE,
|
||||
},
|
||||
{
|
||||
.name = "VPM",
|
||||
.idx = 1,
|
||||
.id = APR_SVC_VPM,
|
||||
.client_id = APR_CLIENT_VOICE,
|
||||
},
|
||||
{
|
||||
.name = "MVS",
|
||||
.idx = 2,
|
||||
.id = APR_SVC_MVS,
|
||||
.client_id = APR_CLIENT_VOICE,
|
||||
},
|
||||
{
|
||||
.name = "MVM",
|
||||
.idx = 3,
|
||||
.id = APR_SVC_MVM,
|
||||
.client_id = APR_CLIENT_VOICE,
|
||||
},
|
||||
{
|
||||
.name = "CVS",
|
||||
.idx = 4,
|
||||
.id = APR_SVC_CVS,
|
||||
.client_id = APR_CLIENT_VOICE,
|
||||
},
|
||||
{
|
||||
.name = "CVP",
|
||||
.idx = 5,
|
||||
.id = APR_SVC_CVP,
|
||||
.client_id = APR_CLIENT_VOICE,
|
||||
},
|
||||
{
|
||||
.name = "SRD",
|
||||
.idx = 6,
|
||||
.id = APR_SVC_SRD,
|
||||
.client_id = APR_CLIENT_VOICE,
|
||||
},
|
||||
{
|
||||
.name = "TEST",
|
||||
.idx = 7,
|
||||
.id = APR_SVC_TEST_CLIENT,
|
||||
.client_id = APR_CLIENT_VOICE,
|
||||
},
|
||||
};
|
||||
|
||||
enum apr_subsys_state apr_get_modem_state(void)
|
||||
{
|
||||
return atomic_read(&q6.modem_state);
|
||||
}
|
||||
|
||||
void apr_set_modem_state(enum apr_subsys_state state)
|
||||
{
|
||||
atomic_set(&q6.modem_state, state);
|
||||
}
|
||||
|
||||
enum apr_subsys_state apr_cmpxchg_modem_state(enum apr_subsys_state prev,
|
||||
enum apr_subsys_state new)
|
||||
{
|
||||
return atomic_cmpxchg(&q6.modem_state, prev, new);
|
||||
}
|
||||
|
||||
enum apr_subsys_state apr_get_q6_state(void)
|
||||
{
|
||||
return atomic_read(&q6.q6_state);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(apr_get_q6_state);
|
||||
|
||||
int apr_set_q6_state(enum apr_subsys_state state)
|
||||
{
|
||||
pr_debug("%s: setting adsp state %d\n", __func__, state);
|
||||
if (state < APR_SUBSYS_DOWN || state > APR_SUBSYS_LOADED)
|
||||
return -EINVAL;
|
||||
atomic_set(&q6.q6_state, state);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(apr_set_q6_state);
|
||||
|
||||
enum apr_subsys_state apr_cmpxchg_q6_state(enum apr_subsys_state prev,
|
||||
enum apr_subsys_state new)
|
||||
{
|
||||
return atomic_cmpxchg(&q6.q6_state, prev, new);
|
||||
}
|
||||
|
||||
int apr_wait_for_device_up(int dest_id)
|
||||
{
|
||||
int rc = -1;
|
||||
if (dest_id == APR_DEST_MODEM)
|
||||
rc = wait_event_interruptible_timeout(modem_wait,
|
||||
(apr_get_modem_state() == APR_SUBSYS_UP),
|
||||
(1 * HZ));
|
||||
else if (dest_id == APR_DEST_QDSP6)
|
||||
rc = wait_event_interruptible_timeout(dsp_wait,
|
||||
(apr_get_q6_state() == APR_SUBSYS_UP),
|
||||
(1 * HZ));
|
||||
else
|
||||
pr_err("%s: unknown dest_id %d\n", __func__, dest_id);
|
||||
/* returns left time */
|
||||
return rc;
|
||||
}
|
||||
|
||||
int apr_load_adsp_image(void)
|
||||
{
|
||||
int rc = 0;
|
||||
mutex_lock(&q6.lock);
|
||||
if (apr_get_q6_state() == APR_SUBSYS_UP) {
|
||||
q6.pil = pil_get("q6");
|
||||
if (IS_ERR(q6.pil)) {
|
||||
rc = PTR_ERR(q6.pil);
|
||||
pr_err("APR: Unable to load q6 image, error:%d\n", rc);
|
||||
} else {
|
||||
apr_set_q6_state(APR_SUBSYS_LOADED);
|
||||
pr_debug("APR: Image is loaded, stated\n");
|
||||
}
|
||||
} else
|
||||
pr_debug("APR: cannot load state %d\n", apr_get_q6_state());
|
||||
mutex_unlock(&q6.lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
struct apr_client *apr_get_client(int dest_id, int client_id)
|
||||
{
|
||||
return &client[dest_id][client_id];
|
||||
}
|
||||
|
||||
int apr_send_pkt(void *handle, uint32_t *buf)
|
||||
{
|
||||
|
@ -72,11 +262,11 @@ int apr_send_pkt(void *handle, uint32_t *buf)
|
|||
}
|
||||
|
||||
if ((svc->dest_id == APR_DEST_QDSP6) &&
|
||||
(atomic_read(&dsp_state) == 0)) {
|
||||
pr_err("apr: Still dsp is not Up\n");
|
||||
(apr_get_q6_state() != APR_SUBSYS_LOADED)) {
|
||||
pr_err("%s: Still dsp is not Up\n", __func__);
|
||||
return -ENETRESET;
|
||||
} else if ((svc->dest_id == APR_DEST_MODEM) &&
|
||||
(atomic_read(&modem_state) == 0)) {
|
||||
(apr_get_modem_state() == APR_SUBSYS_DOWN)) {
|
||||
pr_err("apr: Still Modem is not Up\n");
|
||||
return -ENETRESET;
|
||||
}
|
||||
|
@ -111,7 +301,7 @@ int apr_send_pkt(void *handle, uint32_t *buf)
|
|||
return w_len;
|
||||
}
|
||||
|
||||
static void apr_cb_func(void *buf, int len, void *priv)
|
||||
void apr_cb_func(void *buf, int len, void *priv)
|
||||
{
|
||||
struct apr_client_data data;
|
||||
struct apr_client *apr_client;
|
||||
|
@ -136,8 +326,7 @@ static void apr_cb_func(void *buf, int len, void *priv)
|
|||
pr_debug("\n*****************\n");
|
||||
|
||||
if (!buf || len <= APR_HDR_SIZE) {
|
||||
pr_err("APR: Improper apr pkt received:%p %d\n",
|
||||
buf, len);
|
||||
pr_err("APR: Improper apr pkt received:%p %d\n", buf, len);
|
||||
return;
|
||||
}
|
||||
hdr = buf;
|
||||
|
@ -162,8 +351,7 @@ static void apr_cb_func(void *buf, int len, void *priv)
|
|||
}
|
||||
msg_type = hdr->hdr_field;
|
||||
msg_type = (msg_type >> 0x08) & 0x0003;
|
||||
if (msg_type >= APR_MSG_TYPE_MAX &&
|
||||
msg_type != APR_BASIC_RSP_RESULT) {
|
||||
if (msg_type >= APR_MSG_TYPE_MAX && msg_type != APR_BASIC_RSP_RESULT) {
|
||||
pr_err("APR: Wrong message type: %d\n", msg_type);
|
||||
return;
|
||||
}
|
||||
|
@ -180,8 +368,8 @@ static void apr_cb_func(void *buf, int len, void *priv)
|
|||
if (hdr->src_domain == APR_DOMAIN_MODEM) {
|
||||
src = APR_DEST_MODEM;
|
||||
if (svc == APR_SVC_MVS || svc == APR_SVC_MVM ||
|
||||
svc == APR_SVC_CVS || svc == APR_SVC_CVP ||
|
||||
svc == APR_SVC_TEST_CLIENT)
|
||||
svc == APR_SVC_CVS || svc == APR_SVC_CVP ||
|
||||
svc == APR_SVC_TEST_CLIENT)
|
||||
clnt = APR_CLIENT_VOICE;
|
||||
else {
|
||||
pr_err("APR: Wrong svc :%d\n", svc);
|
||||
|
@ -190,11 +378,11 @@ static void apr_cb_func(void *buf, int len, void *priv)
|
|||
} else if (hdr->src_domain == APR_DOMAIN_ADSP) {
|
||||
src = APR_DEST_QDSP6;
|
||||
if (svc == APR_SVC_AFE || svc == APR_SVC_ASM ||
|
||||
svc == APR_SVC_VSM || svc == APR_SVC_VPM ||
|
||||
svc == APR_SVC_ADM || svc == APR_SVC_ADSP_CORE ||
|
||||
svc == APR_SVC_USM ||
|
||||
svc == APR_SVC_TEST_CLIENT || svc == APR_SVC_ADSP_MVM ||
|
||||
svc == APR_SVC_ADSP_CVS || svc == APR_SVC_ADSP_CVP)
|
||||
svc == APR_SVC_VSM || svc == APR_SVC_VPM ||
|
||||
svc == APR_SVC_ADM || svc == APR_SVC_ADSP_CORE ||
|
||||
svc == APR_SVC_USM ||
|
||||
svc == APR_SVC_TEST_CLIENT || svc == APR_SVC_ADSP_MVM ||
|
||||
svc == APR_SVC_ADSP_CVS || svc == APR_SVC_ADSP_CVP)
|
||||
clnt = APR_CLIENT_AUDIO;
|
||||
else {
|
||||
pr_err("APR: Wrong svc :%d\n", svc);
|
||||
|
@ -220,7 +408,7 @@ static void apr_cb_func(void *buf, int len, void *priv)
|
|||
}
|
||||
pr_debug("svc_idx = %d\n", i);
|
||||
pr_debug("%x %x %x %p %p\n", c_svc->id, c_svc->dest_id,
|
||||
c_svc->client_id, c_svc->fn, c_svc->priv);
|
||||
c_svc->client_id, c_svc->fn, c_svc->priv);
|
||||
data.payload_size = hdr->pkt_size - hdr_size;
|
||||
data.opcode = hdr->opcode;
|
||||
data.src = src;
|
||||
|
@ -241,199 +429,39 @@ static void apr_cb_func(void *buf, int len, void *priv)
|
|||
pr_err("APR: Rxed a packet for NULL callback\n");
|
||||
}
|
||||
|
||||
struct apr_svc *apr_register(char *dest, char *svc_name, apr_fn svc_fn,
|
||||
uint32_t src_port, void *priv)
|
||||
int apr_get_svc(const char *svc_name, int dest_id, int *client_id,
|
||||
int *svc_idx, int *svc_id)
|
||||
{
|
||||
int client_id = 0;
|
||||
int svc_idx = 0;
|
||||
int svc_id = 0;
|
||||
int dest_id = 0;
|
||||
int temp_port = 0;
|
||||
struct apr_svc *svc = NULL;
|
||||
int rc = 0;
|
||||
int i;
|
||||
int size;
|
||||
struct apr_svc_table *tbl;
|
||||
int ret = 0;
|
||||
|
||||
if (!dest || !svc_name || !svc_fn)
|
||||
return NULL;
|
||||
|
||||
if (!strncmp(dest, "ADSP", 4))
|
||||
dest_id = APR_DEST_QDSP6;
|
||||
else if (!strncmp(dest, "MODEM", 5)) {
|
||||
dest_id = APR_DEST_MODEM;
|
||||
if (dest_id == APR_DEST_QDSP6) {
|
||||
tbl = (struct apr_svc_table *)&svc_tbl_audio;
|
||||
size = ARRAY_SIZE(svc_tbl_audio);
|
||||
} else {
|
||||
pr_err("APR: wrong destination\n");
|
||||
goto done;
|
||||
tbl = (struct apr_svc_table *)&svc_tbl_voice;
|
||||
size = ARRAY_SIZE(svc_tbl_voice);
|
||||
}
|
||||
|
||||
if ((dest_id == APR_DEST_QDSP6) &&
|
||||
(atomic_read(&dsp_state) == 0)) {
|
||||
pr_info("%s: Wait for Lpass to bootup\n", __func__);
|
||||
rc = wait_event_interruptible_timeout(dsp_wait,
|
||||
(atomic_read(&dsp_state) == 1), (1 * HZ));
|
||||
if (rc == 0) {
|
||||
pr_err("%s: DSP is not Up\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
pr_info("%s: Lpass Up\n", __func__);
|
||||
} else if ((dest_id == APR_DEST_MODEM) &&
|
||||
(atomic_read(&modem_state) == 0)) {
|
||||
pr_info("%s: Wait for modem to bootup\n", __func__);
|
||||
rc = wait_event_interruptible_timeout(modem_wait,
|
||||
(atomic_read(&modem_state) == 1), (1 * HZ));
|
||||
if (rc == 0) {
|
||||
pr_err("%s: Modem is not Up\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
pr_info("%s: modem Up\n", __func__);
|
||||
}
|
||||
|
||||
if (!strncmp(svc_name, "AFE", 3)) {
|
||||
client_id = APR_CLIENT_AUDIO;
|
||||
svc_idx = 0;
|
||||
svc_id = APR_SVC_AFE;
|
||||
} else if (!strncmp(svc_name, "ASM", 3)) {
|
||||
client_id = APR_CLIENT_AUDIO;
|
||||
svc_idx = 1;
|
||||
svc_id = APR_SVC_ASM;
|
||||
} else if (!strncmp(svc_name, "ADM", 3)) {
|
||||
client_id = APR_CLIENT_AUDIO;
|
||||
svc_idx = 2;
|
||||
svc_id = APR_SVC_ADM;
|
||||
} else if (!strncmp(svc_name, "CORE", 4)) {
|
||||
client_id = APR_CLIENT_AUDIO;
|
||||
svc_idx = 3;
|
||||
svc_id = APR_SVC_ADSP_CORE;
|
||||
} else if (!strncmp(svc_name, "TEST", 4)) {
|
||||
if (dest_id == APR_DEST_QDSP6) {
|
||||
client_id = APR_CLIENT_AUDIO;
|
||||
svc_idx = 4;
|
||||
} else {
|
||||
client_id = APR_CLIENT_VOICE;
|
||||
svc_idx = 7;
|
||||
}
|
||||
svc_id = APR_SVC_TEST_CLIENT;
|
||||
} else if (!strncmp(svc_name, "VSM", 3)) {
|
||||
client_id = APR_CLIENT_VOICE;
|
||||
svc_idx = 0;
|
||||
svc_id = APR_SVC_VSM;
|
||||
} else if (!strncmp(svc_name, "VPM", 3)) {
|
||||
client_id = APR_CLIENT_VOICE;
|
||||
svc_idx = 1;
|
||||
svc_id = APR_SVC_VPM;
|
||||
} else if (!strncmp(svc_name, "MVS", 3)) {
|
||||
client_id = APR_CLIENT_VOICE;
|
||||
svc_idx = 2;
|
||||
svc_id = APR_SVC_MVS;
|
||||
} else if (!strncmp(svc_name, "MVM", 3)) {
|
||||
if (dest_id == APR_DEST_MODEM) {
|
||||
client_id = APR_CLIENT_VOICE;
|
||||
svc_idx = 3;
|
||||
svc_id = APR_SVC_MVM;
|
||||
} else {
|
||||
client_id = APR_CLIENT_AUDIO;
|
||||
svc_idx = 5;
|
||||
svc_id = APR_SVC_ADSP_MVM;
|
||||
}
|
||||
} else if (!strncmp(svc_name, "CVS", 3)) {
|
||||
if (dest_id == APR_DEST_MODEM) {
|
||||
client_id = APR_CLIENT_VOICE;
|
||||
svc_idx = 4;
|
||||
svc_id = APR_SVC_CVS;
|
||||
} else {
|
||||
client_id = APR_CLIENT_AUDIO;
|
||||
svc_idx = 6;
|
||||
svc_id = APR_SVC_ADSP_CVS;
|
||||
}
|
||||
} else if (!strncmp(svc_name, "CVP", 3)) {
|
||||
if (dest_id == APR_DEST_MODEM) {
|
||||
client_id = APR_CLIENT_VOICE;
|
||||
svc_idx = 5;
|
||||
svc_id = APR_SVC_CVP;
|
||||
} else {
|
||||
client_id = APR_CLIENT_AUDIO;
|
||||
svc_idx = 7;
|
||||
svc_id = APR_SVC_ADSP_CVP;
|
||||
}
|
||||
} else if (!strncmp(svc_name, "SRD", 3)) {
|
||||
client_id = APR_CLIENT_VOICE;
|
||||
svc_idx = 6;
|
||||
svc_id = APR_SVC_SRD;
|
||||
} else if (!strncmp(svc_name, "USM", 3)) {
|
||||
client_id = APR_CLIENT_AUDIO;
|
||||
svc_idx = 8;
|
||||
svc_id = APR_SVC_USM;
|
||||
} else {
|
||||
pr_err("APR: Wrong svc name\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
pr_debug("svc name = %s c_id = %d dest_id = %d\n",
|
||||
svc_name, client_id, dest_id);
|
||||
mutex_lock(&q6.lock);
|
||||
if (q6.state == APR_Q6_NOIMG) {
|
||||
q6.pil = pil_get("q6");
|
||||
if (IS_ERR(q6.pil)) {
|
||||
q6.pil = pil_get("adsp");
|
||||
if (IS_ERR(q6.pil)) {
|
||||
rc = PTR_ERR(q6.pil);
|
||||
pr_err("APR: Unable to load q6 image, error:%d\n",
|
||||
rc);
|
||||
mutex_unlock(&q6.lock);
|
||||
return svc;
|
||||
}
|
||||
}
|
||||
q6.state = APR_Q6_LOADED;
|
||||
}
|
||||
mutex_unlock(&q6.lock);
|
||||
mutex_lock(&client[dest_id][client_id].m_lock);
|
||||
if (!client[dest_id][client_id].handle) {
|
||||
client[dest_id][client_id].handle = apr_tal_open(client_id,
|
||||
dest_id, APR_DL_SMD, apr_cb_func, NULL);
|
||||
if (!client[dest_id][client_id].handle) {
|
||||
svc = NULL;
|
||||
pr_err("APR: Unable to open handle\n");
|
||||
mutex_unlock(&client[dest_id][client_id].m_lock);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&client[dest_id][client_id].m_lock);
|
||||
svc = &client[dest_id][client_id].svc[svc_idx];
|
||||
mutex_lock(&svc->m_lock);
|
||||
client[dest_id][client_id].id = client_id;
|
||||
if (svc->need_reset) {
|
||||
mutex_unlock(&svc->m_lock);
|
||||
pr_err("APR: Service needs reset\n");
|
||||
goto done;
|
||||
}
|
||||
svc->priv = priv;
|
||||
svc->id = svc_id;
|
||||
svc->dest_id = dest_id;
|
||||
svc->client_id = client_id;
|
||||
if (src_port != 0xFFFFFFFF) {
|
||||
temp_port = ((src_port >> 8) * 8) + (src_port & 0xFF);
|
||||
pr_debug("port = %d t_port = %d\n", src_port, temp_port);
|
||||
if (temp_port >= APR_MAX_PORTS || temp_port < 0) {
|
||||
pr_err("APR: temp_port out of bounds\n");
|
||||
mutex_unlock(&svc->m_lock);
|
||||
return NULL;
|
||||
}
|
||||
if (!svc->port_cnt && !svc->svc_cnt)
|
||||
client[dest_id][client_id].svc_cnt++;
|
||||
svc->port_cnt++;
|
||||
svc->port_fn[temp_port] = svc_fn;
|
||||
svc->port_priv[temp_port] = priv;
|
||||
} else {
|
||||
if (!svc->fn) {
|
||||
if (!svc->port_cnt && !svc->svc_cnt)
|
||||
client[dest_id][client_id].svc_cnt++;
|
||||
svc->fn = svc_fn;
|
||||
if (svc->port_cnt)
|
||||
svc->svc_cnt++;
|
||||
for (i = 0; i < size; i++) {
|
||||
if (!strncmp(svc_name, tbl[i].name, strlen(tbl[i].name))) {
|
||||
*client_id = tbl[i].client_id;
|
||||
*svc_idx = tbl[i].idx;
|
||||
*svc_id = tbl[i].id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&svc->m_lock);
|
||||
done:
|
||||
return svc;
|
||||
pr_debug("%s: svc_name = %s c_id = %d dest_id = %d\n",
|
||||
__func__, svc_name, *client_id, dest_id);
|
||||
if (i == size) {
|
||||
pr_err("%s: APR: Wrong svc name %s\n", __func__, svc_name);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void apr_reset_deregister(struct work_struct *work)
|
||||
|
@ -489,7 +517,7 @@ int apr_deregister(void *handle)
|
|||
svc->need_reset = 0x0;
|
||||
}
|
||||
if (client[dest_id][client_id].handle &&
|
||||
!client[dest_id][client_id].svc_cnt) {
|
||||
!client[dest_id][client_id].svc_cnt) {
|
||||
apr_tal_close(client[dest_id][client_id].handle);
|
||||
client[dest_id][client_id].handle = NULL;
|
||||
}
|
||||
|
@ -524,14 +552,7 @@ void apr_reset(void *handle)
|
|||
queue_work(apr_reset_workqueue, &apr_reset_worker->work);
|
||||
}
|
||||
|
||||
void change_q6_state(int state)
|
||||
{
|
||||
mutex_lock(&q6.lock);
|
||||
q6.state = state;
|
||||
mutex_unlock(&q6.lock);
|
||||
}
|
||||
|
||||
int adsp_state(int state)
|
||||
static int adsp_state(int state)
|
||||
{
|
||||
pr_info("dsp state = %d\n", state);
|
||||
return 0;
|
||||
|
@ -590,12 +611,12 @@ void dispatch_event(unsigned long code, unsigned short proc)
|
|||
}
|
||||
|
||||
static int modem_notifier_cb(struct notifier_block *this, unsigned long code,
|
||||
void *_cmd)
|
||||
void *_cmd)
|
||||
{
|
||||
switch (code) {
|
||||
case SUBSYS_BEFORE_SHUTDOWN:
|
||||
pr_debug("M-Notify: Shutdown started\n");
|
||||
atomic_set(&modem_state, 0);
|
||||
apr_set_modem_state(APR_SUBSYS_DOWN);
|
||||
dispatch_event(code, APR_DEST_MODEM);
|
||||
break;
|
||||
case SUBSYS_AFTER_SHUTDOWN:
|
||||
|
@ -605,10 +626,9 @@ static int modem_notifier_cb(struct notifier_block *this, unsigned long code,
|
|||
pr_debug("M-notify: Bootup started\n");
|
||||
break;
|
||||
case SUBSYS_AFTER_POWERUP:
|
||||
if (atomic_read(&modem_state) == 0) {
|
||||
atomic_set(&modem_state, 1);
|
||||
if (apr_cmpxchg_modem_state(APR_SUBSYS_DOWN, APR_SUBSYS_UP) ==
|
||||
APR_SUBSYS_DOWN)
|
||||
wake_up(&modem_wait);
|
||||
}
|
||||
pr_debug("M-Notify: Bootup Completed\n");
|
||||
break;
|
||||
default:
|
||||
|
@ -623,12 +643,12 @@ static struct notifier_block mnb = {
|
|||
};
|
||||
|
||||
static int lpass_notifier_cb(struct notifier_block *this, unsigned long code,
|
||||
void *_cmd)
|
||||
void *_cmd)
|
||||
{
|
||||
switch (code) {
|
||||
case SUBSYS_BEFORE_SHUTDOWN:
|
||||
pr_debug("L-Notify: Shutdown started\n");
|
||||
atomic_set(&dsp_state, 0);
|
||||
apr_set_q6_state(APR_SUBSYS_DOWN);
|
||||
dispatch_event(code, APR_DEST_QDSP6);
|
||||
break;
|
||||
case SUBSYS_AFTER_SHUTDOWN:
|
||||
|
@ -638,10 +658,9 @@ static int lpass_notifier_cb(struct notifier_block *this, unsigned long code,
|
|||
pr_debug("L-notify: Bootup started\n");
|
||||
break;
|
||||
case SUBSYS_AFTER_POWERUP:
|
||||
if (atomic_read(&dsp_state) == 0) {
|
||||
atomic_set(&dsp_state, 1);
|
||||
if (apr_cmpxchg_q6_state(APR_SUBSYS_DOWN, APR_SUBSYS_UP) ==
|
||||
APR_SUBSYS_DOWN)
|
||||
wake_up(&dsp_wait);
|
||||
}
|
||||
pr_debug("L-Notify: Bootup Completed\n");
|
||||
break;
|
||||
default:
|
||||
|
@ -670,8 +689,7 @@ static int __init apr_init(void)
|
|||
}
|
||||
mutex_init(&q6.lock);
|
||||
dsp_debug_register(adsp_state);
|
||||
apr_reset_workqueue =
|
||||
create_singlethread_workqueue("apr_driver");
|
||||
apr_reset_workqueue = create_singlethread_workqueue("apr_driver");
|
||||
if (!apr_reset_workqueue)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
|
@ -683,10 +701,9 @@ static int __init apr_late_init(void)
|
|||
int ret = 0;
|
||||
init_waitqueue_head(&dsp_wait);
|
||||
init_waitqueue_head(&modem_wait);
|
||||
atomic_set(&dsp_state, 1);
|
||||
atomic_set(&modem_state, 1);
|
||||
subsys_notif_register_notifier("modem", &mnb);
|
||||
subsys_notif_register_notifier("lpass", &lnb);
|
||||
apr_set_subsys_state();
|
||||
return ret;
|
||||
}
|
||||
late_initcall(apr_late_init);
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 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/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/err.h>
|
||||
#include <mach/qdsp6v2/apr.h>
|
||||
#include <mach/qdsp6v2/apr_tal.h>
|
||||
#include <mach/qdsp6v2/dsp_debug.h>
|
||||
#include <mach/peripheral-loader.h>
|
||||
|
||||
struct apr_svc *apr_register(char *dest, char *svc_name, apr_fn svc_fn,
|
||||
uint32_t src_port, void *priv)
|
||||
{
|
||||
struct apr_client *client;
|
||||
int client_id = 0;
|
||||
int svc_idx = 0;
|
||||
int svc_id = 0;
|
||||
int dest_id = 0;
|
||||
int temp_port = 0;
|
||||
struct apr_svc *svc = NULL;
|
||||
int rc = 0;
|
||||
|
||||
if (!dest || !svc_name || !svc_fn)
|
||||
return NULL;
|
||||
|
||||
if (!strncmp(dest, "ADSP", 4))
|
||||
dest_id = APR_DEST_QDSP6;
|
||||
else if (!strncmp(dest, "MODEM", 5)) {
|
||||
dest_id = APR_DEST_MODEM;
|
||||
} else {
|
||||
pr_err("APR: wrong destination\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (dest_id == APR_DEST_QDSP6 &&
|
||||
apr_get_q6_state() == APR_SUBSYS_DOWN) {
|
||||
pr_info("%s: Wait for Lpass to bootup\n", __func__);
|
||||
rc = apr_wait_for_device_up(dest_id);
|
||||
if (rc == 0) {
|
||||
pr_err("%s: DSP is not Up\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
pr_info("%s: Lpass Up\n", __func__);
|
||||
} else if (dest_id == APR_DEST_MODEM &&
|
||||
(apr_get_modem_state() == APR_SUBSYS_DOWN)) {
|
||||
pr_info("%s: Wait for modem to bootup\n", __func__);
|
||||
rc = apr_wait_for_device_up(dest_id);
|
||||
if (rc == 0) {
|
||||
pr_err("%s: Modem is not Up\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
pr_info("%s: modem Up\n", __func__);
|
||||
}
|
||||
|
||||
if (apr_get_svc(svc_name, dest_id, &client_id, &svc_idx, &svc_id)) {
|
||||
pr_err("%s: apr_get_svc failed\n", __func__);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* APRv1 loads ADSP image automatically */
|
||||
apr_load_adsp_image();
|
||||
|
||||
client = apr_get_client(dest_id, client_id);
|
||||
mutex_lock(&client->m_lock);
|
||||
if (!client->handle) {
|
||||
client->handle = apr_tal_open(client_id, dest_id, APR_DL_SMD,
|
||||
apr_cb_func, NULL);
|
||||
if (!client->handle) {
|
||||
svc = NULL;
|
||||
pr_err("APR: Unable to open handle\n");
|
||||
mutex_unlock(&client->m_lock);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&client->m_lock);
|
||||
svc = &client->svc[svc_idx];
|
||||
mutex_lock(&svc->m_lock);
|
||||
client->id = client_id;
|
||||
if (svc->need_reset) {
|
||||
mutex_unlock(&svc->m_lock);
|
||||
pr_err("APR: Service needs reset\n");
|
||||
goto done;
|
||||
}
|
||||
svc->priv = priv;
|
||||
svc->id = svc_id;
|
||||
svc->dest_id = dest_id;
|
||||
svc->client_id = client_id;
|
||||
if (src_port != 0xFFFFFFFF) {
|
||||
temp_port = ((src_port >> 8) * 8) + (src_port & 0xFF);
|
||||
pr_debug("port = %d t_port = %d\n", src_port, temp_port);
|
||||
if (temp_port >= APR_MAX_PORTS || temp_port < 0) {
|
||||
pr_err("APR: temp_port out of bounds\n");
|
||||
mutex_unlock(&svc->m_lock);
|
||||
return NULL;
|
||||
}
|
||||
if (!svc->port_cnt && !svc->svc_cnt)
|
||||
client->svc_cnt++;
|
||||
svc->port_cnt++;
|
||||
svc->port_fn[temp_port] = svc_fn;
|
||||
svc->port_priv[temp_port] = priv;
|
||||
} else {
|
||||
if (!svc->fn) {
|
||||
if (!svc->port_cnt && !svc->svc_cnt)
|
||||
client->svc_cnt++;
|
||||
svc->fn = svc_fn;
|
||||
if (svc->port_cnt)
|
||||
svc->svc_cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&svc->m_lock);
|
||||
done:
|
||||
return svc;
|
||||
}
|
||||
|
||||
void apr_set_subsys_state(void)
|
||||
{
|
||||
apr_set_q6_state(APR_SUBSYS_UP);
|
||||
apr_set_modem_state(APR_SUBSYS_UP);
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 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/types.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <mach/qdsp6v2/apr.h>
|
||||
#include <mach/qdsp6v2/apr_tal.h>
|
||||
#include <mach/qdsp6v2/dsp_debug.h>
|
||||
|
||||
struct apr_svc *apr_register(char *dest, char *svc_name, apr_fn svc_fn,
|
||||
uint32_t src_port, void *priv)
|
||||
{
|
||||
struct apr_client *client;
|
||||
int client_id = 0;
|
||||
int svc_idx = 0;
|
||||
int svc_id = 0;
|
||||
int dest_id = 0;
|
||||
int temp_port = 0;
|
||||
struct apr_svc *svc = NULL;
|
||||
int rc = 0;
|
||||
|
||||
if (!dest || !svc_name || !svc_fn)
|
||||
return NULL;
|
||||
|
||||
if (!strncmp(dest, "ADSP", 4))
|
||||
dest_id = APR_DEST_QDSP6;
|
||||
else if (!strncmp(dest, "MODEM", 5)) {
|
||||
dest_id = APR_DEST_MODEM;
|
||||
} else {
|
||||
pr_err("APR: wrong destination\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if ((dest_id == APR_DEST_QDSP6)) {
|
||||
if (apr_get_q6_state() != APR_SUBSYS_LOADED) {
|
||||
pr_err("%s: adsp not up\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
pr_info("%s: Lpass Up\n", __func__);
|
||||
} else if ((dest_id == APR_DEST_MODEM) &&
|
||||
(apr_get_modem_state() == APR_SUBSYS_DOWN)) {
|
||||
pr_info("%s: Wait for modem to bootup\n", __func__);
|
||||
rc = apr_wait_for_device_up(dest_id);
|
||||
if (rc == 0) {
|
||||
pr_err("%s: Modem is not Up\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
pr_info("%s: modem Up\n", __func__);
|
||||
}
|
||||
|
||||
if (apr_get_svc(svc_name, dest_id, &client_id, &svc_idx, &svc_id)) {
|
||||
pr_err("%s: apr_get_svc failed\n", __func__);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* APRv2 doen't load ADSP image automatically */
|
||||
|
||||
client = apr_get_client(dest_id, client_id);
|
||||
mutex_lock(&client->m_lock);
|
||||
if (!client->handle) {
|
||||
client->handle = apr_tal_open(client_id, dest_id, APR_DL_SMD,
|
||||
apr_cb_func, NULL);
|
||||
if (!client->handle) {
|
||||
svc = NULL;
|
||||
pr_err("APR: Unable to open handle\n");
|
||||
mutex_unlock(&client->m_lock);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&client->m_lock);
|
||||
svc = &client->svc[svc_idx];
|
||||
mutex_lock(&svc->m_lock);
|
||||
client->id = client_id;
|
||||
if (svc->need_reset) {
|
||||
mutex_unlock(&svc->m_lock);
|
||||
pr_err("APR: Service needs reset\n");
|
||||
goto done;
|
||||
}
|
||||
svc->priv = priv;
|
||||
svc->id = svc_id;
|
||||
svc->dest_id = dest_id;
|
||||
svc->client_id = client_id;
|
||||
if (src_port != 0xFFFFFFFF) {
|
||||
temp_port = ((src_port >> 8) * 8) + (src_port & 0xFF);
|
||||
pr_debug("port = %d t_port = %d\n", src_port, temp_port);
|
||||
if (temp_port >= APR_MAX_PORTS || temp_port < 0) {
|
||||
pr_err("APR: temp_port out of bounds\n");
|
||||
mutex_unlock(&svc->m_lock);
|
||||
return NULL;
|
||||
}
|
||||
if (!svc->port_cnt && !svc->svc_cnt)
|
||||
client->svc_cnt++;
|
||||
svc->port_cnt++;
|
||||
svc->port_fn[temp_port] = svc_fn;
|
||||
svc->port_priv[temp_port] = priv;
|
||||
} else {
|
||||
if (!svc->fn) {
|
||||
if (!svc->port_cnt && !svc->svc_cnt)
|
||||
client->svc_cnt++;
|
||||
svc->fn = svc_fn;
|
||||
if (svc->port_cnt)
|
||||
svc->svc_cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&svc->m_lock);
|
||||
done:
|
||||
return svc;
|
||||
}
|
||||
|
||||
void apr_set_subsys_state(void)
|
||||
{
|
||||
apr_set_q6_state(APR_SUBSYS_DOWN);
|
||||
apr_set_modem_state(APR_SUBSYS_UP);
|
||||
}
|
|
@ -337,7 +337,7 @@ static ssize_t apr_debug_write(struct file *file, const char __user *buf,
|
|||
if (apr_handle_q)
|
||||
apr_deregister(apr_handle_q);
|
||||
} else if (!strncmp(l_buf + 20, "loaded", 64)) {
|
||||
change_q6_state(APR_Q6_LOADED);
|
||||
apr_set_q6_state(APR_SUBSYS_LOADED);
|
||||
} else if (!strncmp(l_buf + 20, "boom", 64)) {
|
||||
q6audio_dsp_not_responding();
|
||||
} else if (!strncmp(l_buf + 20, "dsp_ver", 64)) {
|
||||
|
|
Loading…
Reference in New Issue