Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932123AbcKGMhr (ORCPT ); Mon, 7 Nov 2016 07:37:47 -0500 Received: from smtp.codeaurora.org ([198.145.29.96]:41502 "EHLO smtp.codeaurora.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752376AbcKGMhl (ORCPT ); Mon, 7 Nov 2016 07:37:41 -0500 DMARC-Filter: OpenDMARC Filter v1.3.1 smtp.codeaurora.org 94E0C6120D Authentication-Results: pdx-caf-mail.web.codeaurora.org; dmarc=none header.from=codeaurora.org Authentication-Results: pdx-caf-mail.web.codeaurora.org; spf=pass smtp.mailfrom=akdwived@codeaurora.org From: Avaneesh Kumar Dwivedi To: bjorn.andersson@linaro.org Cc: linux-kernel@vger.kernel.org, linux-remoteproc@vger.kernel.org, linux-arm-msm@vger.kernel.org, Avaneesh Kumar Dwivedi Subject: [PATCH v3 3/3] remoteproc: qcom: Adding q6v56 reset sequence. Date: Mon, 7 Nov 2016 18:07:20 +0530 Message-Id: <1478522240-11036-4-git-send-email-akdwived@codeaurora.org> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1478522240-11036-1-git-send-email-akdwived@codeaurora.org> References: <1478522240-11036-1-git-send-email-akdwived@codeaurora.org> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 8824 Lines: 244 Adding additional reset sequence steps required specific to q6v56 based on version check, along with some trivial changes in name of local functions. Signed-off-by: Avaneesh Kumar Dwivedi --- drivers/remoteproc/qcom_q6v5_pil.c | 132 +++++++++++++++++++++++++++---------- 1 file changed, 98 insertions(+), 34 deletions(-) diff --git a/drivers/remoteproc/qcom_q6v5_pil.c b/drivers/remoteproc/qcom_q6v5_pil.c index 1fc505b..68eda4f 100644 --- a/drivers/remoteproc/qcom_q6v5_pil.c +++ b/drivers/remoteproc/qcom_q6v5_pil.c @@ -66,6 +66,8 @@ #define QDSP6SS_RESET_REG 0x014 #define QDSP6SS_GFMUX_CTL_REG 0x020 #define QDSP6SS_PWR_CTL_REG 0x030 +#define QDSP6SS_MEM_PWR_CTL 0x0B0 +#define QDSP6SS_STRAP_ACC 0x110 /* AXI Halt Register Offsets */ #define AXI_HALTREQ_REG 0x0 @@ -94,8 +96,14 @@ #define QDSS_BHS_ON BIT(21) #define QDSS_LDO_BYP BIT(22) +/* QDSP6v56 parameters */ +#define QDSP6v56_LDO_BYP BIT(25) +#define QDSP6v56_BHS_ON BIT(24) #define QDSP6v56_CLAMP_WL BIT(21) #define QDSP6v56_CLAMP_QMC_MEM BIT(22) +#define HALT_CHECK_MAX_LOOPS (200) +#define QDSP6SS_XO_CBCR (0x0038) +#define QDSP6SS_ACC_OVERRIDE_VAL 0x20 struct q6_rproc_res { char **proxy_clks; int proxy_clk_cnt; @@ -389,7 +397,8 @@ static void pil_mss_restart_reg(struct q6v5 *qproc, u32 mss_restart) udelay(2); } } -static int q6v5_load(struct rproc *rproc, const struct firmware *fw) + +static int q6_load(struct rproc *rproc, const struct firmware *fw) { struct q6v5 *qproc = rproc->priv; @@ -400,10 +409,10 @@ static int q6v5_load(struct rproc *rproc, const struct firmware *fw) static const struct rproc_fw_ops q6_fw_ops = { .find_rsc_table = qcom_mdt_find_rsc_table, - .load = q6v5_load, + .load = q6_load, }; -static int q6v5_rmb_pbl_wait(struct q6v5 *qproc, int ms) +static int q6_rmb_pbl_wait(struct q6v5 *qproc, int ms) { unsigned long timeout; s32 val; @@ -423,7 +432,7 @@ static int q6v5_rmb_pbl_wait(struct q6v5 *qproc, int ms) return val; } -static int q6v5_rmb_mba_wait(struct q6v5 *qproc, u32 status, int ms) +static int q6_rmb_mba_wait(struct q6v5 *qproc, u32 status, int ms) { unsigned long timeout; @@ -449,40 +458,95 @@ static int q6v5_rmb_mba_wait(struct q6v5 *qproc, u32 status, int ms) return val; } -static int q6v5proc_reset(struct q6v5 *qproc) +static int q6proc_reset(struct q6v5 *qproc) { - u32 val; - int ret; + int ret, i, count; + u64 val; + + /* Override the ACC value if required */ + if (!strcmp(qproc->q6_rproc_res->q6_version, "v56")) + writel_relaxed(QDSP6SS_ACC_OVERRIDE_VAL, + qproc->reg_base + QDSP6SS_STRAP_ACC); /* Assert resets, stop core */ - val = readl(qproc->reg_base + QDSP6SS_RESET_REG); + val = readl_relaxed(qproc->reg_base + QDSP6SS_RESET_REG); val |= (Q6SS_CORE_ARES | Q6SS_BUS_ARES_ENABLE | Q6SS_STOP_CORE); - writel(val, qproc->reg_base + QDSP6SS_RESET_REG); + writel_relaxed(val, qproc->reg_base + QDSP6SS_RESET_REG); + /* BHS require xo cbcr to be enabled */ + if (!strcmp(qproc->q6_rproc_res->q6_version, "v56")) { + val = readl_relaxed(qproc->reg_base + QDSP6SS_XO_CBCR); + val |= 0x1; + writel_relaxed(val, qproc->reg_base + QDSP6SS_XO_CBCR); + for (count = HALT_CHECK_MAX_LOOPS; count > 0; count--) { + val = readl_relaxed(qproc->reg_base + QDSP6SS_XO_CBCR); + if (!(val & BIT(31))) + break; + udelay(1); + } + + val = readl_relaxed(qproc->reg_base + QDSP6SS_XO_CBCR); + if ((val & BIT(31))) + dev_err(qproc->dev, "Failed to enable xo branch clock.\n"); + } /* Enable power block headswitch, and wait for it to stabilize */ - val = readl(qproc->reg_base + QDSP6SS_PWR_CTL_REG); - val |= QDSS_BHS_ON | QDSS_LDO_BYP; - writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG); + val = readl_relaxed(qproc->reg_base + QDSP6SS_PWR_CTL_REG); + val |= QDSP6v56_BHS_ON; + writel_relaxed(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG); udelay(1); - /* - * Turn on memories. L2 banks should be done individually - * to minimize inrush current. - */ - val = readl(qproc->reg_base + QDSP6SS_PWR_CTL_REG); - val |= Q6SS_SLP_RET_N | Q6SS_L2TAG_SLP_NRET_N | - Q6SS_ETB_SLP_NRET_N | Q6SS_L2DATA_STBY_N; - writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG); - val |= Q6SS_L2DATA_SLP_NRET_N_2; - writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG); - val |= Q6SS_L2DATA_SLP_NRET_N_1; - writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG); - val |= Q6SS_L2DATA_SLP_NRET_N_0; - writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG); + /* Put LDO in bypass mode */ + val |= QDSP6v56_LDO_BYP; + writel_relaxed(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG); + + if (!strcmp(qproc->q6_rproc_res->q6_version, "v56")) { + /* + * Deassert QDSP6 compiler memory clamp + */ + val = readl_relaxed(qproc->reg_base + QDSP6SS_PWR_CTL_REG); + val &= ~QDSP6v56_CLAMP_QMC_MEM; + writel_relaxed(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG); + + /* Deassert memory peripheral sleep and L2 memory standby */ + val |= (Q6SS_L2DATA_STBY_N | Q6SS_SLP_RET_N); + writel_relaxed(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG); + /* Turn on L1, L2, ETB and JU memories 1 at a time */ + val = readl_relaxed(qproc->reg_base + QDSP6SS_MEM_PWR_CTL); + for (i = 19; i >= 0; i--) { + val |= BIT(i); + writel_relaxed(val, qproc->reg_base + + QDSP6SS_MEM_PWR_CTL); + /* + * Wait for 1us for both memory peripheral and + * data array to turn on. + */ + mb(); + udelay(1); + } + /* Remove word line clamp */ + val = readl_relaxed(qproc->reg_base + QDSP6SS_PWR_CTL_REG); + val &= ~QDSP6v56_CLAMP_WL; + writel_relaxed(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG); + } else { + /* + * Turn on memories. L2 banks should be done individually + * to minimize inrush current. + */ + val = readl(qproc->reg_base + QDSP6SS_PWR_CTL_REG); + val |= Q6SS_SLP_RET_N | Q6SS_L2TAG_SLP_NRET_N | + Q6SS_ETB_SLP_NRET_N | Q6SS_L2DATA_STBY_N; + writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG); + val |= Q6SS_L2DATA_SLP_NRET_N_2; + writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG); + val |= Q6SS_L2DATA_SLP_NRET_N_1; + writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG); + val |= Q6SS_L2DATA_SLP_NRET_N_0; + writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG); + } /* Remove IO clamp */ val &= ~Q6SS_CLAMP_IO; - writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG); + writel_relaxed(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG); /* Bring core out of reset */ val = readl(qproc->reg_base + QDSP6SS_RESET_REG); @@ -490,9 +554,9 @@ static int q6v5proc_reset(struct q6v5 *qproc) writel(val, qproc->reg_base + QDSP6SS_RESET_REG); /* Turn on core clock */ - val = readl(qproc->reg_base + QDSP6SS_GFMUX_CTL_REG); + val = readl_relaxed(qproc->reg_base + QDSP6SS_GFMUX_CTL_REG); val |= Q6SS_CLK_ENABLE; - writel(val, qproc->reg_base + QDSP6SS_GFMUX_CTL_REG); + writel_relaxed(val, qproc->reg_base + QDSP6SS_GFMUX_CTL_REG); /* Start core execution */ val = readl(qproc->reg_base + QDSP6SS_RESET_REG); @@ -500,7 +564,7 @@ static int q6v5proc_reset(struct q6v5 *qproc) writel(val, qproc->reg_base + QDSP6SS_RESET_REG); /* Wait for PBL status */ - ret = q6v5_rmb_pbl_wait(qproc, 1000); + ret = q6_rmb_pbl_wait(qproc, 1000); if (ret == -ETIMEDOUT) { dev_err(qproc->dev, "PBL boot timed out\n"); } else if (ret != RMB_PBL_SUCCESS) { @@ -560,7 +624,7 @@ static int q6_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw) writel(phys, qproc->rmb_base + RMB_PMI_META_DATA_REG); writel(RMB_CMD_META_DATA_READY, qproc->rmb_base + RMB_MBA_COMMAND_REG); - ret = q6v5_rmb_mba_wait(qproc, RMB_MBA_META_DATA_AUTH_SUCCESS, 1000); + ret = q6_rmb_mba_wait(qproc, RMB_MBA_META_DATA_AUTH_SUCCESS, 1000); if (ret == -ETIMEDOUT) dev_err(qproc->dev, "MPSS header authentication timed out\n"); else if (ret < 0) @@ -618,7 +682,7 @@ static int q6_mpss_validate(struct q6v5 *qproc, const struct firmware *fw) writel(size, qproc->rmb_base + RMB_PMI_CODE_LENGTH_REG); } - ret = q6v5_rmb_mba_wait(qproc, RMB_MBA_AUTH_COMPLETE, 10000); + ret = q6_rmb_mba_wait(qproc, RMB_MBA_AUTH_COMPLETE, 10000); if (ret == -ETIMEDOUT) dev_err(qproc->dev, "MPSS authentication timed out\n"); else if (ret < 0) @@ -704,11 +768,11 @@ static int q6_start(struct rproc *rproc) writel_relaxed(qproc->mba_phys, qproc->rmb_base + RMB_MBA_IMAGE_REG); - ret = q6v5proc_reset(qproc); + ret = q6proc_reset(qproc); if (ret) goto halt_axi_ports; - ret = q6v5_rmb_mba_wait(qproc, 0, 5000); + ret = q6_rmb_mba_wait(qproc, 0, 5000); if (ret == -ETIMEDOUT) { dev_err(qproc->dev, "MBA boot timed out\n"); goto halt_axi_ports; -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.