^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (C) 2016-2018 Linaro Ltd.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (C) 2014 Sony Mobile Communications AB
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/iopoll.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/mfd/syscon.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/of_reserved_mem.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/regmap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/reset.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/soc/qcom/mdt_loader.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include "qcom_common.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include "qcom_pil_info.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include "qcom_q6v5.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #define WCSS_CRASH_REASON 421
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) /* Q6SS Register Offsets */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define Q6SS_RESET_REG 0x014
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define Q6SS_GFMUX_CTL_REG 0x020
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define Q6SS_PWR_CTL_REG 0x030
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define Q6SS_MEM_PWR_CTL 0x0B0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) /* AXI Halt Register Offsets */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define AXI_HALTREQ_REG 0x0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #define AXI_HALTACK_REG 0x4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #define AXI_IDLE_REG 0x8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define HALT_ACK_TIMEOUT_MS 100
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) /* Q6SS_RESET */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define Q6SS_STOP_CORE BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define Q6SS_CORE_ARES BIT(1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define Q6SS_BUS_ARES_ENABLE BIT(2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) /* Q6SS_GFMUX_CTL */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #define Q6SS_CLK_ENABLE BIT(1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) /* Q6SS_PWR_CTL */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #define Q6SS_L2DATA_STBY_N BIT(18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #define Q6SS_SLP_RET_N BIT(19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #define Q6SS_CLAMP_IO BIT(20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #define QDSS_BHS_ON BIT(21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) /* Q6SS parameters */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) #define Q6SS_LDO_BYP BIT(25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) #define Q6SS_BHS_ON BIT(24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) #define Q6SS_CLAMP_WL BIT(21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) #define Q6SS_CLAMP_QMC_MEM BIT(22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) #define HALT_CHECK_MAX_LOOPS 200
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) #define Q6SS_XO_CBCR GENMASK(5, 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) /* Q6SS config/status registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) #define TCSR_GLOBAL_CFG0 0x0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) #define TCSR_GLOBAL_CFG1 0x4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) #define SSCAON_CONFIG 0x8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) #define SSCAON_STATUS 0xc
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) #define Q6SS_BHS_STATUS 0x78
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) #define Q6SS_RST_EVB 0x10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) #define BHS_EN_REST_ACK BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) #define SSCAON_ENABLE BIT(13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) #define SSCAON_BUS_EN BIT(15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) #define SSCAON_BUS_MUX_MASK GENMASK(18, 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) #define MEM_BANKS 19
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) #define TCSR_WCSS_CLK_MASK 0x1F
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) #define TCSR_WCSS_CLK_ENABLE 0x14
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) struct q6v5_wcss {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) struct device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) void __iomem *reg_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) void __iomem *rmb_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) struct regmap *halt_map;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) u32 halt_q6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) u32 halt_wcss;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) u32 halt_nc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) struct reset_control *wcss_aon_reset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) struct reset_control *wcss_reset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) struct reset_control *wcss_q6_reset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) struct qcom_q6v5 q6v5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) phys_addr_t mem_phys;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) phys_addr_t mem_reloc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) void *mem_region;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) size_t mem_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) struct qcom_rproc_glink glink_subdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) struct qcom_rproc_ssr ssr_subdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) static int q6v5_wcss_reset(struct q6v5_wcss *wcss)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) /* Assert resets, stop core */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) val = readl(wcss->reg_base + Q6SS_RESET_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) val |= Q6SS_CORE_ARES | Q6SS_BUS_ARES_ENABLE | Q6SS_STOP_CORE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) writel(val, wcss->reg_base + Q6SS_RESET_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) /* BHS require xo cbcr to be enabled */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) val = readl(wcss->reg_base + Q6SS_XO_CBCR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) val |= 0x1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) writel(val, wcss->reg_base + Q6SS_XO_CBCR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) /* Read CLKOFF bit to go low indicating CLK is enabled */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) ret = readl_poll_timeout(wcss->reg_base + Q6SS_XO_CBCR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) val, !(val & BIT(31)), 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) HALT_CHECK_MAX_LOOPS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) dev_err(wcss->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) "xo cbcr enabling timed out (rc:%d)\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) /* Enable power block headswitch and wait for it to stabilize */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) val |= Q6SS_BHS_ON;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) udelay(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) /* Put LDO in bypass mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) val |= Q6SS_LDO_BYP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) /* Deassert Q6 compiler memory clamp */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) val &= ~Q6SS_CLAMP_QMC_MEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) /* Deassert memory peripheral sleep and L2 memory standby */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) val |= Q6SS_L2DATA_STBY_N | Q6SS_SLP_RET_N;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) /* Turn on L1, L2, ETB and JU memories 1 at a time */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) val = readl(wcss->reg_base + Q6SS_MEM_PWR_CTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) for (i = MEM_BANKS; i >= 0; i--) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) val |= BIT(i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) writel(val, wcss->reg_base + Q6SS_MEM_PWR_CTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) * Read back value to ensure the write is done then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) * wait for 1us for both memory peripheral and data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) * array to turn on.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) val |= readl(wcss->reg_base + Q6SS_MEM_PWR_CTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) udelay(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) /* Remove word line clamp */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) val &= ~Q6SS_CLAMP_WL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) /* Remove IO clamp */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) val &= ~Q6SS_CLAMP_IO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) /* Bring core out of reset */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) val = readl(wcss->reg_base + Q6SS_RESET_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) val &= ~Q6SS_CORE_ARES;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) writel(val, wcss->reg_base + Q6SS_RESET_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) /* Turn on core clock */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) val = readl(wcss->reg_base + Q6SS_GFMUX_CTL_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) val |= Q6SS_CLK_ENABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) writel(val, wcss->reg_base + Q6SS_GFMUX_CTL_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) /* Start core execution */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) val = readl(wcss->reg_base + Q6SS_RESET_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) val &= ~Q6SS_STOP_CORE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) writel(val, wcss->reg_base + Q6SS_RESET_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) static int q6v5_wcss_start(struct rproc *rproc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) struct q6v5_wcss *wcss = rproc->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) qcom_q6v5_prepare(&wcss->q6v5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) /* Release Q6 and WCSS reset */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) ret = reset_control_deassert(wcss->wcss_reset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) dev_err(wcss->dev, "wcss_reset failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) ret = reset_control_deassert(wcss->wcss_q6_reset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) dev_err(wcss->dev, "wcss_q6_reset failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) goto wcss_reset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) /* Lithium configuration - clock gating and bus arbitration */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) ret = regmap_update_bits(wcss->halt_map,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) wcss->halt_nc + TCSR_GLOBAL_CFG0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) TCSR_WCSS_CLK_MASK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) TCSR_WCSS_CLK_ENABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) goto wcss_q6_reset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) ret = regmap_update_bits(wcss->halt_map,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) wcss->halt_nc + TCSR_GLOBAL_CFG1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) 1, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) goto wcss_q6_reset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) /* Write bootaddr to EVB so that Q6WCSS will jump there after reset */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) writel(rproc->bootaddr >> 4, wcss->reg_base + Q6SS_RST_EVB);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) ret = q6v5_wcss_reset(wcss);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) goto wcss_q6_reset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) ret = qcom_q6v5_wait_for_start(&wcss->q6v5, 5 * HZ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) if (ret == -ETIMEDOUT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) dev_err(wcss->dev, "start timed out\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) wcss_q6_reset:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) reset_control_assert(wcss->wcss_q6_reset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) wcss_reset:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) reset_control_assert(wcss->wcss_reset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) static void q6v5_wcss_halt_axi_port(struct q6v5_wcss *wcss,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) struct regmap *halt_map,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) u32 offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) unsigned long timeout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) unsigned int val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) /* Check if we're already idle */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) ret = regmap_read(halt_map, offset + AXI_IDLE_REG, &val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) if (!ret && val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) /* Assert halt request */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) regmap_write(halt_map, offset + AXI_HALTREQ_REG, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) /* Wait for halt */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) timeout = jiffies + msecs_to_jiffies(HALT_ACK_TIMEOUT_MS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) for (;;) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) ret = regmap_read(halt_map, offset + AXI_HALTACK_REG, &val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) if (ret || val || time_after(jiffies, timeout))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) msleep(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) ret = regmap_read(halt_map, offset + AXI_IDLE_REG, &val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) if (ret || !val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) dev_err(wcss->dev, "port failed halt\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) /* Clear halt request (port will remain halted until reset) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) regmap_write(halt_map, offset + AXI_HALTREQ_REG, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) static int q6v5_wcss_powerdown(struct q6v5_wcss *wcss)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) /* 1 - Assert WCSS/Q6 HALTREQ */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) q6v5_wcss_halt_axi_port(wcss, wcss->halt_map, wcss->halt_wcss);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) /* 2 - Enable WCSSAON_CONFIG */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) val = readl(wcss->rmb_base + SSCAON_CONFIG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) val |= SSCAON_ENABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) writel(val, wcss->rmb_base + SSCAON_CONFIG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) /* 3 - Set SSCAON_CONFIG */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) val |= SSCAON_BUS_EN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) val &= ~SSCAON_BUS_MUX_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) writel(val, wcss->rmb_base + SSCAON_CONFIG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) /* 4 - SSCAON_CONFIG 1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) val |= BIT(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) writel(val, wcss->rmb_base + SSCAON_CONFIG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) /* 5 - wait for SSCAON_STATUS */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) ret = readl_poll_timeout(wcss->rmb_base + SSCAON_STATUS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) val, (val & 0xffff) == 0x400, 1000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) HALT_CHECK_MAX_LOOPS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) dev_err(wcss->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) "can't get SSCAON_STATUS rc:%d)\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) /* 6 - De-assert WCSS_AON reset */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) reset_control_assert(wcss->wcss_aon_reset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) /* 7 - Disable WCSSAON_CONFIG 13 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) val = readl(wcss->rmb_base + SSCAON_CONFIG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) val &= ~SSCAON_ENABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) writel(val, wcss->rmb_base + SSCAON_CONFIG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) /* 8 - De-assert WCSS/Q6 HALTREQ */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) reset_control_assert(wcss->wcss_reset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) static int q6v5_q6_powerdown(struct q6v5_wcss *wcss)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) /* 1 - Halt Q6 bus interface */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) q6v5_wcss_halt_axi_port(wcss, wcss->halt_map, wcss->halt_q6);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) /* 2 - Disable Q6 Core clock */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) val = readl(wcss->reg_base + Q6SS_GFMUX_CTL_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) val &= ~Q6SS_CLK_ENABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) writel(val, wcss->reg_base + Q6SS_GFMUX_CTL_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) /* 3 - Clamp I/O */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) val |= Q6SS_CLAMP_IO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) /* 4 - Clamp WL */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) val |= QDSS_BHS_ON;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) /* 5 - Clear Erase standby */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) val &= ~Q6SS_L2DATA_STBY_N;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) /* 6 - Clear Sleep RTN */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) val &= ~Q6SS_SLP_RET_N;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) /* 7 - turn off Q6 memory foot/head switch one bank at a time */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) for (i = 0; i < 20; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) val = readl(wcss->reg_base + Q6SS_MEM_PWR_CTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) val &= ~BIT(i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) writel(val, wcss->reg_base + Q6SS_MEM_PWR_CTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) mdelay(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) /* 8 - Assert QMC memory RTN */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) val |= Q6SS_CLAMP_QMC_MEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) /* 9 - Turn off BHS */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) val &= ~Q6SS_BHS_ON;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) udelay(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) /* 10 - Wait till BHS Reset is done */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) ret = readl_poll_timeout(wcss->reg_base + Q6SS_BHS_STATUS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) val, !(val & BHS_EN_REST_ACK), 1000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) HALT_CHECK_MAX_LOOPS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) dev_err(wcss->dev, "BHS_STATUS not OFF (rc:%d)\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) /* 11 - Assert WCSS reset */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) reset_control_assert(wcss->wcss_reset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) /* 12 - Assert Q6 reset */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) reset_control_assert(wcss->wcss_q6_reset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) static int q6v5_wcss_stop(struct rproc *rproc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) struct q6v5_wcss *wcss = rproc->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) /* WCSS powerdown */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) ret = qcom_q6v5_request_stop(&wcss->q6v5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) if (ret == -ETIMEDOUT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) dev_err(wcss->dev, "timed out on wait\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) ret = q6v5_wcss_powerdown(wcss);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) /* Q6 Power down */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) ret = q6v5_q6_powerdown(wcss);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) qcom_q6v5_unprepare(&wcss->q6v5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) static void *q6v5_wcss_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) struct q6v5_wcss *wcss = rproc->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) int offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) offset = da - wcss->mem_reloc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) if (offset < 0 || offset + len > wcss->mem_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) return wcss->mem_region + offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) static int q6v5_wcss_load(struct rproc *rproc, const struct firmware *fw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) struct q6v5_wcss *wcss = rproc->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) ret = qcom_mdt_load_no_init(wcss->dev, fw, rproc->firmware,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) 0, wcss->mem_region, wcss->mem_phys,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) wcss->mem_size, &wcss->mem_reloc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) qcom_pil_info_store("wcnss", wcss->mem_phys, wcss->mem_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) static const struct rproc_ops q6v5_wcss_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) .start = q6v5_wcss_start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) .stop = q6v5_wcss_stop,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) .da_to_va = q6v5_wcss_da_to_va,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) .load = q6v5_wcss_load,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) .get_boot_addr = rproc_elf_get_boot_addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) static int q6v5_wcss_init_reset(struct q6v5_wcss *wcss)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) struct device *dev = wcss->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) wcss->wcss_aon_reset = devm_reset_control_get(dev, "wcss_aon_reset");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) if (IS_ERR(wcss->wcss_aon_reset)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) dev_err(wcss->dev, "unable to acquire wcss_aon_reset\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) return PTR_ERR(wcss->wcss_aon_reset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) wcss->wcss_reset = devm_reset_control_get(dev, "wcss_reset");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) if (IS_ERR(wcss->wcss_reset)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) dev_err(wcss->dev, "unable to acquire wcss_reset\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) return PTR_ERR(wcss->wcss_reset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) wcss->wcss_q6_reset = devm_reset_control_get(dev, "wcss_q6_reset");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) if (IS_ERR(wcss->wcss_q6_reset)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) dev_err(wcss->dev, "unable to acquire wcss_q6_reset\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) return PTR_ERR(wcss->wcss_q6_reset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) static int q6v5_wcss_init_mmio(struct q6v5_wcss *wcss,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) struct of_phandle_args args;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) struct resource *res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qdsp6");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) wcss->reg_base = devm_ioremap_resource(&pdev->dev, res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) if (IS_ERR(wcss->reg_base))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) return PTR_ERR(wcss->reg_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rmb");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) wcss->rmb_base = devm_ioremap_resource(&pdev->dev, res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) if (IS_ERR(wcss->rmb_base))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) return PTR_ERR(wcss->rmb_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) "qcom,halt-regs", 3, 0, &args);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) dev_err(&pdev->dev, "failed to parse qcom,halt-regs\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) wcss->halt_map = syscon_node_to_regmap(args.np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) of_node_put(args.np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) if (IS_ERR(wcss->halt_map))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) return PTR_ERR(wcss->halt_map);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) wcss->halt_q6 = args.args[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) wcss->halt_wcss = args.args[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) wcss->halt_nc = args.args[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) static int q6v5_alloc_memory_region(struct q6v5_wcss *wcss)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) struct reserved_mem *rmem = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) struct device_node *node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) struct device *dev = wcss->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) node = of_parse_phandle(dev->of_node, "memory-region", 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) if (node)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) rmem = of_reserved_mem_lookup(node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) of_node_put(node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) if (!rmem) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) dev_err(dev, "unable to acquire memory-region\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) wcss->mem_phys = rmem->base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) wcss->mem_reloc = rmem->base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) wcss->mem_size = rmem->size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) wcss->mem_region = devm_ioremap_wc(dev, wcss->mem_phys, wcss->mem_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) if (!wcss->mem_region) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) dev_err(dev, "unable to map memory region: %pa+%pa\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) &rmem->base, &rmem->size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) static int q6v5_wcss_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) struct q6v5_wcss *wcss;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) struct rproc *rproc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) rproc = rproc_alloc(&pdev->dev, pdev->name, &q6v5_wcss_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) "IPQ8074/q6_fw.mdt", sizeof(*wcss));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) if (!rproc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) dev_err(&pdev->dev, "failed to allocate rproc\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) wcss = rproc->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) wcss->dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) ret = q6v5_wcss_init_mmio(wcss, pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) goto free_rproc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) ret = q6v5_alloc_memory_region(wcss);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) goto free_rproc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) ret = q6v5_wcss_init_reset(wcss);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) goto free_rproc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) ret = qcom_q6v5_init(&wcss->q6v5, pdev, rproc, WCSS_CRASH_REASON, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) goto free_rproc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) qcom_add_glink_subdev(rproc, &wcss->glink_subdev, "q6wcss");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) qcom_add_ssr_subdev(rproc, &wcss->ssr_subdev, "q6wcss");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) ret = rproc_add(rproc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) goto free_rproc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) platform_set_drvdata(pdev, rproc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) free_rproc:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) rproc_free(rproc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) static int q6v5_wcss_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) struct rproc *rproc = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) rproc_del(rproc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) rproc_free(rproc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) static const struct of_device_id q6v5_wcss_of_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) { .compatible = "qcom,ipq8074-wcss-pil" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) { },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) MODULE_DEVICE_TABLE(of, q6v5_wcss_of_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) static struct platform_driver q6v5_wcss_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) .probe = q6v5_wcss_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) .remove = q6v5_wcss_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) .name = "qcom-q6v5-wcss-pil",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) .of_match_table = q6v5_wcss_of_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) module_platform_driver(q6v5_wcss_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) MODULE_DESCRIPTION("Hexagon WCSS Peripheral Image Loader");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) MODULE_LICENSE("GPL v2");