1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2016-2018 Linaro Ltd.
4 * Copyright (C) 2014 Sony Mobile Communications AB
5 * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
7 #include <linux/iopoll.h>
8 #include <linux/kernel.h>
9 #include <linux/mfd/syscon.h>
10 #include <linux/module.h>
11 #include <linux/of_reserved_mem.h>
12 #include <linux/platform_device.h>
13 #include <linux/regmap.h>
14 #include <linux/reset.h>
15 #include <linux/soc/qcom/mdt_loader.h>
16 #include "qcom_common.h"
17 #include "qcom_q6v5.h"
19 #define WCSS_CRASH_REASON 421
21 /* Q6SS Register Offsets */
22 #define Q6SS_RESET_REG 0x014
23 #define Q6SS_GFMUX_CTL_REG 0x020
24 #define Q6SS_PWR_CTL_REG 0x030
25 #define Q6SS_MEM_PWR_CTL 0x0B0
27 /* AXI Halt Register Offsets */
28 #define AXI_HALTREQ_REG 0x0
29 #define AXI_HALTACK_REG 0x4
30 #define AXI_IDLE_REG 0x8
32 #define HALT_ACK_TIMEOUT_MS 100
35 #define Q6SS_STOP_CORE BIT(0)
36 #define Q6SS_CORE_ARES BIT(1)
37 #define Q6SS_BUS_ARES_ENABLE BIT(2)
40 #define Q6SS_CLK_ENABLE BIT(1)
43 #define Q6SS_L2DATA_STBY_N BIT(18)
44 #define Q6SS_SLP_RET_N BIT(19)
45 #define Q6SS_CLAMP_IO BIT(20)
46 #define QDSS_BHS_ON BIT(21)
49 #define Q6SS_LDO_BYP BIT(25)
50 #define Q6SS_BHS_ON BIT(24)
51 #define Q6SS_CLAMP_WL BIT(21)
52 #define Q6SS_CLAMP_QMC_MEM BIT(22)
53 #define HALT_CHECK_MAX_LOOPS 200
54 #define Q6SS_XO_CBCR GENMASK(5, 3)
56 /* Q6SS config/status registers */
57 #define TCSR_GLOBAL_CFG0 0x0
58 #define TCSR_GLOBAL_CFG1 0x4
59 #define SSCAON_CONFIG 0x8
60 #define SSCAON_STATUS 0xc
61 #define Q6SS_BHS_STATUS 0x78
62 #define Q6SS_RST_EVB 0x10
64 #define BHS_EN_REST_ACK BIT(0)
65 #define SSCAON_ENABLE BIT(13)
66 #define SSCAON_BUS_EN BIT(15)
67 #define SSCAON_BUS_MUX_MASK GENMASK(18, 16)
70 #define TCSR_WCSS_CLK_MASK 0x1F
71 #define TCSR_WCSS_CLK_ENABLE 0x14
76 void __iomem *reg_base;
77 void __iomem *rmb_base;
79 struct regmap *halt_map;
84 struct reset_control *wcss_aon_reset;
85 struct reset_control *wcss_reset;
86 struct reset_control *wcss_q6_reset;
88 struct qcom_q6v5 q6v5;
91 phys_addr_t mem_reloc;
95 struct qcom_rproc_glink glink_subdev;
96 struct qcom_rproc_ssr ssr_subdev;
99 static int q6v5_wcss_reset(struct q6v5_wcss *wcss)
105 /* Assert resets, stop core */
106 val = readl(wcss->reg_base + Q6SS_RESET_REG);
107 val |= Q6SS_CORE_ARES | Q6SS_BUS_ARES_ENABLE | Q6SS_STOP_CORE;
108 writel(val, wcss->reg_base + Q6SS_RESET_REG);
110 /* BHS require xo cbcr to be enabled */
111 val = readl(wcss->reg_base + Q6SS_XO_CBCR);
113 writel(val, wcss->reg_base + Q6SS_XO_CBCR);
115 /* Read CLKOFF bit to go low indicating CLK is enabled */
116 ret = readl_poll_timeout(wcss->reg_base + Q6SS_XO_CBCR,
117 val, !(val & BIT(31)), 1,
118 HALT_CHECK_MAX_LOOPS);
121 "xo cbcr enabling timed out (rc:%d)\n", ret);
124 /* Enable power block headswitch and wait for it to stabilize */
125 val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
127 writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
130 /* Put LDO in bypass mode */
132 writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
134 /* Deassert Q6 compiler memory clamp */
135 val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
136 val &= ~Q6SS_CLAMP_QMC_MEM;
137 writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
139 /* Deassert memory peripheral sleep and L2 memory standby */
140 val |= Q6SS_L2DATA_STBY_N | Q6SS_SLP_RET_N;
141 writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
143 /* Turn on L1, L2, ETB and JU memories 1 at a time */
144 val = readl(wcss->reg_base + Q6SS_MEM_PWR_CTL);
145 for (i = MEM_BANKS; i >= 0; i--) {
147 writel(val, wcss->reg_base + Q6SS_MEM_PWR_CTL);
149 * Read back value to ensure the write is done then
150 * wait for 1us for both memory peripheral and data
153 val |= readl(wcss->reg_base + Q6SS_MEM_PWR_CTL);
156 /* Remove word line clamp */
157 val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
158 val &= ~Q6SS_CLAMP_WL;
159 writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
161 /* Remove IO clamp */
162 val &= ~Q6SS_CLAMP_IO;
163 writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
165 /* Bring core out of reset */
166 val = readl(wcss->reg_base + Q6SS_RESET_REG);
167 val &= ~Q6SS_CORE_ARES;
168 writel(val, wcss->reg_base + Q6SS_RESET_REG);
170 /* Turn on core clock */
171 val = readl(wcss->reg_base + Q6SS_GFMUX_CTL_REG);
172 val |= Q6SS_CLK_ENABLE;
173 writel(val, wcss->reg_base + Q6SS_GFMUX_CTL_REG);
175 /* Start core execution */
176 val = readl(wcss->reg_base + Q6SS_RESET_REG);
177 val &= ~Q6SS_STOP_CORE;
178 writel(val, wcss->reg_base + Q6SS_RESET_REG);
183 static int q6v5_wcss_start(struct rproc *rproc)
185 struct q6v5_wcss *wcss = rproc->priv;
188 qcom_q6v5_prepare(&wcss->q6v5);
190 /* Release Q6 and WCSS reset */
191 ret = reset_control_deassert(wcss->wcss_reset);
193 dev_err(wcss->dev, "wcss_reset failed\n");
197 ret = reset_control_deassert(wcss->wcss_q6_reset);
199 dev_err(wcss->dev, "wcss_q6_reset failed\n");
203 /* Lithium configuration - clock gating and bus arbitration */
204 ret = regmap_update_bits(wcss->halt_map,
205 wcss->halt_nc + TCSR_GLOBAL_CFG0,
207 TCSR_WCSS_CLK_ENABLE);
211 ret = regmap_update_bits(wcss->halt_map,
212 wcss->halt_nc + TCSR_GLOBAL_CFG1,
217 /* Write bootaddr to EVB so that Q6WCSS will jump there after reset */
218 writel(rproc->bootaddr >> 4, wcss->reg_base + Q6SS_RST_EVB);
220 ret = q6v5_wcss_reset(wcss);
224 ret = qcom_q6v5_wait_for_start(&wcss->q6v5, 5 * HZ);
225 if (ret == -ETIMEDOUT)
226 dev_err(wcss->dev, "start timed out\n");
231 reset_control_assert(wcss->wcss_q6_reset);
234 reset_control_assert(wcss->wcss_reset);
239 static void q6v5_wcss_halt_axi_port(struct q6v5_wcss *wcss,
240 struct regmap *halt_map,
243 unsigned long timeout;
247 /* Check if we're already idle */
248 ret = regmap_read(halt_map, offset + AXI_IDLE_REG, &val);
252 /* Assert halt request */
253 regmap_write(halt_map, offset + AXI_HALTREQ_REG, 1);
256 timeout = jiffies + msecs_to_jiffies(HALT_ACK_TIMEOUT_MS);
258 ret = regmap_read(halt_map, offset + AXI_HALTACK_REG, &val);
259 if (ret || val || time_after(jiffies, timeout))
265 ret = regmap_read(halt_map, offset + AXI_IDLE_REG, &val);
267 dev_err(wcss->dev, "port failed halt\n");
269 /* Clear halt request (port will remain halted until reset) */
270 regmap_write(halt_map, offset + AXI_HALTREQ_REG, 0);
273 static int q6v5_wcss_powerdown(struct q6v5_wcss *wcss)
278 /* 1 - Assert WCSS/Q6 HALTREQ */
279 q6v5_wcss_halt_axi_port(wcss, wcss->halt_map, wcss->halt_wcss);
281 /* 2 - Enable WCSSAON_CONFIG */
282 val = readl(wcss->rmb_base + SSCAON_CONFIG);
283 val |= SSCAON_ENABLE;
284 writel(val, wcss->rmb_base + SSCAON_CONFIG);
286 /* 3 - Set SSCAON_CONFIG */
287 val |= SSCAON_BUS_EN;
288 val &= ~SSCAON_BUS_MUX_MASK;
289 writel(val, wcss->rmb_base + SSCAON_CONFIG);
291 /* 4 - SSCAON_CONFIG 1 */
293 writel(val, wcss->rmb_base + SSCAON_CONFIG);
295 /* 5 - wait for SSCAON_STATUS */
296 ret = readl_poll_timeout(wcss->rmb_base + SSCAON_STATUS,
297 val, (val & 0xffff) == 0x400, 1000,
298 HALT_CHECK_MAX_LOOPS);
301 "can't get SSCAON_STATUS rc:%d)\n", ret);
305 /* 6 - De-assert WCSS_AON reset */
306 reset_control_assert(wcss->wcss_aon_reset);
308 /* 7 - Disable WCSSAON_CONFIG 13 */
309 val = readl(wcss->rmb_base + SSCAON_CONFIG);
310 val &= ~SSCAON_ENABLE;
311 writel(val, wcss->rmb_base + SSCAON_CONFIG);
313 /* 8 - De-assert WCSS/Q6 HALTREQ */
314 reset_control_assert(wcss->wcss_reset);
319 static int q6v5_q6_powerdown(struct q6v5_wcss *wcss)
325 /* 1 - Halt Q6 bus interface */
326 q6v5_wcss_halt_axi_port(wcss, wcss->halt_map, wcss->halt_q6);
328 /* 2 - Disable Q6 Core clock */
329 val = readl(wcss->reg_base + Q6SS_GFMUX_CTL_REG);
330 val &= ~Q6SS_CLK_ENABLE;
331 writel(val, wcss->reg_base + Q6SS_GFMUX_CTL_REG);
334 val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
335 val |= Q6SS_CLAMP_IO;
336 writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
340 writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
342 /* 5 - Clear Erase standby */
343 val &= ~Q6SS_L2DATA_STBY_N;
344 writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
346 /* 6 - Clear Sleep RTN */
347 val &= ~Q6SS_SLP_RET_N;
348 writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
350 /* 7 - turn off Q6 memory foot/head switch one bank at a time */
351 for (i = 0; i < 20; i++) {
352 val = readl(wcss->reg_base + Q6SS_MEM_PWR_CTL);
354 writel(val, wcss->reg_base + Q6SS_MEM_PWR_CTL);
358 /* 8 - Assert QMC memory RTN */
359 val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
360 val |= Q6SS_CLAMP_QMC_MEM;
361 writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
363 /* 9 - Turn off BHS */
365 writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
368 /* 10 - Wait till BHS Reset is done */
369 ret = readl_poll_timeout(wcss->reg_base + Q6SS_BHS_STATUS,
370 val, !(val & BHS_EN_REST_ACK), 1000,
371 HALT_CHECK_MAX_LOOPS);
373 dev_err(wcss->dev, "BHS_STATUS not OFF (rc:%d)\n", ret);
377 /* 11 - Assert WCSS reset */
378 reset_control_assert(wcss->wcss_reset);
380 /* 12 - Assert Q6 reset */
381 reset_control_assert(wcss->wcss_q6_reset);
386 static int q6v5_wcss_stop(struct rproc *rproc)
388 struct q6v5_wcss *wcss = rproc->priv;
392 ret = qcom_q6v5_request_stop(&wcss->q6v5);
393 if (ret == -ETIMEDOUT) {
394 dev_err(wcss->dev, "timed out on wait\n");
398 ret = q6v5_wcss_powerdown(wcss);
403 ret = q6v5_q6_powerdown(wcss);
407 qcom_q6v5_unprepare(&wcss->q6v5);
412 static void *q6v5_wcss_da_to_va(struct rproc *rproc, u64 da, size_t len)
414 struct q6v5_wcss *wcss = rproc->priv;
417 offset = da - wcss->mem_reloc;
418 if (offset < 0 || offset + len > wcss->mem_size)
421 return wcss->mem_region + offset;
424 static int q6v5_wcss_load(struct rproc *rproc, const struct firmware *fw)
426 struct q6v5_wcss *wcss = rproc->priv;
428 return qcom_mdt_load_no_init(wcss->dev, fw, rproc->firmware,
429 0, wcss->mem_region, wcss->mem_phys,
430 wcss->mem_size, &wcss->mem_reloc);
433 static const struct rproc_ops q6v5_wcss_ops = {
434 .start = q6v5_wcss_start,
435 .stop = q6v5_wcss_stop,
436 .da_to_va = q6v5_wcss_da_to_va,
437 .load = q6v5_wcss_load,
438 .get_boot_addr = rproc_elf_get_boot_addr,
441 static int q6v5_wcss_init_reset(struct q6v5_wcss *wcss)
443 struct device *dev = wcss->dev;
445 wcss->wcss_aon_reset = devm_reset_control_get(dev, "wcss_aon_reset");
446 if (IS_ERR(wcss->wcss_aon_reset)) {
447 dev_err(wcss->dev, "unable to acquire wcss_aon_reset\n");
448 return PTR_ERR(wcss->wcss_aon_reset);
451 wcss->wcss_reset = devm_reset_control_get(dev, "wcss_reset");
452 if (IS_ERR(wcss->wcss_reset)) {
453 dev_err(wcss->dev, "unable to acquire wcss_reset\n");
454 return PTR_ERR(wcss->wcss_reset);
457 wcss->wcss_q6_reset = devm_reset_control_get(dev, "wcss_q6_reset");
458 if (IS_ERR(wcss->wcss_q6_reset)) {
459 dev_err(wcss->dev, "unable to acquire wcss_q6_reset\n");
460 return PTR_ERR(wcss->wcss_q6_reset);
466 static int q6v5_wcss_init_mmio(struct q6v5_wcss *wcss,
467 struct platform_device *pdev)
469 struct of_phandle_args args;
470 struct resource *res;
473 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qdsp6");
474 wcss->reg_base = devm_ioremap_resource(&pdev->dev, res);
475 if (IS_ERR(wcss->reg_base))
476 return PTR_ERR(wcss->reg_base);
478 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rmb");
479 wcss->rmb_base = devm_ioremap_resource(&pdev->dev, res);
480 if (IS_ERR(wcss->rmb_base))
481 return PTR_ERR(wcss->rmb_base);
483 ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node,
484 "qcom,halt-regs", 3, 0, &args);
486 dev_err(&pdev->dev, "failed to parse qcom,halt-regs\n");
490 wcss->halt_map = syscon_node_to_regmap(args.np);
491 of_node_put(args.np);
492 if (IS_ERR(wcss->halt_map))
493 return PTR_ERR(wcss->halt_map);
495 wcss->halt_q6 = args.args[0];
496 wcss->halt_wcss = args.args[1];
497 wcss->halt_nc = args.args[2];
502 static int q6v5_alloc_memory_region(struct q6v5_wcss *wcss)
504 struct reserved_mem *rmem = NULL;
505 struct device_node *node;
506 struct device *dev = wcss->dev;
508 node = of_parse_phandle(dev->of_node, "memory-region", 0);
510 rmem = of_reserved_mem_lookup(node);
514 dev_err(dev, "unable to acquire memory-region\n");
518 wcss->mem_phys = rmem->base;
519 wcss->mem_reloc = rmem->base;
520 wcss->mem_size = rmem->size;
521 wcss->mem_region = devm_ioremap_wc(dev, wcss->mem_phys, wcss->mem_size);
522 if (!wcss->mem_region) {
523 dev_err(dev, "unable to map memory region: %pa+%pa\n",
524 &rmem->base, &rmem->size);
531 static int q6v5_wcss_probe(struct platform_device *pdev)
533 struct q6v5_wcss *wcss;
537 rproc = rproc_alloc(&pdev->dev, pdev->name, &q6v5_wcss_ops,
538 "IPQ8074/q6_fw.mdt", sizeof(*wcss));
540 dev_err(&pdev->dev, "failed to allocate rproc\n");
545 wcss->dev = &pdev->dev;
547 ret = q6v5_wcss_init_mmio(wcss, pdev);
551 ret = q6v5_alloc_memory_region(wcss);
555 ret = q6v5_wcss_init_reset(wcss);
559 ret = qcom_q6v5_init(&wcss->q6v5, pdev, rproc, WCSS_CRASH_REASON, NULL);
563 qcom_add_glink_subdev(rproc, &wcss->glink_subdev, "q6wcss");
564 qcom_add_ssr_subdev(rproc, &wcss->ssr_subdev, "q6wcss");
566 ret = rproc_add(rproc);
570 platform_set_drvdata(pdev, rproc);
580 static int q6v5_wcss_remove(struct platform_device *pdev)
582 struct rproc *rproc = platform_get_drvdata(pdev);
590 static const struct of_device_id q6v5_wcss_of_match[] = {
591 { .compatible = "qcom,ipq8074-wcss-pil" },
594 MODULE_DEVICE_TABLE(of, q6v5_wcss_of_match);
596 static struct platform_driver q6v5_wcss_driver = {
597 .probe = q6v5_wcss_probe,
598 .remove = q6v5_wcss_remove,
600 .name = "qcom-q6v5-wcss-pil",
601 .of_match_table = q6v5_wcss_of_match,
604 module_platform_driver(q6v5_wcss_driver);
606 MODULE_DESCRIPTION("Hexagon WCSS Peripheral Image Loader");
607 MODULE_LICENSE("GPL v2");