diff options
author | Linux Build Service Account <lnxbuild@localhost> | 2016-09-29 11:21:06 -0700 |
---|---|---|
committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2016-09-29 11:21:06 -0700 |
commit | 6d162862f4c53ca925468e3c87d328878946d2a6 (patch) | |
tree | e490a43bf7a8d6e2e4ea55e15c1b5770c0f802cf /drivers | |
parent | f5b7228107c86363f41396738b06c46643c8f97d (diff) | |
parent | dec2bc73ee22e3680ef4423152ce9d4e39ce4e19 (diff) |
Merge "ASoC: msmcobalt: Enable msmcobalt to use audio notifier"
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/soc/qcom/qdsp6v2/apr.c | 184 | ||||
-rw-r--r-- | drivers/soc/qcom/qdsp6v2/apr_v2.c | 20 | ||||
-rw-r--r-- | drivers/soc/qcom/qdsp6v2/apr_v3.c | 18 |
3 files changed, 94 insertions, 128 deletions
diff --git a/drivers/soc/qcom/qdsp6v2/apr.c b/drivers/soc/qcom/qdsp6v2/apr.c index bbe686f4bc42..5517f20f310c 100644 --- a/drivers/soc/qcom/qdsp6v2/apr.c +++ b/drivers/soc/qcom/qdsp6v2/apr.c @@ -27,16 +27,15 @@ #include <linux/device.h> #include <linux/slab.h> #include <soc/qcom/subsystem_restart.h> -#include <soc/qcom/subsystem_notif.h> #include <soc/qcom/scm.h> #include <sound/apr_audio-v2.h> #include <soc/qcom/smd.h> #include <linux/qdsp6v2/apr.h> #include <linux/qdsp6v2/apr_tal.h> #include <linux/qdsp6v2/dsp_debug.h> +#include <linux/qdsp6v2/audio_notifier.h> #include <linux/ipc_logging.h> -#define SCM_Q6_NMI_CMD 0x1 #define APR_PKT_IPC_LOG_PAGE_CNT 2 static struct apr_q6 q6; @@ -45,9 +44,11 @@ static void *apr_pkt_ctx; static wait_queue_head_t dsp_wait; static wait_queue_head_t modem_wait; static bool is_modem_up; +static bool is_initial_boot; /* Subsystem restart: QDSP6 data, functions */ static struct workqueue_struct *apr_reset_workqueue; static void apr_reset_deregister(struct work_struct *work); +static void dispatch_event(unsigned long code, uint16_t proc); struct apr_reset_work { void *handle; struct work_struct work; @@ -202,6 +203,20 @@ enum apr_subsys_state apr_cmpxchg_modem_state(enum apr_subsys_state prev, return atomic_cmpxchg(&q6.modem_state, prev, new); } +static void apr_modem_down(unsigned long opcode) +{ + apr_set_modem_state(APR_SUBSYS_DOWN); + dispatch_event(opcode, APR_DEST_MODEM); +} + +static void apr_modem_up(void) +{ + if (apr_cmpxchg_modem_state(APR_SUBSYS_DOWN, APR_SUBSYS_UP) == + APR_SUBSYS_DOWN) + wake_up(&modem_wait); + is_modem_up = 1; +} + enum apr_subsys_state apr_get_q6_state(void) { return atomic_read(&q6.q6_state); @@ -224,6 +239,19 @@ enum apr_subsys_state apr_cmpxchg_q6_state(enum apr_subsys_state prev, return atomic_cmpxchg(&q6.q6_state, prev, new); } +static void apr_adsp_down(unsigned long opcode) +{ + apr_set_q6_state(APR_SUBSYS_DOWN); + dispatch_event(opcode, APR_DEST_QDSP6); +} + +static void apr_adsp_up(void) +{ + if (apr_cmpxchg_q6_state(APR_SUBSYS_DOWN, APR_SUBSYS_LOADED) == + APR_SUBSYS_DOWN) + wake_up(&dsp_wait); +} + int apr_wait_for_device_up(int dest_id) { int rc = -1; @@ -730,7 +758,7 @@ void apr_reset(void *handle) } /* Dispatch the Reset events to Modem and audio clients */ -void dispatch_event(unsigned long code, uint16_t proc) +static void dispatch_event(unsigned long code, uint16_t proc) { struct apr_client *apr_client; struct apr_client_data data; @@ -783,128 +811,51 @@ void dispatch_event(unsigned long code, uint16_t proc) } } -static int modem_notifier_cb(struct notifier_block *this, unsigned long code, - void *_cmd) +static int apr_notifier_service_cb(struct notifier_block *this, + unsigned long opcode, void *data) { - static int boot_count = 2; + struct audio_notifier_cb_data *cb_data = data; - if (boot_count) { - boot_count--; - return NOTIFY_OK; + if (cb_data == NULL) { + pr_err("%s: Callback data is NULL!\n", __func__); + goto done; } - switch (code) { - case SUBSYS_BEFORE_SHUTDOWN: - pr_debug("M-Notify: Shutdown started\n"); - apr_set_modem_state(APR_SUBSYS_DOWN); - dispatch_event(code, APR_DEST_MODEM); - break; - case SUBSYS_AFTER_SHUTDOWN: - pr_debug("M-Notify: Shutdown Completed\n"); - break; - case SUBSYS_BEFORE_POWERUP: - pr_debug("M-notify: Bootup started\n"); - break; - case SUBSYS_AFTER_POWERUP: - if (apr_cmpxchg_modem_state(APR_SUBSYS_DOWN, APR_SUBSYS_UP) == - APR_SUBSYS_DOWN) - wake_up(&modem_wait); - is_modem_up = 1; - pr_debug("M-Notify: Bootup Completed\n"); - break; - default: - pr_err("M-Notify: General: %lu\n", code); - break; - } - return NOTIFY_DONE; -} + pr_debug("%s: Service opcode 0x%lx, domain %d\n", + __func__, opcode, cb_data->domain); -static struct notifier_block mnb = { - .notifier_call = modem_notifier_cb, -}; - -static bool powered_on; - -static int lpass_notifier_cb(struct notifier_block *this, unsigned long code, - void *_cmd) -{ - static int boot_count = 2; - struct notif_data *data = (struct notif_data *)_cmd; - struct scm_desc desc; - - if (boot_count) { - boot_count--; - return NOTIFY_OK; - } - - switch (code) { - case SUBSYS_BEFORE_SHUTDOWN: - pr_debug("L-Notify: Shutdown started\n"); - apr_set_q6_state(APR_SUBSYS_DOWN); - dispatch_event(code, APR_DEST_QDSP6); - if (data && data->crashed) { - /* Send NMI to QDSP6 via an SCM call. */ - if (!is_scm_armv8()) { - scm_call_atomic1(SCM_SVC_UTIL, - SCM_Q6_NMI_CMD, 0x1); - } else { - desc.args[0] = 0x1; - desc.arginfo = SCM_ARGS(1); - scm_call2_atomic(SCM_SIP_FNID(SCM_SVC_UTIL, - SCM_Q6_NMI_CMD), &desc); - } - /* The write should go through before q6 is shutdown */ - mb(); - pr_debug("L-Notify: Q6 NMI was sent.\n"); - } - break; - case SUBSYS_AFTER_SHUTDOWN: - powered_on = false; - pr_debug("L-Notify: Shutdown Completed\n"); - break; - case SUBSYS_BEFORE_POWERUP: - pr_debug("L-notify: Bootup started\n"); + switch (opcode) { + case AUDIO_NOTIFIER_SERVICE_DOWN: + /* + * Use flag to ignore down notifications during + * initial boot. There is no benefit from error + * recovery notifications during initial boot + * up since everything is expected to be down. + */ + if (is_initial_boot) + break; + if (cb_data->domain == AUDIO_NOTIFIER_MODEM_DOMAIN) + apr_modem_down(opcode); + else + apr_adsp_down(opcode); break; - case SUBSYS_AFTER_POWERUP: - if (apr_cmpxchg_q6_state(APR_SUBSYS_DOWN, - APR_SUBSYS_LOADED) == APR_SUBSYS_DOWN) - wake_up(&dsp_wait); - powered_on = true; - pr_debug("L-Notify: Bootup Completed\n"); + case AUDIO_NOTIFIER_SERVICE_UP: + is_initial_boot = false; + if (cb_data->domain == AUDIO_NOTIFIER_MODEM_DOMAIN) + apr_modem_up(); + else + apr_adsp_up(); break; default: - pr_err("L-Notify: Generel: %lu\n", code); break; } - return NOTIFY_DONE; +done: + return NOTIFY_OK; } -static struct notifier_block lnb = { +static struct notifier_block service_nb = { + .notifier_call = apr_notifier_service_cb, .priority = 0, - .notifier_call = lpass_notifier_cb, -}; - -static int panic_handler(struct notifier_block *this, - unsigned long event, void *ptr) -{ - struct scm_desc desc; - - if (powered_on) { - /* Send NMI to QDSP6 via an SCM call. */ - if (!is_scm_armv8()) { - scm_call_atomic1(SCM_SVC_UTIL, SCM_Q6_NMI_CMD, 0x1); - } else { - desc.args[0] = 0x1; - desc.arginfo = SCM_ARGS(1); - scm_call2_atomic(SCM_SIP_FNID(SCM_SVC_UTIL, - SCM_Q6_NMI_CMD), &desc); - } - } - return NOTIFY_DONE; -} - -static struct notifier_block panic_nb = { - .notifier_call = panic_handler, }; static int __init apr_init(void) @@ -924,13 +875,18 @@ static int __init apr_init(void) apr_reset_workqueue = create_singlethread_workqueue("apr_driver"); if (!apr_reset_workqueue) return -ENOMEM; - atomic_notifier_chain_register(&panic_notifier_list, &panic_nb); apr_pkt_ctx = ipc_log_context_create(APR_PKT_IPC_LOG_PAGE_CNT, "apr", 0); if (!apr_pkt_ctx) pr_err("%s: Unable to create ipc log context\n", __func__); + is_initial_boot = true; + subsys_notif_register("apr_adsp", AUDIO_NOTIFIER_ADSP_DOMAIN, + &service_nb); + subsys_notif_register("apr_modem", AUDIO_NOTIFIER_MODEM_DOMAIN, + &service_nb); + return 0; } device_initcall(apr_init); @@ -940,7 +896,7 @@ 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; } late_initcall(apr_late_init); diff --git a/drivers/soc/qcom/qdsp6v2/apr_v2.c b/drivers/soc/qcom/qdsp6v2/apr_v2.c index 2d6ea825c811..037fb3327ef0 100644 --- a/drivers/soc/qcom/qdsp6v2/apr_v2.c +++ b/drivers/soc/qcom/qdsp6v2/apr_v2.c @@ -18,8 +18,7 @@ #include <linux/qdsp6v2/apr.h> #include <linux/qdsp6v2/apr_tal.h> #include <linux/qdsp6v2/dsp_debug.h> - -static const char *lpass_subsys_name = "adsp"; +#include <linux/qdsp6v2/audio_notifier.h> enum apr_subsys_state apr_get_subsys_state(void) { @@ -32,11 +31,6 @@ void apr_set_subsys_state(void) apr_set_modem_state(APR_SUBSYS_UP); } -const char *apr_get_lpass_subsys_name(void) -{ - return lpass_subsys_name; -} - uint16_t apr_get_data_src(struct apr_hdr *hdr) { if (hdr->src_domain == APR_DOMAIN_MODEM) @@ -57,11 +51,15 @@ int apr_get_dest_id(char *dest) return APR_DEST_MODEM; } -void subsys_notif_register(struct notifier_block *mod_notif, - struct notifier_block *lp_notif) +void subsys_notif_register(char *client_name, int domain, + struct notifier_block *nb) { - subsys_notif_register_notifier("modem", mod_notif); - subsys_notif_register_notifier(apr_get_lpass_subsys_name(), lp_notif); + int ret; + + ret = audio_notifier_register(client_name, domain, nb); + if (ret < 0) + pr_err("%s: Audio notifier register failed for domain %d ret = %d\n", + __func__, domain, ret); } uint16_t apr_get_reset_domain(uint16_t proc) diff --git a/drivers/soc/qcom/qdsp6v2/apr_v3.c b/drivers/soc/qcom/qdsp6v2/apr_v3.c index 6bb913edf3ec..2bfc518841c9 100644 --- a/drivers/soc/qcom/qdsp6v2/apr_v3.c +++ b/drivers/soc/qcom/qdsp6v2/apr_v3.c @@ -18,6 +18,7 @@ #include <linux/qdsp6v2/apr.h> #include <linux/qdsp6v2/apr_tal.h> #include <linux/qdsp6v2/dsp_debug.h> +#include <linux/qdsp6v2/audio_notifier.h> #define DEST_ID APR_DEST_MODEM @@ -41,10 +42,21 @@ int apr_get_dest_id(char *dest) return DEST_ID; } -void subsys_notif_register(struct notifier_block *mod_notif, - struct notifier_block *lp_notif) +void subsys_notif_register(char *client_name, int domain, + struct notifier_block *nb) { - subsys_notif_register_notifier("modem", mod_notif); + int ret; + + if (domain != AUDIO_NOTIFIER_MODEM_DOMAIN) { + pr_debug("%s: Unused domain %d not registering with notifier\n", + __func__, domain); + return; + } + + ret = audio_notifier_register(client_name, domain, nb); + if (ret < 0) + pr_err("%s: Audio notifier register failed for domain %d ret = %d\n", + __func__, domain, ret); } uint16_t apr_get_reset_domain(uint16_t proc) |