This change introduces appropriate additional steps in reset sequence so that hexagon v56 1.5.0 is brough out of reset. Signed-off-by: Avaneesh Kumar Dwivedi <akdwived@xxxxxxxxxxxxxx> --- drivers/remoteproc/qcom_q6v5_pil.c | 125 ++++++++++++++++++++++++++++++------- 1 file changed, 104 insertions(+), 21 deletions(-) diff --git a/drivers/remoteproc/qcom_q6v5_pil.c b/drivers/remoteproc/qcom_q6v5_pil.c index c55dc9a..7ea2f53 100644 --- a/drivers/remoteproc/qcom_q6v5_pil.c +++ b/drivers/remoteproc/qcom_q6v5_pil.c @@ -65,6 +65,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 @@ -93,6 +95,15 @@ #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 rproc_hexagon_res { char *hexagon_mba_image; char **proxy_reg_string; @@ -147,6 +158,8 @@ struct q6v5 { phys_addr_t mpss_reloc; void *mpss_region; size_t mpss_size; + + int hexagon_ver; }; enum { @@ -388,35 +401,103 @@ static int q6v5_rmb_mba_wait(struct q6v5 *qproc, u32 status, int ms) static int q6v5proc_reset(struct q6v5 *qproc) { - u32 val; - int ret; + u64 val; + int ret, i, count; + + /* Override the ACC value if required */ + if (qproc->hexagon_ver & 0x2) + 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 |= (Q6SS_CORE_ARES | Q6SS_BUS_ARES_ENABLE | Q6SS_STOP_CORE); writel(val, qproc->reg_base + QDSP6SS_RESET_REG); + /* BHS require xo cbcr to be enabled */ + if (qproc->hexagon_ver & 0x2) { + 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"); + } + + if (qproc->hexagon_ver & 0x2) { /* 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); - 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); + 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); + /* Put LDO in bypass mode */ + val |= QDSP6v56_LDO_BYP; + writel_relaxed(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG); + + } else { + /* + * 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); + udelay(1); + } + + if (qproc->hexagon_ver & 0x2) { + /* + * 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); @@ -1031,6 +1112,8 @@ static int q6v5_probe(struct platform_device *pdev) } qproc->active_reg_count = count; + qproc->hexagon_ver = desc->hexagon_ver; + ret = q6v5_request_irq(qproc, pdev, "wdog", q6v5_wdog_interrupt); if (ret < 0) goto free_rproc; -- Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project. -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html