From b8fcfd2679b63bb977a47a43c5f80c9312b0f2c9 Mon Sep 17 00:00:00 2001 From: Kamati Srinivas Date: Tue, 6 Aug 2024 11:14:19 +0530 Subject: [PATCH 1/3] Revert "remoteproc: pas: Check running ack for D0 transition" This reverts commit a8ce5c255285d7e0e1753ee9803ed782b580df65. TCSR register read can be solely relied upon for D0 confirmation. Change-Id: I9cb11a13313d2a9964efdc02a77b698b62268070 Signed-off-by: Kamati Srinivas --- drivers/remoteproc/qcom_q6v5.h | 2 -- drivers/remoteproc/qcom_q6v5_pas.c | 37 ------------------------------ 2 files changed, 39 deletions(-) diff --git a/drivers/remoteproc/qcom_q6v5.h b/drivers/remoteproc/qcom_q6v5.h index c072ab8bb792..709f8fc8256f 100644 --- a/drivers/remoteproc/qcom_q6v5.h +++ b/drivers/remoteproc/qcom_q6v5.h @@ -33,7 +33,6 @@ struct qcom_q6v5 { int ready_irq; int handover_irq; int stop_irq; - int active_state_ack_irq; struct rproc_subdev *ssr_subdev; @@ -43,7 +42,6 @@ struct qcom_q6v5 { struct completion start_done; struct completion stop_done; - struct completion running_ack; int crash_reason; diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index 563e4f993137..7e6733be98e4 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -814,15 +814,6 @@ exit: return ret; } -static irqreturn_t soccp_running_ack(int irq, void *data) -{ - struct qcom_q6v5 *q6v5 = data; - - complete(&q6v5->running_ack); - - return IRQ_HANDLED; -} - /** * rproc_config_check() - Check back the config register * @state: new state of the rproc @@ -971,8 +962,6 @@ int rproc_set_state(struct rproc *rproc, bool state) goto soccp_out; } - reinit_completion(&(adsp->q6v5.running_ack)); - ret = qcom_smem_state_update_bits(adsp->wake_state, SOCCP_STATE_MASK, BIT(adsp->wake_bit)); @@ -989,15 +978,6 @@ int rproc_set_state(struct rproc *rproc, bool state) goto soccp_out; } - ret = wait_for_completion_timeout(&adsp->q6v5.running_ack, msecs_to_jiffies(5)); - if (!ret) { - dev_err(adsp->dev, "%s requested D3->D0: failed to get wake ack\n", - current->comm); - ret = -ETIMEDOUT; - goto soccp_out; - } else - ret = 0; - adsp->current_users = 1; } else { if (users > 1) { @@ -1736,26 +1716,9 @@ static int adsp_probe(struct platform_device *pdev) goto detach_proxy_pds; } - adsp->q6v5.active_state_ack_irq = platform_get_irq_byname(pdev, "wake-ack"); - if (adsp->q6v5.active_state_ack_irq < 0) { - dev_err(&pdev->dev, "failed to acquire readyack irq\n"); - goto detach_proxy_pds; - } - - ret = devm_request_threaded_irq(&pdev->dev, adsp->q6v5.active_state_ack_irq, - NULL, soccp_running_ack, - IRQF_TRIGGER_RISING | IRQF_ONESHOT, - "qcom_q6v5_pas", &adsp->q6v5); - if (ret) { - dev_err(&pdev->dev, "failed to acquire ready ack IRQ\n"); - goto detach_proxy_pds; - } - mutex_init(&adsp->adsp_lock); - init_completion(&(adsp->q6v5.running_ack)); adsp->current_users = 0; - } qcom_q6v5_register_ssr_subdev(&adsp->q6v5, &adsp->ssr_subdev.subdev); From 1bb038ef633d5de34a9d4711a1a6f13144a2fee6 Mon Sep 17 00:00:00 2001 From: Gokul krishna Krishnakumar Date: Tue, 25 Jun 2024 13:06:07 -0700 Subject: [PATCH 2/3] remoteproc: pas: Clear master kernel if D request fails Clear the master kernel bit if the SOCCP does not honour the APPS request for a state change. Change-Id: I5a6747973ed87e4c7f0d9074ef8da56925d2a927 Signed-off-by: Gokul krishna Krishnakumar Signed-off-by: Kamati Srinivas --- drivers/remoteproc/qcom_q6v5_pas.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index 7e6733be98e4..a755f1ed955c 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -972,6 +972,12 @@ int rproc_set_state(struct rproc *rproc, bool state) ret = rproc_config_check(adsp, SOCCP_D0); if (ret) { + ret = qcom_smem_state_update_bits(adsp->wake_state, + SOCCP_STATE_MASK, + !BIT(adsp->wake_bit)); + if (ret) + dev_err(adsp->dev, "failed to clear smem bits after a failed D0 request\n"); + dsb(sy); dev_err(adsp->dev, "%s requested D3->D0: soccp failed to update tcsr val=%d\n", current->comm, readl(adsp->config_addr)); @@ -995,6 +1001,12 @@ int rproc_set_state(struct rproc *rproc, bool state) ret = rproc_config_check(adsp, SOCCP_D3); if (ret) { + ret = qcom_smem_state_update_bits(adsp->sleep_state, + SOCCP_STATE_MASK, + !BIT(adsp->sleep_bit)); + if (ret) + dev_err(adsp->dev, "failed to clear smem bits after a failed D3 request\n"); + dsb(sy); dev_err(adsp->dev, "%s requested D0->D3 failed: TCSR value:%d\n", current->comm, readl(adsp->config_addr)); From a7975a4fd92a0aa4a3d40d7cc56fe745f3070523 Mon Sep 17 00:00:00 2001 From: Kamati Srinivas Date: Tue, 6 Aug 2024 13:35:16 +0530 Subject: [PATCH 3/3] remoteproc: qcom: pas: Use SOCCP_SPARE register to check D0 state TCSR_SOCCP_SLEEP_STATUS is updated when SOCCP starts wakeup process and is not done processing the sleep request, Check the D0 state transition by polling on SOCCP_SPARE register. Change-Id: I7a00ec58f99ca748857e93ce4aab5a8dcc126faf Signed-off-by: Gokul krishna Krishnakumar Signed-off-by: Kamati Srinivas --- drivers/remoteproc/qcom_q6v5_pas.c | 96 +++++++++++++++++++----------- 1 file changed, 61 insertions(+), 35 deletions(-) diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index a755f1ed955c..a117ce953b82 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -61,6 +61,7 @@ static bool recovery_set_cb; #define SOCCP_SLEEP_US 100 #define SOCCP_TIMEOUT_US 10000 #define SOCCP_STATE_MASK 0x600 +#define SPARE_REG_SOCCP_D0 0x1 #define SOCCP_D0 0x2 #define SOCCP_D1 0x4 #define SOCCP_D3 0x8 @@ -164,7 +165,8 @@ struct qcom_adsp { unsigned int wake_bit; unsigned int sleep_bit; int current_users; - void *config_addr; + void *tcsr_addr; + void *spare_reg_addr; bool check_status; }; @@ -818,35 +820,33 @@ exit: * rproc_config_check() - Check back the config register * @state: new state of the rproc * - * Call this function after there has been a request to change of - * state of rproc. This function takes in the new state to which the - * rproc has transitioned, and poll the WFI status register to check - * if the state request change has been accepted successfully by the - * rproc. The poll is timed out after 10 milliseconds. + * Polled read on a register till with a 5ms timeout and 100-200Us interval. + * Returns immediately if the expected value is read back from the addr. * - * Return: 0 if the WFI status register reflects the requested state. + * state: new state of the rproc + * + * addr: Address to poll on + * + * return: 0 if the expected value is read back from the address + * -ETIMEDOUT is the value was not read in 5ms */ -static int rproc_config_check(struct qcom_adsp *adsp, u32 state) +static int rproc_config_check(struct qcom_adsp *adsp, u32 state, void *addr) { unsigned int retry_num = 50; u32 val; do { usleep_range(SOCCP_SLEEP_US, SOCCP_SLEEP_US + 100); - /* Making sure the mem mapped io is read correctly*/ - dsb(sy); - val = readl(adsp->config_addr); - if ((state == SOCCP_D0) && (val == SOCCP_D1)) - return 0; - } while (val != state && --retry_num); + val = readl(addr); + } while (!(val && state) && --retry_num); - return (val == state) ? 0 : -ETIMEDOUT; + return (val & state) ? 0 : -ETIMEDOUT; } -static int rproc_config_check_atomic(struct qcom_adsp *adsp, u32 state) +static int rproc_config_check_atomic(struct qcom_adsp *adsp, u32 state, void *addr) { u32 val; - return readx_poll_timeout_atomic(readl, adsp->config_addr, val, + return readx_poll_timeout_atomic(readl, addr, val, val == state, SOCCP_SLEEP_US, SOCCP_TIMEOUT_US); } @@ -862,31 +862,49 @@ static int rproc_find_status_register(struct qcom_adsp *adsp) { struct device_node *tcsr; struct device_node *np = adsp->dev->of_node; - u32 offset; + struct resource res; + u32 offset, addr; int ret; void *tcsr_base; - tcsr = of_parse_phandle(np, "soccp-config", 0); + tcsr = of_parse_phandle(np, "soccp-tcsr", 0); if (!tcsr) { dev_err(adsp->dev, "Unable to find the soccp config register\n"); return -EINVAL; } - tcsr_base = of_iomap(tcsr, 0); + ret = of_address_to_resource(tcsr, 0, &res); of_node_put(tcsr); + if (ret) { + dev_err(adsp->dev, "Unable to find the tcsr base addr\n"); + return ret; + } + + tcsr_base = ioremap_wc(res.start, resource_size(&res)); if (!tcsr_base) { dev_err(adsp->dev, "Unable to find the tcsr base addr\n"); return -ENOMEM; } - ret = of_property_read_u32_index(np, "soccp-config", 1, &offset); + ret = of_property_read_u32_index(np, "soccp-tcsr", 1, &offset); if (ret < 0) { - dev_err(adsp->dev, "Unable to find the tcsr offset addr\n"); + dev_err(adsp->dev, "Unable to find the tcsr config offset addr\n"); iounmap(tcsr_base); return ret; } + adsp->tcsr_addr = tcsr_base + offset; - adsp->config_addr = tcsr_base + offset; + ret = of_property_read_u32(np, "soccp-spare", &addr); + if (!addr) { + dev_err(adsp->dev, "Unable to find the running config register\n"); + return -EINVAL; + } + + adsp->spare_reg_addr = ioremap_wc(addr, 4); + if (!adsp->spare_reg_addr) { + dev_err(adsp->dev, "Unable to find the tcsr base addr\n"); + return -ENOMEM; + } return 0; } @@ -970,7 +988,14 @@ int rproc_set_state(struct rproc *rproc, bool state) goto soccp_out; } - ret = rproc_config_check(adsp, SOCCP_D0); + ret = rproc_config_check(adsp, SOCCP_D0 | SOCCP_D1, adsp->tcsr_addr); + if (ret) { + dev_err(adsp->dev, "%s requested D3->D0: soccp failed to update tcsr val=%d\n", + current->comm, readl(adsp->tcsr_addr)); + goto soccp_out; + } + + ret = rproc_config_check(adsp, SPARE_REG_SOCCP_D0, adsp->spare_reg_addr); if (ret) { ret = qcom_smem_state_update_bits(adsp->wake_state, SOCCP_STATE_MASK, @@ -978,9 +1003,8 @@ int rproc_set_state(struct rproc *rproc, bool state) if (ret) dev_err(adsp->dev, "failed to clear smem bits after a failed D0 request\n"); - dsb(sy); - dev_err(adsp->dev, "%s requested D3->D0: soccp failed to update tcsr val=%d\n", - current->comm, readl(adsp->config_addr)); + dev_err(adsp->dev, "%s requested D3->D0: soccp failed to update spare reg val=%d\n", + current->comm, readl(adsp->spare_reg_addr)); goto soccp_out; } @@ -999,7 +1023,7 @@ int rproc_set_state(struct rproc *rproc, bool state) goto soccp_out; } - ret = rproc_config_check(adsp, SOCCP_D3); + ret = rproc_config_check(adsp, SOCCP_D3, adsp->tcsr_addr); if (ret) { ret = qcom_smem_state_update_bits(adsp->sleep_state, SOCCP_STATE_MASK, @@ -1007,9 +1031,8 @@ int rproc_set_state(struct rproc *rproc, bool state) if (ret) dev_err(adsp->dev, "failed to clear smem bits after a failed D3 request\n"); - dsb(sy); dev_err(adsp->dev, "%s requested D0->D3 failed: TCSR value:%d\n", - current->comm, readl(adsp->config_addr)); + current->comm, readl(adsp->tcsr_addr)); goto soccp_out; } disable_regulators(adsp); @@ -1054,7 +1077,11 @@ static int rproc_panic_handler(struct notifier_block *this, dev_err(adsp->dev, "failed to update smem bits for D3 to D0\n"); goto done; } - ret = rproc_config_check_atomic(adsp, SOCCP_D0); + ret = rproc_config_check_atomic(adsp, SOCCP_D0, adsp->tcsr_addr); + if (ret) + dev_err(adsp->dev, "failed to change to D0\n"); + + ret = rproc_config_check_atomic(adsp, SPARE_REG_SOCCP_D0, adsp->spare_reg_addr); if (ret) dev_err(adsp->dev, "failed to change to D0\n"); done: @@ -1067,14 +1094,13 @@ static void qcom_pas_handover(struct qcom_q6v5 *q6v5) int ret; if (adsp->check_status) { - ret = rproc_config_check(adsp, SOCCP_D3); - dsb(sy); + ret = rproc_config_check(adsp, SOCCP_D3, adsp->tcsr_addr); if (ret) dev_err(adsp->dev, "state not changed in handover TCSR val = %d\n", - readl(adsp->config_addr)); + readl(adsp->tcsr_addr)); else dev_info(adsp->dev, "state changed in handover for soccp! TCSR val = %d\n", - readl(adsp->config_addr)); + readl(adsp->tcsr_addr)); } disable_regulators(adsp); clk_disable_unprepare(adsp->aggre2_clk);