0001
0002
0003
0004
0005
0006
0007 #include <linux/clk.h>
0008 #include <linux/delay.h>
0009 #include <linux/io.h>
0010 #include <linux/iopoll.h>
0011 #include <linux/kernel.h>
0012 #include <linux/mfd/syscon.h>
0013 #include <linux/module.h>
0014 #include <linux/of_address.h>
0015 #include <linux/of_reserved_mem.h>
0016 #include <linux/platform_device.h>
0017 #include <linux/regmap.h>
0018 #include <linux/regulator/consumer.h>
0019 #include <linux/reset.h>
0020 #include <linux/soc/qcom/mdt_loader.h>
0021 #include "qcom_common.h"
0022 #include "qcom_pil_info.h"
0023 #include "qcom_q6v5.h"
0024
0025 #define WCSS_CRASH_REASON 421
0026
0027
0028 #define Q6SS_RESET_REG 0x014
0029 #define Q6SS_GFMUX_CTL_REG 0x020
0030 #define Q6SS_PWR_CTL_REG 0x030
0031 #define Q6SS_MEM_PWR_CTL 0x0B0
0032 #define Q6SS_STRAP_ACC 0x110
0033 #define Q6SS_CGC_OVERRIDE 0x034
0034 #define Q6SS_BCR_REG 0x6000
0035
0036
0037 #define AXI_HALTREQ_REG 0x0
0038 #define AXI_HALTACK_REG 0x4
0039 #define AXI_IDLE_REG 0x8
0040
0041 #define HALT_ACK_TIMEOUT_MS 100
0042
0043
0044 #define Q6SS_STOP_CORE BIT(0)
0045 #define Q6SS_CORE_ARES BIT(1)
0046 #define Q6SS_BUS_ARES_ENABLE BIT(2)
0047
0048
0049 #define Q6SS_BRC_BLK_ARES BIT(0)
0050
0051
0052 #define Q6SS_CLK_ENABLE BIT(1)
0053 #define Q6SS_SWITCH_CLK_SRC BIT(8)
0054
0055
0056 #define Q6SS_L2DATA_STBY_N BIT(18)
0057 #define Q6SS_SLP_RET_N BIT(19)
0058 #define Q6SS_CLAMP_IO BIT(20)
0059 #define QDSS_BHS_ON BIT(21)
0060 #define QDSS_Q6_MEMORIES GENMASK(15, 0)
0061
0062
0063 #define Q6SS_LDO_BYP BIT(25)
0064 #define Q6SS_BHS_ON BIT(24)
0065 #define Q6SS_CLAMP_WL BIT(21)
0066 #define Q6SS_CLAMP_QMC_MEM BIT(22)
0067 #define HALT_CHECK_MAX_LOOPS 200
0068 #define Q6SS_XO_CBCR GENMASK(5, 3)
0069 #define Q6SS_SLEEP_CBCR GENMASK(5, 2)
0070
0071
0072 #define TCSR_GLOBAL_CFG0 0x0
0073 #define TCSR_GLOBAL_CFG1 0x4
0074 #define SSCAON_CONFIG 0x8
0075 #define SSCAON_STATUS 0xc
0076 #define Q6SS_BHS_STATUS 0x78
0077 #define Q6SS_RST_EVB 0x10
0078
0079 #define BHS_EN_REST_ACK BIT(0)
0080 #define SSCAON_ENABLE BIT(13)
0081 #define SSCAON_BUS_EN BIT(15)
0082 #define SSCAON_BUS_MUX_MASK GENMASK(18, 16)
0083
0084 #define MEM_BANKS 19
0085 #define TCSR_WCSS_CLK_MASK 0x1F
0086 #define TCSR_WCSS_CLK_ENABLE 0x14
0087
0088 #define MAX_HALT_REG 3
0089 enum {
0090 WCSS_IPQ8074,
0091 WCSS_QCS404,
0092 };
0093
0094 struct wcss_data {
0095 const char *firmware_name;
0096 unsigned int crash_reason_smem;
0097 u32 version;
0098 bool aon_reset_required;
0099 bool wcss_q6_reset_required;
0100 const char *ssr_name;
0101 const char *sysmon_name;
0102 int ssctl_id;
0103 const struct rproc_ops *ops;
0104 bool requires_force_stop;
0105 };
0106
0107 struct q6v5_wcss {
0108 struct device *dev;
0109
0110 void __iomem *reg_base;
0111 void __iomem *rmb_base;
0112
0113 struct regmap *halt_map;
0114 u32 halt_q6;
0115 u32 halt_wcss;
0116 u32 halt_nc;
0117
0118 struct clk *xo;
0119 struct clk *ahbfabric_cbcr_clk;
0120 struct clk *gcc_abhs_cbcr;
0121 struct clk *gcc_axim_cbcr;
0122 struct clk *lcc_csr_cbcr;
0123 struct clk *ahbs_cbcr;
0124 struct clk *tcm_slave_cbcr;
0125 struct clk *qdsp6ss_abhm_cbcr;
0126 struct clk *qdsp6ss_sleep_cbcr;
0127 struct clk *qdsp6ss_axim_cbcr;
0128 struct clk *qdsp6ss_xo_cbcr;
0129 struct clk *qdsp6ss_core_gfmux;
0130 struct clk *lcc_bcr_sleep;
0131 struct regulator *cx_supply;
0132 struct qcom_sysmon *sysmon;
0133
0134 struct reset_control *wcss_aon_reset;
0135 struct reset_control *wcss_reset;
0136 struct reset_control *wcss_q6_reset;
0137 struct reset_control *wcss_q6_bcr_reset;
0138
0139 struct qcom_q6v5 q6v5;
0140
0141 phys_addr_t mem_phys;
0142 phys_addr_t mem_reloc;
0143 void *mem_region;
0144 size_t mem_size;
0145
0146 unsigned int crash_reason_smem;
0147 u32 version;
0148 bool requires_force_stop;
0149
0150 struct qcom_rproc_glink glink_subdev;
0151 struct qcom_rproc_ssr ssr_subdev;
0152 };
0153
0154 static int q6v5_wcss_reset(struct q6v5_wcss *wcss)
0155 {
0156 int ret;
0157 u32 val;
0158 int i;
0159
0160
0161 val = readl(wcss->reg_base + Q6SS_RESET_REG);
0162 val |= Q6SS_CORE_ARES | Q6SS_BUS_ARES_ENABLE | Q6SS_STOP_CORE;
0163 writel(val, wcss->reg_base + Q6SS_RESET_REG);
0164
0165
0166 val = readl(wcss->reg_base + Q6SS_XO_CBCR);
0167 val |= 0x1;
0168 writel(val, wcss->reg_base + Q6SS_XO_CBCR);
0169
0170
0171 ret = readl_poll_timeout(wcss->reg_base + Q6SS_XO_CBCR,
0172 val, !(val & BIT(31)), 1,
0173 HALT_CHECK_MAX_LOOPS);
0174 if (ret) {
0175 dev_err(wcss->dev,
0176 "xo cbcr enabling timed out (rc:%d)\n", ret);
0177 return ret;
0178 }
0179
0180 val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
0181 val |= Q6SS_BHS_ON;
0182 writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
0183 udelay(1);
0184
0185
0186 val |= Q6SS_LDO_BYP;
0187 writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
0188
0189
0190 val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
0191 val &= ~Q6SS_CLAMP_QMC_MEM;
0192 writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
0193
0194
0195 val |= Q6SS_L2DATA_STBY_N | Q6SS_SLP_RET_N;
0196 writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
0197
0198
0199 val = readl(wcss->reg_base + Q6SS_MEM_PWR_CTL);
0200 for (i = MEM_BANKS; i >= 0; i--) {
0201 val |= BIT(i);
0202 writel(val, wcss->reg_base + Q6SS_MEM_PWR_CTL);
0203
0204
0205
0206
0207
0208 val |= readl(wcss->reg_base + Q6SS_MEM_PWR_CTL);
0209 udelay(1);
0210 }
0211
0212 val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
0213 val &= ~Q6SS_CLAMP_WL;
0214 writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
0215
0216
0217 val &= ~Q6SS_CLAMP_IO;
0218 writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
0219
0220
0221 val = readl(wcss->reg_base + Q6SS_RESET_REG);
0222 val &= ~Q6SS_CORE_ARES;
0223 writel(val, wcss->reg_base + Q6SS_RESET_REG);
0224
0225
0226 val = readl(wcss->reg_base + Q6SS_GFMUX_CTL_REG);
0227 val |= Q6SS_CLK_ENABLE;
0228 writel(val, wcss->reg_base + Q6SS_GFMUX_CTL_REG);
0229
0230
0231 val = readl(wcss->reg_base + Q6SS_RESET_REG);
0232 val &= ~Q6SS_STOP_CORE;
0233 writel(val, wcss->reg_base + Q6SS_RESET_REG);
0234
0235 return 0;
0236 }
0237
0238 static int q6v5_wcss_start(struct rproc *rproc)
0239 {
0240 struct q6v5_wcss *wcss = rproc->priv;
0241 int ret;
0242
0243 qcom_q6v5_prepare(&wcss->q6v5);
0244
0245
0246 ret = reset_control_deassert(wcss->wcss_reset);
0247 if (ret) {
0248 dev_err(wcss->dev, "wcss_reset failed\n");
0249 return ret;
0250 }
0251
0252 ret = reset_control_deassert(wcss->wcss_q6_reset);
0253 if (ret) {
0254 dev_err(wcss->dev, "wcss_q6_reset failed\n");
0255 goto wcss_reset;
0256 }
0257
0258
0259 ret = regmap_update_bits(wcss->halt_map,
0260 wcss->halt_nc + TCSR_GLOBAL_CFG0,
0261 TCSR_WCSS_CLK_MASK,
0262 TCSR_WCSS_CLK_ENABLE);
0263 if (ret)
0264 goto wcss_q6_reset;
0265
0266 ret = regmap_update_bits(wcss->halt_map,
0267 wcss->halt_nc + TCSR_GLOBAL_CFG1,
0268 1, 0);
0269 if (ret)
0270 goto wcss_q6_reset;
0271
0272
0273 writel(rproc->bootaddr >> 4, wcss->reg_base + Q6SS_RST_EVB);
0274
0275 ret = q6v5_wcss_reset(wcss);
0276 if (ret)
0277 goto wcss_q6_reset;
0278
0279 ret = qcom_q6v5_wait_for_start(&wcss->q6v5, 5 * HZ);
0280 if (ret == -ETIMEDOUT)
0281 dev_err(wcss->dev, "start timed out\n");
0282
0283 return ret;
0284
0285 wcss_q6_reset:
0286 reset_control_assert(wcss->wcss_q6_reset);
0287
0288 wcss_reset:
0289 reset_control_assert(wcss->wcss_reset);
0290
0291 return ret;
0292 }
0293
0294 static int q6v5_wcss_qcs404_power_on(struct q6v5_wcss *wcss)
0295 {
0296 unsigned long val;
0297 int ret, idx;
0298
0299
0300 reset_control_assert(wcss->wcss_reset);
0301 usleep_range(200, 300);
0302 reset_control_deassert(wcss->wcss_reset);
0303 usleep_range(200, 300);
0304
0305
0306 ret = clk_prepare_enable(wcss->gcc_abhs_cbcr);
0307 if (ret)
0308 return ret;
0309
0310
0311 reset_control_deassert(wcss->wcss_q6_bcr_reset);
0312
0313
0314 ret = clk_prepare_enable(wcss->ahbfabric_cbcr_clk);
0315 if (ret)
0316 goto disable_gcc_abhs_cbcr_clk;
0317
0318
0319 ret = clk_prepare_enable(wcss->lcc_csr_cbcr);
0320 if (ret)
0321 goto disable_ahbfabric_cbcr_clk;
0322
0323
0324 ret = clk_prepare_enable(wcss->ahbs_cbcr);
0325 if (ret)
0326 goto disable_csr_cbcr_clk;
0327
0328
0329 ret = clk_prepare_enable(wcss->tcm_slave_cbcr);
0330 if (ret)
0331 goto disable_ahbs_cbcr_clk;
0332
0333
0334 ret = clk_prepare_enable(wcss->qdsp6ss_abhm_cbcr);
0335 if (ret)
0336 goto disable_tcm_slave_cbcr_clk;
0337
0338
0339 ret = clk_prepare_enable(wcss->qdsp6ss_axim_cbcr);
0340 if (ret)
0341 goto disable_abhm_cbcr_clk;
0342
0343
0344 val = readl(wcss->reg_base + Q6SS_XO_CBCR);
0345 val |= BIT(0);
0346 writel(val, wcss->reg_base + Q6SS_XO_CBCR);
0347
0348 ret = readl_poll_timeout(wcss->reg_base + Q6SS_XO_CBCR,
0349 val, !(val & BIT(31)), 1,
0350 HALT_CHECK_MAX_LOOPS);
0351 if (ret) {
0352 dev_err(wcss->dev,
0353 "xo cbcr enabling timed out (rc:%d)\n", ret);
0354 return ret;
0355 }
0356
0357 writel(0, wcss->reg_base + Q6SS_CGC_OVERRIDE);
0358
0359
0360 val = readl(wcss->reg_base + Q6SS_SLEEP_CBCR);
0361 val |= BIT(0);
0362 writel(val, wcss->reg_base + Q6SS_SLEEP_CBCR);
0363
0364
0365 ret = clk_prepare_enable(wcss->gcc_axim_cbcr);
0366 if (ret)
0367 goto disable_sleep_cbcr_clk;
0368
0369
0370 val = readl(wcss->reg_base + Q6SS_RESET_REG);
0371 val |= Q6SS_CORE_ARES | Q6SS_BUS_ARES_ENABLE | Q6SS_STOP_CORE;
0372 writel(val, wcss->reg_base + Q6SS_RESET_REG);
0373
0374
0375 writel(0x01700000, wcss->reg_base + Q6SS_PWR_CTL_REG);
0376
0377 writel(0x03700000, wcss->reg_base + Q6SS_PWR_CTL_REG);
0378
0379 writel(0x03300000, wcss->reg_base + Q6SS_PWR_CTL_REG);
0380
0381 writel(0x033C0000, wcss->reg_base + Q6SS_PWR_CTL_REG);
0382
0383
0384
0385
0386
0387 for (idx = 28; idx >= 0; idx--) {
0388 writel((readl(wcss->reg_base + Q6SS_MEM_PWR_CTL) |
0389 (1 << idx)), wcss->reg_base + Q6SS_MEM_PWR_CTL);
0390 }
0391
0392 writel(0x031C0000, wcss->reg_base + Q6SS_PWR_CTL_REG);
0393 writel(0x030C0000, wcss->reg_base + Q6SS_PWR_CTL_REG);
0394
0395 val = readl(wcss->reg_base + Q6SS_RESET_REG);
0396 val &= ~Q6SS_CORE_ARES;
0397 writel(val, wcss->reg_base + Q6SS_RESET_REG);
0398
0399
0400 val = readl(wcss->reg_base + Q6SS_GFMUX_CTL_REG);
0401 val |= Q6SS_CLK_ENABLE | Q6SS_SWITCH_CLK_SRC;
0402 writel(val, wcss->reg_base + Q6SS_GFMUX_CTL_REG);
0403
0404
0405 ret = clk_prepare_enable(wcss->lcc_bcr_sleep);
0406 if (ret)
0407 goto disable_core_gfmux_clk;
0408
0409 return 0;
0410
0411 disable_core_gfmux_clk:
0412 val = readl(wcss->reg_base + Q6SS_GFMUX_CTL_REG);
0413 val &= ~(Q6SS_CLK_ENABLE | Q6SS_SWITCH_CLK_SRC);
0414 writel(val, wcss->reg_base + Q6SS_GFMUX_CTL_REG);
0415 clk_disable_unprepare(wcss->gcc_axim_cbcr);
0416 disable_sleep_cbcr_clk:
0417 val = readl(wcss->reg_base + Q6SS_SLEEP_CBCR);
0418 val &= ~Q6SS_CLK_ENABLE;
0419 writel(val, wcss->reg_base + Q6SS_SLEEP_CBCR);
0420 val = readl(wcss->reg_base + Q6SS_XO_CBCR);
0421 val &= ~Q6SS_CLK_ENABLE;
0422 writel(val, wcss->reg_base + Q6SS_XO_CBCR);
0423 clk_disable_unprepare(wcss->qdsp6ss_axim_cbcr);
0424 disable_abhm_cbcr_clk:
0425 clk_disable_unprepare(wcss->qdsp6ss_abhm_cbcr);
0426 disable_tcm_slave_cbcr_clk:
0427 clk_disable_unprepare(wcss->tcm_slave_cbcr);
0428 disable_ahbs_cbcr_clk:
0429 clk_disable_unprepare(wcss->ahbs_cbcr);
0430 disable_csr_cbcr_clk:
0431 clk_disable_unprepare(wcss->lcc_csr_cbcr);
0432 disable_ahbfabric_cbcr_clk:
0433 clk_disable_unprepare(wcss->ahbfabric_cbcr_clk);
0434 disable_gcc_abhs_cbcr_clk:
0435 clk_disable_unprepare(wcss->gcc_abhs_cbcr);
0436
0437 return ret;
0438 }
0439
0440 static inline int q6v5_wcss_qcs404_reset(struct q6v5_wcss *wcss)
0441 {
0442 unsigned long val;
0443
0444 writel(0x80800000, wcss->reg_base + Q6SS_STRAP_ACC);
0445
0446
0447 val = readl(wcss->reg_base + Q6SS_RESET_REG);
0448 val &= ~Q6SS_STOP_CORE;
0449 writel(val, wcss->reg_base + Q6SS_RESET_REG);
0450
0451 return 0;
0452 }
0453
0454 static int q6v5_qcs404_wcss_start(struct rproc *rproc)
0455 {
0456 struct q6v5_wcss *wcss = rproc->priv;
0457 int ret;
0458
0459 ret = clk_prepare_enable(wcss->xo);
0460 if (ret)
0461 return ret;
0462
0463 ret = regulator_enable(wcss->cx_supply);
0464 if (ret)
0465 goto disable_xo_clk;
0466
0467 qcom_q6v5_prepare(&wcss->q6v5);
0468
0469 ret = q6v5_wcss_qcs404_power_on(wcss);
0470 if (ret) {
0471 dev_err(wcss->dev, "wcss clk_enable failed\n");
0472 goto disable_cx_supply;
0473 }
0474
0475 writel(rproc->bootaddr >> 4, wcss->reg_base + Q6SS_RST_EVB);
0476
0477 q6v5_wcss_qcs404_reset(wcss);
0478
0479 ret = qcom_q6v5_wait_for_start(&wcss->q6v5, 5 * HZ);
0480 if (ret == -ETIMEDOUT) {
0481 dev_err(wcss->dev, "start timed out\n");
0482 goto disable_cx_supply;
0483 }
0484
0485 return 0;
0486
0487 disable_cx_supply:
0488 regulator_disable(wcss->cx_supply);
0489 disable_xo_clk:
0490 clk_disable_unprepare(wcss->xo);
0491
0492 return ret;
0493 }
0494
0495 static void q6v5_wcss_halt_axi_port(struct q6v5_wcss *wcss,
0496 struct regmap *halt_map,
0497 u32 offset)
0498 {
0499 unsigned long timeout;
0500 unsigned int val;
0501 int ret;
0502
0503
0504 ret = regmap_read(halt_map, offset + AXI_IDLE_REG, &val);
0505 if (!ret && val)
0506 return;
0507
0508
0509 regmap_write(halt_map, offset + AXI_HALTREQ_REG, 1);
0510
0511
0512 timeout = jiffies + msecs_to_jiffies(HALT_ACK_TIMEOUT_MS);
0513 for (;;) {
0514 ret = regmap_read(halt_map, offset + AXI_HALTACK_REG, &val);
0515 if (ret || val || time_after(jiffies, timeout))
0516 break;
0517
0518 msleep(1);
0519 }
0520
0521 ret = regmap_read(halt_map, offset + AXI_IDLE_REG, &val);
0522 if (ret || !val)
0523 dev_err(wcss->dev, "port failed halt\n");
0524
0525
0526 regmap_write(halt_map, offset + AXI_HALTREQ_REG, 0);
0527 }
0528
0529 static int q6v5_qcs404_wcss_shutdown(struct q6v5_wcss *wcss)
0530 {
0531 unsigned long val;
0532 int ret;
0533
0534 q6v5_wcss_halt_axi_port(wcss, wcss->halt_map, wcss->halt_wcss);
0535
0536
0537 val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
0538 val |= (Q6SS_CLAMP_IO | Q6SS_CLAMP_WL | Q6SS_CLAMP_QMC_MEM);
0539 writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
0540
0541
0542 writel((readl(wcss->reg_base + Q6SS_MEM_PWR_CTL) &
0543 ~QDSS_Q6_MEMORIES),
0544 wcss->reg_base + Q6SS_MEM_PWR_CTL);
0545
0546
0547 val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
0548 val &= ~Q6SS_BHS_ON;
0549 writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
0550
0551 clk_disable_unprepare(wcss->ahbfabric_cbcr_clk);
0552 clk_disable_unprepare(wcss->lcc_csr_cbcr);
0553 clk_disable_unprepare(wcss->tcm_slave_cbcr);
0554 clk_disable_unprepare(wcss->qdsp6ss_abhm_cbcr);
0555 clk_disable_unprepare(wcss->qdsp6ss_axim_cbcr);
0556
0557 val = readl(wcss->reg_base + Q6SS_SLEEP_CBCR);
0558 val &= ~BIT(0);
0559 writel(val, wcss->reg_base + Q6SS_SLEEP_CBCR);
0560
0561 val = readl(wcss->reg_base + Q6SS_XO_CBCR);
0562 val &= ~BIT(0);
0563 writel(val, wcss->reg_base + Q6SS_XO_CBCR);
0564
0565 clk_disable_unprepare(wcss->ahbs_cbcr);
0566 clk_disable_unprepare(wcss->lcc_bcr_sleep);
0567
0568 val = readl(wcss->reg_base + Q6SS_GFMUX_CTL_REG);
0569 val &= ~(Q6SS_CLK_ENABLE | Q6SS_SWITCH_CLK_SRC);
0570 writel(val, wcss->reg_base + Q6SS_GFMUX_CTL_REG);
0571
0572 clk_disable_unprepare(wcss->gcc_abhs_cbcr);
0573
0574 ret = reset_control_assert(wcss->wcss_reset);
0575 if (ret) {
0576 dev_err(wcss->dev, "wcss_reset failed\n");
0577 return ret;
0578 }
0579 usleep_range(200, 300);
0580
0581 ret = reset_control_deassert(wcss->wcss_reset);
0582 if (ret) {
0583 dev_err(wcss->dev, "wcss_reset failed\n");
0584 return ret;
0585 }
0586 usleep_range(200, 300);
0587
0588 clk_disable_unprepare(wcss->gcc_axim_cbcr);
0589
0590 return 0;
0591 }
0592
0593 static int q6v5_wcss_powerdown(struct q6v5_wcss *wcss)
0594 {
0595 int ret;
0596 u32 val;
0597
0598
0599 q6v5_wcss_halt_axi_port(wcss, wcss->halt_map, wcss->halt_wcss);
0600
0601
0602 val = readl(wcss->rmb_base + SSCAON_CONFIG);
0603 val |= SSCAON_ENABLE;
0604 writel(val, wcss->rmb_base + SSCAON_CONFIG);
0605
0606
0607 val |= SSCAON_BUS_EN;
0608 val &= ~SSCAON_BUS_MUX_MASK;
0609 writel(val, wcss->rmb_base + SSCAON_CONFIG);
0610
0611
0612 val |= BIT(1);
0613 writel(val, wcss->rmb_base + SSCAON_CONFIG);
0614
0615
0616 ret = readl_poll_timeout(wcss->rmb_base + SSCAON_STATUS,
0617 val, (val & 0xffff) == 0x400, 1000,
0618 HALT_CHECK_MAX_LOOPS);
0619 if (ret) {
0620 dev_err(wcss->dev,
0621 "can't get SSCAON_STATUS rc:%d)\n", ret);
0622 return ret;
0623 }
0624
0625
0626 reset_control_assert(wcss->wcss_aon_reset);
0627
0628
0629 val = readl(wcss->rmb_base + SSCAON_CONFIG);
0630 val &= ~SSCAON_ENABLE;
0631 writel(val, wcss->rmb_base + SSCAON_CONFIG);
0632
0633
0634 reset_control_assert(wcss->wcss_reset);
0635
0636 return 0;
0637 }
0638
0639 static int q6v5_q6_powerdown(struct q6v5_wcss *wcss)
0640 {
0641 int ret;
0642 u32 val;
0643 int i;
0644
0645
0646 q6v5_wcss_halt_axi_port(wcss, wcss->halt_map, wcss->halt_q6);
0647
0648
0649 val = readl(wcss->reg_base + Q6SS_GFMUX_CTL_REG);
0650 val &= ~Q6SS_CLK_ENABLE;
0651 writel(val, wcss->reg_base + Q6SS_GFMUX_CTL_REG);
0652
0653
0654 val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
0655 val |= Q6SS_CLAMP_IO;
0656 writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
0657
0658
0659 val |= QDSS_BHS_ON;
0660 writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
0661
0662
0663 val &= ~Q6SS_L2DATA_STBY_N;
0664 writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
0665
0666
0667 val &= ~Q6SS_SLP_RET_N;
0668 writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
0669
0670
0671 for (i = 0; i < 20; i++) {
0672 val = readl(wcss->reg_base + Q6SS_MEM_PWR_CTL);
0673 val &= ~BIT(i);
0674 writel(val, wcss->reg_base + Q6SS_MEM_PWR_CTL);
0675 mdelay(1);
0676 }
0677
0678
0679 val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
0680 val |= Q6SS_CLAMP_QMC_MEM;
0681 writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
0682
0683
0684 val &= ~Q6SS_BHS_ON;
0685 writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
0686 udelay(1);
0687
0688
0689 ret = readl_poll_timeout(wcss->reg_base + Q6SS_BHS_STATUS,
0690 val, !(val & BHS_EN_REST_ACK), 1000,
0691 HALT_CHECK_MAX_LOOPS);
0692 if (ret) {
0693 dev_err(wcss->dev, "BHS_STATUS not OFF (rc:%d)\n", ret);
0694 return ret;
0695 }
0696
0697
0698 reset_control_assert(wcss->wcss_reset);
0699
0700
0701 reset_control_assert(wcss->wcss_q6_reset);
0702
0703 return 0;
0704 }
0705
0706 static int q6v5_wcss_stop(struct rproc *rproc)
0707 {
0708 struct q6v5_wcss *wcss = rproc->priv;
0709 int ret;
0710
0711
0712 if (wcss->requires_force_stop) {
0713 ret = qcom_q6v5_request_stop(&wcss->q6v5, NULL);
0714 if (ret == -ETIMEDOUT) {
0715 dev_err(wcss->dev, "timed out on wait\n");
0716 return ret;
0717 }
0718 }
0719
0720 if (wcss->version == WCSS_QCS404) {
0721 ret = q6v5_qcs404_wcss_shutdown(wcss);
0722 if (ret)
0723 return ret;
0724 } else {
0725 ret = q6v5_wcss_powerdown(wcss);
0726 if (ret)
0727 return ret;
0728
0729
0730 ret = q6v5_q6_powerdown(wcss);
0731 if (ret)
0732 return ret;
0733 }
0734
0735 qcom_q6v5_unprepare(&wcss->q6v5);
0736
0737 return 0;
0738 }
0739
0740 static void *q6v5_wcss_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem)
0741 {
0742 struct q6v5_wcss *wcss = rproc->priv;
0743 int offset;
0744
0745 offset = da - wcss->mem_reloc;
0746 if (offset < 0 || offset + len > wcss->mem_size)
0747 return NULL;
0748
0749 return wcss->mem_region + offset;
0750 }
0751
0752 static int q6v5_wcss_load(struct rproc *rproc, const struct firmware *fw)
0753 {
0754 struct q6v5_wcss *wcss = rproc->priv;
0755 int ret;
0756
0757 ret = qcom_mdt_load_no_init(wcss->dev, fw, rproc->firmware,
0758 0, wcss->mem_region, wcss->mem_phys,
0759 wcss->mem_size, &wcss->mem_reloc);
0760 if (ret)
0761 return ret;
0762
0763 qcom_pil_info_store("wcnss", wcss->mem_phys, wcss->mem_size);
0764
0765 return ret;
0766 }
0767
0768 static const struct rproc_ops q6v5_wcss_ipq8074_ops = {
0769 .start = q6v5_wcss_start,
0770 .stop = q6v5_wcss_stop,
0771 .da_to_va = q6v5_wcss_da_to_va,
0772 .load = q6v5_wcss_load,
0773 .get_boot_addr = rproc_elf_get_boot_addr,
0774 };
0775
0776 static const struct rproc_ops q6v5_wcss_qcs404_ops = {
0777 .start = q6v5_qcs404_wcss_start,
0778 .stop = q6v5_wcss_stop,
0779 .da_to_va = q6v5_wcss_da_to_va,
0780 .load = q6v5_wcss_load,
0781 .get_boot_addr = rproc_elf_get_boot_addr,
0782 .parse_fw = qcom_register_dump_segments,
0783 };
0784
0785 static int q6v5_wcss_init_reset(struct q6v5_wcss *wcss,
0786 const struct wcss_data *desc)
0787 {
0788 struct device *dev = wcss->dev;
0789
0790 if (desc->aon_reset_required) {
0791 wcss->wcss_aon_reset = devm_reset_control_get_exclusive(dev, "wcss_aon_reset");
0792 if (IS_ERR(wcss->wcss_aon_reset)) {
0793 dev_err(wcss->dev, "fail to acquire wcss_aon_reset\n");
0794 return PTR_ERR(wcss->wcss_aon_reset);
0795 }
0796 }
0797
0798 wcss->wcss_reset = devm_reset_control_get_exclusive(dev, "wcss_reset");
0799 if (IS_ERR(wcss->wcss_reset)) {
0800 dev_err(wcss->dev, "unable to acquire wcss_reset\n");
0801 return PTR_ERR(wcss->wcss_reset);
0802 }
0803
0804 if (desc->wcss_q6_reset_required) {
0805 wcss->wcss_q6_reset = devm_reset_control_get_exclusive(dev, "wcss_q6_reset");
0806 if (IS_ERR(wcss->wcss_q6_reset)) {
0807 dev_err(wcss->dev, "unable to acquire wcss_q6_reset\n");
0808 return PTR_ERR(wcss->wcss_q6_reset);
0809 }
0810 }
0811
0812 wcss->wcss_q6_bcr_reset = devm_reset_control_get_exclusive(dev, "wcss_q6_bcr_reset");
0813 if (IS_ERR(wcss->wcss_q6_bcr_reset)) {
0814 dev_err(wcss->dev, "unable to acquire wcss_q6_bcr_reset\n");
0815 return PTR_ERR(wcss->wcss_q6_bcr_reset);
0816 }
0817
0818 return 0;
0819 }
0820
0821 static int q6v5_wcss_init_mmio(struct q6v5_wcss *wcss,
0822 struct platform_device *pdev)
0823 {
0824 unsigned int halt_reg[MAX_HALT_REG] = {0};
0825 struct device_node *syscon;
0826 struct resource *res;
0827 int ret;
0828
0829 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qdsp6");
0830 wcss->reg_base = devm_ioremap(&pdev->dev, res->start,
0831 resource_size(res));
0832 if (!wcss->reg_base)
0833 return -ENOMEM;
0834
0835 if (wcss->version == WCSS_IPQ8074) {
0836 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rmb");
0837 wcss->rmb_base = devm_ioremap_resource(&pdev->dev, res);
0838 if (IS_ERR(wcss->rmb_base))
0839 return PTR_ERR(wcss->rmb_base);
0840 }
0841
0842 syscon = of_parse_phandle(pdev->dev.of_node,
0843 "qcom,halt-regs", 0);
0844 if (!syscon) {
0845 dev_err(&pdev->dev, "failed to parse qcom,halt-regs\n");
0846 return -EINVAL;
0847 }
0848
0849 wcss->halt_map = syscon_node_to_regmap(syscon);
0850 of_node_put(syscon);
0851 if (IS_ERR(wcss->halt_map))
0852 return PTR_ERR(wcss->halt_map);
0853
0854 ret = of_property_read_variable_u32_array(pdev->dev.of_node,
0855 "qcom,halt-regs",
0856 halt_reg, 0,
0857 MAX_HALT_REG);
0858 if (ret < 0) {
0859 dev_err(&pdev->dev, "failed to parse qcom,halt-regs\n");
0860 return -EINVAL;
0861 }
0862
0863 wcss->halt_q6 = halt_reg[0];
0864 wcss->halt_wcss = halt_reg[1];
0865 wcss->halt_nc = halt_reg[2];
0866
0867 return 0;
0868 }
0869
0870 static int q6v5_alloc_memory_region(struct q6v5_wcss *wcss)
0871 {
0872 struct reserved_mem *rmem = NULL;
0873 struct device_node *node;
0874 struct device *dev = wcss->dev;
0875
0876 node = of_parse_phandle(dev->of_node, "memory-region", 0);
0877 if (node)
0878 rmem = of_reserved_mem_lookup(node);
0879 of_node_put(node);
0880
0881 if (!rmem) {
0882 dev_err(dev, "unable to acquire memory-region\n");
0883 return -EINVAL;
0884 }
0885
0886 wcss->mem_phys = rmem->base;
0887 wcss->mem_reloc = rmem->base;
0888 wcss->mem_size = rmem->size;
0889 wcss->mem_region = devm_ioremap_wc(dev, wcss->mem_phys, wcss->mem_size);
0890 if (!wcss->mem_region) {
0891 dev_err(dev, "unable to map memory region: %pa+%pa\n",
0892 &rmem->base, &rmem->size);
0893 return -EBUSY;
0894 }
0895
0896 return 0;
0897 }
0898
0899 static int q6v5_wcss_init_clock(struct q6v5_wcss *wcss)
0900 {
0901 int ret;
0902
0903 wcss->xo = devm_clk_get(wcss->dev, "xo");
0904 if (IS_ERR(wcss->xo)) {
0905 ret = PTR_ERR(wcss->xo);
0906 if (ret != -EPROBE_DEFER)
0907 dev_err(wcss->dev, "failed to get xo clock");
0908 return ret;
0909 }
0910
0911 wcss->gcc_abhs_cbcr = devm_clk_get(wcss->dev, "gcc_abhs_cbcr");
0912 if (IS_ERR(wcss->gcc_abhs_cbcr)) {
0913 ret = PTR_ERR(wcss->gcc_abhs_cbcr);
0914 if (ret != -EPROBE_DEFER)
0915 dev_err(wcss->dev, "failed to get gcc abhs clock");
0916 return ret;
0917 }
0918
0919 wcss->gcc_axim_cbcr = devm_clk_get(wcss->dev, "gcc_axim_cbcr");
0920 if (IS_ERR(wcss->gcc_axim_cbcr)) {
0921 ret = PTR_ERR(wcss->gcc_axim_cbcr);
0922 if (ret != -EPROBE_DEFER)
0923 dev_err(wcss->dev, "failed to get gcc axim clock\n");
0924 return ret;
0925 }
0926
0927 wcss->ahbfabric_cbcr_clk = devm_clk_get(wcss->dev,
0928 "lcc_ahbfabric_cbc");
0929 if (IS_ERR(wcss->ahbfabric_cbcr_clk)) {
0930 ret = PTR_ERR(wcss->ahbfabric_cbcr_clk);
0931 if (ret != -EPROBE_DEFER)
0932 dev_err(wcss->dev, "failed to get ahbfabric clock\n");
0933 return ret;
0934 }
0935
0936 wcss->lcc_csr_cbcr = devm_clk_get(wcss->dev, "tcsr_lcc_cbc");
0937 if (IS_ERR(wcss->lcc_csr_cbcr)) {
0938 ret = PTR_ERR(wcss->lcc_csr_cbcr);
0939 if (ret != -EPROBE_DEFER)
0940 dev_err(wcss->dev, "failed to get csr cbcr clk\n");
0941 return ret;
0942 }
0943
0944 wcss->ahbs_cbcr = devm_clk_get(wcss->dev,
0945 "lcc_abhs_cbc");
0946 if (IS_ERR(wcss->ahbs_cbcr)) {
0947 ret = PTR_ERR(wcss->ahbs_cbcr);
0948 if (ret != -EPROBE_DEFER)
0949 dev_err(wcss->dev, "failed to get ahbs_cbcr clk\n");
0950 return ret;
0951 }
0952
0953 wcss->tcm_slave_cbcr = devm_clk_get(wcss->dev,
0954 "lcc_tcm_slave_cbc");
0955 if (IS_ERR(wcss->tcm_slave_cbcr)) {
0956 ret = PTR_ERR(wcss->tcm_slave_cbcr);
0957 if (ret != -EPROBE_DEFER)
0958 dev_err(wcss->dev, "failed to get tcm cbcr clk\n");
0959 return ret;
0960 }
0961
0962 wcss->qdsp6ss_abhm_cbcr = devm_clk_get(wcss->dev, "lcc_abhm_cbc");
0963 if (IS_ERR(wcss->qdsp6ss_abhm_cbcr)) {
0964 ret = PTR_ERR(wcss->qdsp6ss_abhm_cbcr);
0965 if (ret != -EPROBE_DEFER)
0966 dev_err(wcss->dev, "failed to get abhm cbcr clk\n");
0967 return ret;
0968 }
0969
0970 wcss->qdsp6ss_axim_cbcr = devm_clk_get(wcss->dev, "lcc_axim_cbc");
0971 if (IS_ERR(wcss->qdsp6ss_axim_cbcr)) {
0972 ret = PTR_ERR(wcss->qdsp6ss_axim_cbcr);
0973 if (ret != -EPROBE_DEFER)
0974 dev_err(wcss->dev, "failed to get axim cbcr clk\n");
0975 return ret;
0976 }
0977
0978 wcss->lcc_bcr_sleep = devm_clk_get(wcss->dev, "lcc_bcr_sleep");
0979 if (IS_ERR(wcss->lcc_bcr_sleep)) {
0980 ret = PTR_ERR(wcss->lcc_bcr_sleep);
0981 if (ret != -EPROBE_DEFER)
0982 dev_err(wcss->dev, "failed to get bcr cbcr clk\n");
0983 return ret;
0984 }
0985
0986 return 0;
0987 }
0988
0989 static int q6v5_wcss_init_regulator(struct q6v5_wcss *wcss)
0990 {
0991 wcss->cx_supply = devm_regulator_get(wcss->dev, "cx");
0992 if (IS_ERR(wcss->cx_supply))
0993 return PTR_ERR(wcss->cx_supply);
0994
0995 regulator_set_load(wcss->cx_supply, 100000);
0996
0997 return 0;
0998 }
0999
1000 static int q6v5_wcss_probe(struct platform_device *pdev)
1001 {
1002 const struct wcss_data *desc;
1003 struct q6v5_wcss *wcss;
1004 struct rproc *rproc;
1005 int ret;
1006
1007 desc = device_get_match_data(&pdev->dev);
1008 if (!desc)
1009 return -EINVAL;
1010
1011 rproc = rproc_alloc(&pdev->dev, pdev->name, desc->ops,
1012 desc->firmware_name, sizeof(*wcss));
1013 if (!rproc) {
1014 dev_err(&pdev->dev, "failed to allocate rproc\n");
1015 return -ENOMEM;
1016 }
1017
1018 wcss = rproc->priv;
1019 wcss->dev = &pdev->dev;
1020 wcss->version = desc->version;
1021
1022 wcss->version = desc->version;
1023 wcss->requires_force_stop = desc->requires_force_stop;
1024
1025 ret = q6v5_wcss_init_mmio(wcss, pdev);
1026 if (ret)
1027 goto free_rproc;
1028
1029 ret = q6v5_alloc_memory_region(wcss);
1030 if (ret)
1031 goto free_rproc;
1032
1033 if (wcss->version == WCSS_QCS404) {
1034 ret = q6v5_wcss_init_clock(wcss);
1035 if (ret)
1036 goto free_rproc;
1037
1038 ret = q6v5_wcss_init_regulator(wcss);
1039 if (ret)
1040 goto free_rproc;
1041 }
1042
1043 ret = q6v5_wcss_init_reset(wcss, desc);
1044 if (ret)
1045 goto free_rproc;
1046
1047 ret = qcom_q6v5_init(&wcss->q6v5, pdev, rproc, desc->crash_reason_smem, NULL, NULL);
1048 if (ret)
1049 goto free_rproc;
1050
1051 qcom_add_glink_subdev(rproc, &wcss->glink_subdev, "q6wcss");
1052 qcom_add_ssr_subdev(rproc, &wcss->ssr_subdev, "q6wcss");
1053
1054 if (desc->ssctl_id)
1055 wcss->sysmon = qcom_add_sysmon_subdev(rproc,
1056 desc->sysmon_name,
1057 desc->ssctl_id);
1058
1059 ret = rproc_add(rproc);
1060 if (ret)
1061 goto free_rproc;
1062
1063 platform_set_drvdata(pdev, rproc);
1064
1065 return 0;
1066
1067 free_rproc:
1068 rproc_free(rproc);
1069
1070 return ret;
1071 }
1072
1073 static int q6v5_wcss_remove(struct platform_device *pdev)
1074 {
1075 struct rproc *rproc = platform_get_drvdata(pdev);
1076 struct q6v5_wcss *wcss = rproc->priv;
1077
1078 qcom_q6v5_deinit(&wcss->q6v5);
1079 rproc_del(rproc);
1080 rproc_free(rproc);
1081
1082 return 0;
1083 }
1084
1085 static const struct wcss_data wcss_ipq8074_res_init = {
1086 .firmware_name = "IPQ8074/q6_fw.mdt",
1087 .crash_reason_smem = WCSS_CRASH_REASON,
1088 .aon_reset_required = true,
1089 .wcss_q6_reset_required = true,
1090 .ops = &q6v5_wcss_ipq8074_ops,
1091 .requires_force_stop = true,
1092 };
1093
1094 static const struct wcss_data wcss_qcs404_res_init = {
1095 .crash_reason_smem = WCSS_CRASH_REASON,
1096 .firmware_name = "wcnss.mdt",
1097 .version = WCSS_QCS404,
1098 .aon_reset_required = false,
1099 .wcss_q6_reset_required = false,
1100 .ssr_name = "mpss",
1101 .sysmon_name = "wcnss",
1102 .ssctl_id = 0x12,
1103 .ops = &q6v5_wcss_qcs404_ops,
1104 .requires_force_stop = false,
1105 };
1106
1107 static const struct of_device_id q6v5_wcss_of_match[] = {
1108 { .compatible = "qcom,ipq8074-wcss-pil", .data = &wcss_ipq8074_res_init },
1109 { .compatible = "qcom,qcs404-wcss-pil", .data = &wcss_qcs404_res_init },
1110 { },
1111 };
1112 MODULE_DEVICE_TABLE(of, q6v5_wcss_of_match);
1113
1114 static struct platform_driver q6v5_wcss_driver = {
1115 .probe = q6v5_wcss_probe,
1116 .remove = q6v5_wcss_remove,
1117 .driver = {
1118 .name = "qcom-q6v5-wcss-pil",
1119 .of_match_table = q6v5_wcss_of_match,
1120 },
1121 };
1122 module_platform_driver(q6v5_wcss_driver);
1123
1124 MODULE_DESCRIPTION("Hexagon WCSS Peripheral Image Loader");
1125 MODULE_LICENSE("GPL v2");