1// SPDX-License-Identifier: GPL-2.0
2/*
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.
6 */
7#include <linux/clk.h>
8#include <linux/delay.h>
9#include <linux/io.h>
10#include <linux/iopoll.h>
11#include <linux/kernel.h>
12#include <linux/mfd/syscon.h>
13#include <linux/module.h>
14#include <linux/of_address.h>
15#include <linux/of_reserved_mem.h>
16#include <linux/platform_device.h>
17#include <linux/regmap.h>
18#include <linux/regulator/consumer.h>
19#include <linux/reset.h>
20#include <linux/soc/qcom/mdt_loader.h>
21#include "qcom_common.h"
22#include "qcom_pil_info.h"
23#include "qcom_q6v5.h"
24
25#define WCSS_CRASH_REASON 421
26
27/* Q6SS Register Offsets */
28#define Q6SS_RESET_REG 0x014
29#define Q6SS_GFMUX_CTL_REG 0x020
30#define Q6SS_PWR_CTL_REG 0x030
31#define Q6SS_MEM_PWR_CTL 0x0B0
32#define Q6SS_STRAP_ACC 0x110
33#define Q6SS_CGC_OVERRIDE 0x034
34#define Q6SS_BCR_REG 0x6000
35
36/* AXI Halt Register Offsets */
37#define AXI_HALTREQ_REG 0x0
38#define AXI_HALTACK_REG 0x4
39#define AXI_IDLE_REG 0x8
40
41#define HALT_ACK_TIMEOUT_MS 100
42
43/* Q6SS_RESET */
44#define Q6SS_STOP_CORE BIT(0)
45#define Q6SS_CORE_ARES BIT(1)
46#define Q6SS_BUS_ARES_ENABLE BIT(2)
47
48/* Q6SS_BRC_RESET */
49#define Q6SS_BRC_BLK_ARES BIT(0)
50
51/* Q6SS_GFMUX_CTL */
52#define Q6SS_CLK_ENABLE BIT(1)
53#define Q6SS_SWITCH_CLK_SRC BIT(8)
54
55/* Q6SS_PWR_CTL */
56#define Q6SS_L2DATA_STBY_N BIT(18)
57#define Q6SS_SLP_RET_N BIT(19)
58#define Q6SS_CLAMP_IO BIT(20)
59#define QDSS_BHS_ON BIT(21)
60#define QDSS_Q6_MEMORIES GENMASK(15, 0)
61
62/* Q6SS parameters */
63#define Q6SS_LDO_BYP BIT(25)
64#define Q6SS_BHS_ON BIT(24)
65#define Q6SS_CLAMP_WL BIT(21)
66#define Q6SS_CLAMP_QMC_MEM BIT(22)
67#define HALT_CHECK_MAX_LOOPS 200
68#define Q6SS_XO_CBCR GENMASK(5, 3)
69#define Q6SS_SLEEP_CBCR GENMASK(5, 2)
70
71/* Q6SS config/status registers */
72#define TCSR_GLOBAL_CFG0 0x0
73#define TCSR_GLOBAL_CFG1 0x4
74#define SSCAON_CONFIG 0x8
75#define SSCAON_STATUS 0xc
76#define Q6SS_BHS_STATUS 0x78
77#define Q6SS_RST_EVB 0x10
78
79#define BHS_EN_REST_ACK BIT(0)
80#define SSCAON_ENABLE BIT(13)
81#define SSCAON_BUS_EN BIT(15)
82#define SSCAON_BUS_MUX_MASK GENMASK(18, 16)
83
84#define MEM_BANKS 19
85#define TCSR_WCSS_CLK_MASK 0x1F
86#define TCSR_WCSS_CLK_ENABLE 0x14
87
88#define MAX_HALT_REG 3
89enum {
90 WCSS_IPQ8074,
91 WCSS_QCS404,
92};
93
94struct wcss_data {
95 const char *firmware_name;
96 unsigned int crash_reason_smem;
97 u32 version;
98 bool aon_reset_required;
99 bool wcss_q6_reset_required;
100 const char *ssr_name;
101 const char *sysmon_name;
102 int ssctl_id;
103 const struct rproc_ops *ops;
104 bool requires_force_stop;
105};
106
107struct q6v5_wcss {
108 struct device *dev;
109
110 void __iomem *reg_base;
111 void __iomem *rmb_base;
112
113 struct regmap *halt_map;
114 u32 halt_q6;
115 u32 halt_wcss;
116 u32 halt_nc;
117
118 struct clk *xo;
119 struct clk *ahbfabric_cbcr_clk;
120 struct clk *gcc_abhs_cbcr;
121 struct clk *gcc_axim_cbcr;
122 struct clk *lcc_csr_cbcr;
123 struct clk *ahbs_cbcr;
124 struct clk *tcm_slave_cbcr;
125 struct clk *qdsp6ss_abhm_cbcr;
126 struct clk *qdsp6ss_sleep_cbcr;
127 struct clk *qdsp6ss_axim_cbcr;
128 struct clk *qdsp6ss_xo_cbcr;
129 struct clk *qdsp6ss_core_gfmux;
130 struct clk *lcc_bcr_sleep;
131 struct regulator *cx_supply;
132 struct qcom_sysmon *sysmon;
133
134 struct reset_control *wcss_aon_reset;
135 struct reset_control *wcss_reset;
136 struct reset_control *wcss_q6_reset;
137 struct reset_control *wcss_q6_bcr_reset;
138
139 struct qcom_q6v5 q6v5;
140
141 phys_addr_t mem_phys;
142 phys_addr_t mem_reloc;
143 void *mem_region;
144 size_t mem_size;
145
146 unsigned int crash_reason_smem;
147 u32 version;
148 bool requires_force_stop;
149
150 struct qcom_rproc_glink glink_subdev;
151 struct qcom_rproc_ssr ssr_subdev;
152};
153
154static int q6v5_wcss_reset(struct q6v5_wcss *wcss)
155{
156 int ret;
157 u32 val;
158 int i;
159
160 /* Assert resets, stop core */
161 val = readl(addr: wcss->reg_base + Q6SS_RESET_REG);
162 val |= Q6SS_CORE_ARES | Q6SS_BUS_ARES_ENABLE | Q6SS_STOP_CORE;
163 writel(val, addr: wcss->reg_base + Q6SS_RESET_REG);
164
165 /* BHS require xo cbcr to be enabled */
166 val = readl(addr: wcss->reg_base + Q6SS_XO_CBCR);
167 val |= 0x1;
168 writel(val, addr: wcss->reg_base + Q6SS_XO_CBCR);
169
170 /* Read CLKOFF bit to go low indicating CLK is enabled */
171 ret = readl_poll_timeout(wcss->reg_base + Q6SS_XO_CBCR,
172 val, !(val & BIT(31)), 1,
173 HALT_CHECK_MAX_LOOPS);
174 if (ret) {
175 dev_err(wcss->dev,
176 "xo cbcr enabling timed out (rc:%d)\n", ret);
177 return ret;
178 }
179 /* Enable power block headswitch and wait for it to stabilize */
180 val = readl(addr: wcss->reg_base + Q6SS_PWR_CTL_REG);
181 val |= Q6SS_BHS_ON;
182 writel(val, addr: wcss->reg_base + Q6SS_PWR_CTL_REG);
183 udelay(1);
184
185 /* Put LDO in bypass mode */
186 val |= Q6SS_LDO_BYP;
187 writel(val, addr: wcss->reg_base + Q6SS_PWR_CTL_REG);
188
189 /* Deassert Q6 compiler memory clamp */
190 val = readl(addr: wcss->reg_base + Q6SS_PWR_CTL_REG);
191 val &= ~Q6SS_CLAMP_QMC_MEM;
192 writel(val, addr: wcss->reg_base + Q6SS_PWR_CTL_REG);
193
194 /* Deassert memory peripheral sleep and L2 memory standby */
195 val |= Q6SS_L2DATA_STBY_N | Q6SS_SLP_RET_N;
196 writel(val, addr: wcss->reg_base + Q6SS_PWR_CTL_REG);
197
198 /* Turn on L1, L2, ETB and JU memories 1 at a time */
199 val = readl(addr: wcss->reg_base + Q6SS_MEM_PWR_CTL);
200 for (i = MEM_BANKS; i >= 0; i--) {
201 val |= BIT(i);
202 writel(val, addr: wcss->reg_base + Q6SS_MEM_PWR_CTL);
203 /*
204 * Read back value to ensure the write is done then
205 * wait for 1us for both memory peripheral and data
206 * array to turn on.
207 */
208 val |= readl(addr: wcss->reg_base + Q6SS_MEM_PWR_CTL);
209 udelay(1);
210 }
211 /* Remove word line clamp */
212 val = readl(addr: wcss->reg_base + Q6SS_PWR_CTL_REG);
213 val &= ~Q6SS_CLAMP_WL;
214 writel(val, addr: wcss->reg_base + Q6SS_PWR_CTL_REG);
215
216 /* Remove IO clamp */
217 val &= ~Q6SS_CLAMP_IO;
218 writel(val, addr: wcss->reg_base + Q6SS_PWR_CTL_REG);
219
220 /* Bring core out of reset */
221 val = readl(addr: wcss->reg_base + Q6SS_RESET_REG);
222 val &= ~Q6SS_CORE_ARES;
223 writel(val, addr: wcss->reg_base + Q6SS_RESET_REG);
224
225 /* Turn on core clock */
226 val = readl(addr: wcss->reg_base + Q6SS_GFMUX_CTL_REG);
227 val |= Q6SS_CLK_ENABLE;
228 writel(val, addr: wcss->reg_base + Q6SS_GFMUX_CTL_REG);
229
230 /* Start core execution */
231 val = readl(addr: wcss->reg_base + Q6SS_RESET_REG);
232 val &= ~Q6SS_STOP_CORE;
233 writel(val, addr: wcss->reg_base + Q6SS_RESET_REG);
234
235 return 0;
236}
237
238static int q6v5_wcss_start(struct rproc *rproc)
239{
240 struct q6v5_wcss *wcss = rproc->priv;
241 int ret;
242
243 qcom_q6v5_prepare(q6v5: &wcss->q6v5);
244
245 /* Release Q6 and WCSS reset */
246 ret = reset_control_deassert(rstc: wcss->wcss_reset);
247 if (ret) {
248 dev_err(wcss->dev, "wcss_reset failed\n");
249 return ret;
250 }
251
252 ret = reset_control_deassert(rstc: wcss->wcss_q6_reset);
253 if (ret) {
254 dev_err(wcss->dev, "wcss_q6_reset failed\n");
255 goto wcss_reset;
256 }
257
258 /* Lithium configuration - clock gating and bus arbitration */
259 ret = regmap_update_bits(map: wcss->halt_map,
260 reg: wcss->halt_nc + TCSR_GLOBAL_CFG0,
261 TCSR_WCSS_CLK_MASK,
262 TCSR_WCSS_CLK_ENABLE);
263 if (ret)
264 goto wcss_q6_reset;
265
266 ret = regmap_update_bits(map: wcss->halt_map,
267 reg: wcss->halt_nc + TCSR_GLOBAL_CFG1,
268 mask: 1, val: 0);
269 if (ret)
270 goto wcss_q6_reset;
271
272 /* Write bootaddr to EVB so that Q6WCSS will jump there after reset */
273 writel(val: rproc->bootaddr >> 4, addr: wcss->reg_base + Q6SS_RST_EVB);
274
275 ret = q6v5_wcss_reset(wcss);
276 if (ret)
277 goto wcss_q6_reset;
278
279 ret = qcom_q6v5_wait_for_start(q6v5: &wcss->q6v5, timeout: 5 * HZ);
280 if (ret == -ETIMEDOUT)
281 dev_err(wcss->dev, "start timed out\n");
282
283 return ret;
284
285wcss_q6_reset:
286 reset_control_assert(rstc: wcss->wcss_q6_reset);
287
288wcss_reset:
289 reset_control_assert(rstc: wcss->wcss_reset);
290
291 return ret;
292}
293
294static int q6v5_wcss_qcs404_power_on(struct q6v5_wcss *wcss)
295{
296 unsigned long val;
297 int ret, idx;
298
299 /* Toggle the restart */
300 reset_control_assert(rstc: wcss->wcss_reset);
301 usleep_range(min: 200, max: 300);
302 reset_control_deassert(rstc: wcss->wcss_reset);
303 usleep_range(min: 200, max: 300);
304
305 /* Enable GCC_WDSP_Q6SS_AHBS_CBCR clock */
306 ret = clk_prepare_enable(clk: wcss->gcc_abhs_cbcr);
307 if (ret)
308 return ret;
309
310 /* Remove reset to the WCNSS QDSP6SS */
311 reset_control_deassert(rstc: wcss->wcss_q6_bcr_reset);
312
313 /* Enable Q6SSTOP_AHBFABRIC_CBCR clock */
314 ret = clk_prepare_enable(clk: wcss->ahbfabric_cbcr_clk);
315 if (ret)
316 goto disable_gcc_abhs_cbcr_clk;
317
318 /* Enable the LCCCSR CBC clock, Q6SSTOP_Q6SSTOP_LCC_CSR_CBCR clock */
319 ret = clk_prepare_enable(clk: wcss->lcc_csr_cbcr);
320 if (ret)
321 goto disable_ahbfabric_cbcr_clk;
322
323 /* Enable the Q6AHBS CBC, Q6SSTOP_Q6SS_AHBS_CBCR clock */
324 ret = clk_prepare_enable(clk: wcss->ahbs_cbcr);
325 if (ret)
326 goto disable_csr_cbcr_clk;
327
328 /* Enable the TCM slave CBC, Q6SSTOP_Q6SS_TCM_SLAVE_CBCR clock */
329 ret = clk_prepare_enable(clk: wcss->tcm_slave_cbcr);
330 if (ret)
331 goto disable_ahbs_cbcr_clk;
332
333 /* Enable the Q6SS AHB master CBC, Q6SSTOP_Q6SS_AHBM_CBCR clock */
334 ret = clk_prepare_enable(clk: wcss->qdsp6ss_abhm_cbcr);
335 if (ret)
336 goto disable_tcm_slave_cbcr_clk;
337
338 /* Enable the Q6SS AXI master CBC, Q6SSTOP_Q6SS_AXIM_CBCR clock */
339 ret = clk_prepare_enable(clk: wcss->qdsp6ss_axim_cbcr);
340 if (ret)
341 goto disable_abhm_cbcr_clk;
342
343 /* Enable the Q6SS XO CBC */
344 val = readl(addr: wcss->reg_base + Q6SS_XO_CBCR);
345 val |= BIT(0);
346 writel(val, addr: wcss->reg_base + Q6SS_XO_CBCR);
347 /* Read CLKOFF bit to go low indicating CLK is enabled */
348 ret = readl_poll_timeout(wcss->reg_base + Q6SS_XO_CBCR,
349 val, !(val & BIT(31)), 1,
350 HALT_CHECK_MAX_LOOPS);
351 if (ret) {
352 dev_err(wcss->dev,
353 "xo cbcr enabling timed out (rc:%d)\n", ret);
354 goto disable_xo_cbcr_clk;
355 }
356
357 writel(val: 0, addr: wcss->reg_base + Q6SS_CGC_OVERRIDE);
358
359 /* Enable QDSP6 sleep clock clock */
360 val = readl(addr: wcss->reg_base + Q6SS_SLEEP_CBCR);
361 val |= BIT(0);
362 writel(val, addr: wcss->reg_base + Q6SS_SLEEP_CBCR);
363
364 /* Enable the Enable the Q6 AXI clock, GCC_WDSP_Q6SS_AXIM_CBCR*/
365 ret = clk_prepare_enable(clk: wcss->gcc_axim_cbcr);
366 if (ret)
367 goto disable_sleep_cbcr_clk;
368
369 /* Assert resets, stop core */
370 val = readl(addr: wcss->reg_base + Q6SS_RESET_REG);
371 val |= Q6SS_CORE_ARES | Q6SS_BUS_ARES_ENABLE | Q6SS_STOP_CORE;
372 writel(val, addr: wcss->reg_base + Q6SS_RESET_REG);
373
374 /* Program the QDSP6SS PWR_CTL register */
375 writel(val: 0x01700000, addr: wcss->reg_base + Q6SS_PWR_CTL_REG);
376
377 writel(val: 0x03700000, addr: wcss->reg_base + Q6SS_PWR_CTL_REG);
378
379 writel(val: 0x03300000, addr: wcss->reg_base + Q6SS_PWR_CTL_REG);
380
381 writel(val: 0x033C0000, addr: wcss->reg_base + Q6SS_PWR_CTL_REG);
382
383 /*
384 * Enable memories by turning on the QDSP6 memory foot/head switch, one
385 * bank at a time to avoid in-rush current
386 */
387 for (idx = 28; idx >= 0; idx--) {
388 writel(val: (readl(addr: wcss->reg_base + Q6SS_MEM_PWR_CTL) |
389 (1 << idx)), addr: wcss->reg_base + Q6SS_MEM_PWR_CTL);
390 }
391
392 writel(val: 0x031C0000, addr: wcss->reg_base + Q6SS_PWR_CTL_REG);
393 writel(val: 0x030C0000, addr: wcss->reg_base + Q6SS_PWR_CTL_REG);
394
395 val = readl(addr: wcss->reg_base + Q6SS_RESET_REG);
396 val &= ~Q6SS_CORE_ARES;
397 writel(val, addr: wcss->reg_base + Q6SS_RESET_REG);
398
399 /* Enable the Q6 core clock at the GFM, Q6SSTOP_QDSP6SS_GFMUX_CTL */
400 val = readl(addr: wcss->reg_base + Q6SS_GFMUX_CTL_REG);
401 val |= Q6SS_CLK_ENABLE | Q6SS_SWITCH_CLK_SRC;
402 writel(val, addr: wcss->reg_base + Q6SS_GFMUX_CTL_REG);
403
404 /* Enable sleep clock branch needed for BCR circuit */
405 ret = clk_prepare_enable(clk: wcss->lcc_bcr_sleep);
406 if (ret)
407 goto disable_core_gfmux_clk;
408
409 return 0;
410
411disable_core_gfmux_clk:
412 val = readl(addr: wcss->reg_base + Q6SS_GFMUX_CTL_REG);
413 val &= ~(Q6SS_CLK_ENABLE | Q6SS_SWITCH_CLK_SRC);
414 writel(val, addr: wcss->reg_base + Q6SS_GFMUX_CTL_REG);
415 clk_disable_unprepare(clk: wcss->gcc_axim_cbcr);
416disable_sleep_cbcr_clk:
417 val = readl(addr: wcss->reg_base + Q6SS_SLEEP_CBCR);
418 val &= ~Q6SS_CLK_ENABLE;
419 writel(val, addr: wcss->reg_base + Q6SS_SLEEP_CBCR);
420disable_xo_cbcr_clk:
421 val = readl(addr: wcss->reg_base + Q6SS_XO_CBCR);
422 val &= ~Q6SS_CLK_ENABLE;
423 writel(val, addr: wcss->reg_base + Q6SS_XO_CBCR);
424 clk_disable_unprepare(clk: wcss->qdsp6ss_axim_cbcr);
425disable_abhm_cbcr_clk:
426 clk_disable_unprepare(clk: wcss->qdsp6ss_abhm_cbcr);
427disable_tcm_slave_cbcr_clk:
428 clk_disable_unprepare(clk: wcss->tcm_slave_cbcr);
429disable_ahbs_cbcr_clk:
430 clk_disable_unprepare(clk: wcss->ahbs_cbcr);
431disable_csr_cbcr_clk:
432 clk_disable_unprepare(clk: wcss->lcc_csr_cbcr);
433disable_ahbfabric_cbcr_clk:
434 clk_disable_unprepare(clk: wcss->ahbfabric_cbcr_clk);
435disable_gcc_abhs_cbcr_clk:
436 clk_disable_unprepare(clk: wcss->gcc_abhs_cbcr);
437
438 return ret;
439}
440
441static inline int q6v5_wcss_qcs404_reset(struct q6v5_wcss *wcss)
442{
443 unsigned long val;
444
445 writel(val: 0x80800000, addr: wcss->reg_base + Q6SS_STRAP_ACC);
446
447 /* Start core execution */
448 val = readl(addr: wcss->reg_base + Q6SS_RESET_REG);
449 val &= ~Q6SS_STOP_CORE;
450 writel(val, addr: wcss->reg_base + Q6SS_RESET_REG);
451
452 return 0;
453}
454
455static int q6v5_qcs404_wcss_start(struct rproc *rproc)
456{
457 struct q6v5_wcss *wcss = rproc->priv;
458 int ret;
459
460 ret = clk_prepare_enable(clk: wcss->xo);
461 if (ret)
462 return ret;
463
464 ret = regulator_enable(regulator: wcss->cx_supply);
465 if (ret)
466 goto disable_xo_clk;
467
468 qcom_q6v5_prepare(q6v5: &wcss->q6v5);
469
470 ret = q6v5_wcss_qcs404_power_on(wcss);
471 if (ret) {
472 dev_err(wcss->dev, "wcss clk_enable failed\n");
473 goto disable_cx_supply;
474 }
475
476 writel(val: rproc->bootaddr >> 4, addr: wcss->reg_base + Q6SS_RST_EVB);
477
478 q6v5_wcss_qcs404_reset(wcss);
479
480 ret = qcom_q6v5_wait_for_start(q6v5: &wcss->q6v5, timeout: 5 * HZ);
481 if (ret == -ETIMEDOUT) {
482 dev_err(wcss->dev, "start timed out\n");
483 goto disable_cx_supply;
484 }
485
486 return 0;
487
488disable_cx_supply:
489 regulator_disable(regulator: wcss->cx_supply);
490disable_xo_clk:
491 clk_disable_unprepare(clk: wcss->xo);
492
493 return ret;
494}
495
496static void q6v5_wcss_halt_axi_port(struct q6v5_wcss *wcss,
497 struct regmap *halt_map,
498 u32 offset)
499{
500 unsigned long timeout;
501 unsigned int val;
502 int ret;
503
504 /* Check if we're already idle */
505 ret = regmap_read(map: halt_map, reg: offset + AXI_IDLE_REG, val: &val);
506 if (!ret && val)
507 return;
508
509 /* Assert halt request */
510 regmap_write(map: halt_map, reg: offset + AXI_HALTREQ_REG, val: 1);
511
512 /* Wait for halt */
513 timeout = jiffies + msecs_to_jiffies(HALT_ACK_TIMEOUT_MS);
514 for (;;) {
515 ret = regmap_read(map: halt_map, reg: offset + AXI_HALTACK_REG, val: &val);
516 if (ret || val || time_after(jiffies, timeout))
517 break;
518
519 msleep(msecs: 1);
520 }
521
522 ret = regmap_read(map: halt_map, reg: offset + AXI_IDLE_REG, val: &val);
523 if (ret || !val)
524 dev_err(wcss->dev, "port failed halt\n");
525
526 /* Clear halt request (port will remain halted until reset) */
527 regmap_write(map: halt_map, reg: offset + AXI_HALTREQ_REG, val: 0);
528}
529
530static int q6v5_qcs404_wcss_shutdown(struct q6v5_wcss *wcss)
531{
532 unsigned long val;
533 int ret;
534
535 q6v5_wcss_halt_axi_port(wcss, halt_map: wcss->halt_map, offset: wcss->halt_wcss);
536
537 /* assert clamps to avoid MX current inrush */
538 val = readl(addr: wcss->reg_base + Q6SS_PWR_CTL_REG);
539 val |= (Q6SS_CLAMP_IO | Q6SS_CLAMP_WL | Q6SS_CLAMP_QMC_MEM);
540 writel(val, addr: wcss->reg_base + Q6SS_PWR_CTL_REG);
541
542 /* Disable memories by turning off memory foot/headswitch */
543 writel(val: (readl(addr: wcss->reg_base + Q6SS_MEM_PWR_CTL) &
544 ~QDSS_Q6_MEMORIES),
545 addr: wcss->reg_base + Q6SS_MEM_PWR_CTL);
546
547 /* Clear the BHS_ON bit */
548 val = readl(addr: wcss->reg_base + Q6SS_PWR_CTL_REG);
549 val &= ~Q6SS_BHS_ON;
550 writel(val, addr: wcss->reg_base + Q6SS_PWR_CTL_REG);
551
552 clk_disable_unprepare(clk: wcss->ahbfabric_cbcr_clk);
553 clk_disable_unprepare(clk: wcss->lcc_csr_cbcr);
554 clk_disable_unprepare(clk: wcss->tcm_slave_cbcr);
555 clk_disable_unprepare(clk: wcss->qdsp6ss_abhm_cbcr);
556 clk_disable_unprepare(clk: wcss->qdsp6ss_axim_cbcr);
557
558 val = readl(addr: wcss->reg_base + Q6SS_SLEEP_CBCR);
559 val &= ~BIT(0);
560 writel(val, addr: wcss->reg_base + Q6SS_SLEEP_CBCR);
561
562 val = readl(addr: wcss->reg_base + Q6SS_XO_CBCR);
563 val &= ~BIT(0);
564 writel(val, addr: wcss->reg_base + Q6SS_XO_CBCR);
565
566 clk_disable_unprepare(clk: wcss->ahbs_cbcr);
567 clk_disable_unprepare(clk: wcss->lcc_bcr_sleep);
568
569 val = readl(addr: wcss->reg_base + Q6SS_GFMUX_CTL_REG);
570 val &= ~(Q6SS_CLK_ENABLE | Q6SS_SWITCH_CLK_SRC);
571 writel(val, addr: wcss->reg_base + Q6SS_GFMUX_CTL_REG);
572
573 clk_disable_unprepare(clk: wcss->gcc_abhs_cbcr);
574
575 ret = reset_control_assert(rstc: wcss->wcss_reset);
576 if (ret) {
577 dev_err(wcss->dev, "wcss_reset failed\n");
578 return ret;
579 }
580 usleep_range(min: 200, max: 300);
581
582 ret = reset_control_deassert(rstc: wcss->wcss_reset);
583 if (ret) {
584 dev_err(wcss->dev, "wcss_reset failed\n");
585 return ret;
586 }
587 usleep_range(min: 200, max: 300);
588
589 clk_disable_unprepare(clk: wcss->gcc_axim_cbcr);
590
591 return 0;
592}
593
594static int q6v5_wcss_powerdown(struct q6v5_wcss *wcss)
595{
596 int ret;
597 u32 val;
598
599 /* 1 - Assert WCSS/Q6 HALTREQ */
600 q6v5_wcss_halt_axi_port(wcss, halt_map: wcss->halt_map, offset: wcss->halt_wcss);
601
602 /* 2 - Enable WCSSAON_CONFIG */
603 val = readl(addr: wcss->rmb_base + SSCAON_CONFIG);
604 val |= SSCAON_ENABLE;
605 writel(val, addr: wcss->rmb_base + SSCAON_CONFIG);
606
607 /* 3 - Set SSCAON_CONFIG */
608 val |= SSCAON_BUS_EN;
609 val &= ~SSCAON_BUS_MUX_MASK;
610 writel(val, addr: wcss->rmb_base + SSCAON_CONFIG);
611
612 /* 4 - SSCAON_CONFIG 1 */
613 val |= BIT(1);
614 writel(val, addr: wcss->rmb_base + SSCAON_CONFIG);
615
616 /* 5 - wait for SSCAON_STATUS */
617 ret = readl_poll_timeout(wcss->rmb_base + SSCAON_STATUS,
618 val, (val & 0xffff) == 0x400, 1000,
619 HALT_CHECK_MAX_LOOPS);
620 if (ret) {
621 dev_err(wcss->dev,
622 "can't get SSCAON_STATUS rc:%d)\n", ret);
623 return ret;
624 }
625
626 /* 6 - De-assert WCSS_AON reset */
627 reset_control_assert(rstc: wcss->wcss_aon_reset);
628
629 /* 7 - Disable WCSSAON_CONFIG 13 */
630 val = readl(addr: wcss->rmb_base + SSCAON_CONFIG);
631 val &= ~SSCAON_ENABLE;
632 writel(val, addr: wcss->rmb_base + SSCAON_CONFIG);
633
634 /* 8 - De-assert WCSS/Q6 HALTREQ */
635 reset_control_assert(rstc: wcss->wcss_reset);
636
637 return 0;
638}
639
640static int q6v5_q6_powerdown(struct q6v5_wcss *wcss)
641{
642 int ret;
643 u32 val;
644 int i;
645
646 /* 1 - Halt Q6 bus interface */
647 q6v5_wcss_halt_axi_port(wcss, halt_map: wcss->halt_map, offset: wcss->halt_q6);
648
649 /* 2 - Disable Q6 Core clock */
650 val = readl(addr: wcss->reg_base + Q6SS_GFMUX_CTL_REG);
651 val &= ~Q6SS_CLK_ENABLE;
652 writel(val, addr: wcss->reg_base + Q6SS_GFMUX_CTL_REG);
653
654 /* 3 - Clamp I/O */
655 val = readl(addr: wcss->reg_base + Q6SS_PWR_CTL_REG);
656 val |= Q6SS_CLAMP_IO;
657 writel(val, addr: wcss->reg_base + Q6SS_PWR_CTL_REG);
658
659 /* 4 - Clamp WL */
660 val |= QDSS_BHS_ON;
661 writel(val, addr: wcss->reg_base + Q6SS_PWR_CTL_REG);
662
663 /* 5 - Clear Erase standby */
664 val &= ~Q6SS_L2DATA_STBY_N;
665 writel(val, addr: wcss->reg_base + Q6SS_PWR_CTL_REG);
666
667 /* 6 - Clear Sleep RTN */
668 val &= ~Q6SS_SLP_RET_N;
669 writel(val, addr: wcss->reg_base + Q6SS_PWR_CTL_REG);
670
671 /* 7 - turn off Q6 memory foot/head switch one bank at a time */
672 for (i = 0; i < 20; i++) {
673 val = readl(addr: wcss->reg_base + Q6SS_MEM_PWR_CTL);
674 val &= ~BIT(i);
675 writel(val, addr: wcss->reg_base + Q6SS_MEM_PWR_CTL);
676 mdelay(1);
677 }
678
679 /* 8 - Assert QMC memory RTN */
680 val = readl(addr: wcss->reg_base + Q6SS_PWR_CTL_REG);
681 val |= Q6SS_CLAMP_QMC_MEM;
682 writel(val, addr: wcss->reg_base + Q6SS_PWR_CTL_REG);
683
684 /* 9 - Turn off BHS */
685 val &= ~Q6SS_BHS_ON;
686 writel(val, addr: wcss->reg_base + Q6SS_PWR_CTL_REG);
687 udelay(1);
688
689 /* 10 - Wait till BHS Reset is done */
690 ret = readl_poll_timeout(wcss->reg_base + Q6SS_BHS_STATUS,
691 val, !(val & BHS_EN_REST_ACK), 1000,
692 HALT_CHECK_MAX_LOOPS);
693 if (ret) {
694 dev_err(wcss->dev, "BHS_STATUS not OFF (rc:%d)\n", ret);
695 return ret;
696 }
697
698 /* 11 - Assert WCSS reset */
699 reset_control_assert(rstc: wcss->wcss_reset);
700
701 /* 12 - Assert Q6 reset */
702 reset_control_assert(rstc: wcss->wcss_q6_reset);
703
704 return 0;
705}
706
707static int q6v5_wcss_stop(struct rproc *rproc)
708{
709 struct q6v5_wcss *wcss = rproc->priv;
710 int ret;
711
712 /* WCSS powerdown */
713 if (wcss->requires_force_stop) {
714 ret = qcom_q6v5_request_stop(q6v5: &wcss->q6v5, NULL);
715 if (ret == -ETIMEDOUT) {
716 dev_err(wcss->dev, "timed out on wait\n");
717 return ret;
718 }
719 }
720
721 if (wcss->version == WCSS_QCS404) {
722 ret = q6v5_qcs404_wcss_shutdown(wcss);
723 if (ret)
724 return ret;
725 } else {
726 ret = q6v5_wcss_powerdown(wcss);
727 if (ret)
728 return ret;
729
730 /* Q6 Power down */
731 ret = q6v5_q6_powerdown(wcss);
732 if (ret)
733 return ret;
734 }
735
736 qcom_q6v5_unprepare(q6v5: &wcss->q6v5);
737
738 return 0;
739}
740
741static void *q6v5_wcss_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem)
742{
743 struct q6v5_wcss *wcss = rproc->priv;
744 int offset;
745
746 offset = da - wcss->mem_reloc;
747 if (offset < 0 || offset + len > wcss->mem_size)
748 return NULL;
749
750 return wcss->mem_region + offset;
751}
752
753static int q6v5_wcss_load(struct rproc *rproc, const struct firmware *fw)
754{
755 struct q6v5_wcss *wcss = rproc->priv;
756 int ret;
757
758 ret = qcom_mdt_load_no_init(dev: wcss->dev, fw, fw_name: rproc->firmware,
759 pas_id: 0, mem_region: wcss->mem_region, mem_phys: wcss->mem_phys,
760 mem_size: wcss->mem_size, reloc_base: &wcss->mem_reloc);
761 if (ret)
762 return ret;
763
764 qcom_pil_info_store(image: "wcnss", base: wcss->mem_phys, size: wcss->mem_size);
765
766 return ret;
767}
768
769static const struct rproc_ops q6v5_wcss_ipq8074_ops = {
770 .start = q6v5_wcss_start,
771 .stop = q6v5_wcss_stop,
772 .da_to_va = q6v5_wcss_da_to_va,
773 .load = q6v5_wcss_load,
774 .get_boot_addr = rproc_elf_get_boot_addr,
775};
776
777static const struct rproc_ops q6v5_wcss_qcs404_ops = {
778 .start = q6v5_qcs404_wcss_start,
779 .stop = q6v5_wcss_stop,
780 .da_to_va = q6v5_wcss_da_to_va,
781 .load = q6v5_wcss_load,
782 .get_boot_addr = rproc_elf_get_boot_addr,
783 .parse_fw = qcom_register_dump_segments,
784};
785
786static int q6v5_wcss_init_reset(struct q6v5_wcss *wcss,
787 const struct wcss_data *desc)
788{
789 struct device *dev = wcss->dev;
790
791 if (desc->aon_reset_required) {
792 wcss->wcss_aon_reset = devm_reset_control_get_exclusive(dev, id: "wcss_aon_reset");
793 if (IS_ERR(ptr: wcss->wcss_aon_reset)) {
794 dev_err(wcss->dev, "fail to acquire wcss_aon_reset\n");
795 return PTR_ERR(ptr: wcss->wcss_aon_reset);
796 }
797 }
798
799 wcss->wcss_reset = devm_reset_control_get_exclusive(dev, id: "wcss_reset");
800 if (IS_ERR(ptr: wcss->wcss_reset)) {
801 dev_err(wcss->dev, "unable to acquire wcss_reset\n");
802 return PTR_ERR(ptr: wcss->wcss_reset);
803 }
804
805 if (desc->wcss_q6_reset_required) {
806 wcss->wcss_q6_reset = devm_reset_control_get_exclusive(dev, id: "wcss_q6_reset");
807 if (IS_ERR(ptr: wcss->wcss_q6_reset)) {
808 dev_err(wcss->dev, "unable to acquire wcss_q6_reset\n");
809 return PTR_ERR(ptr: wcss->wcss_q6_reset);
810 }
811 }
812
813 wcss->wcss_q6_bcr_reset = devm_reset_control_get_exclusive(dev, id: "wcss_q6_bcr_reset");
814 if (IS_ERR(ptr: wcss->wcss_q6_bcr_reset)) {
815 dev_err(wcss->dev, "unable to acquire wcss_q6_bcr_reset\n");
816 return PTR_ERR(ptr: wcss->wcss_q6_bcr_reset);
817 }
818
819 return 0;
820}
821
822static int q6v5_wcss_init_mmio(struct q6v5_wcss *wcss,
823 struct platform_device *pdev)
824{
825 unsigned int halt_reg[MAX_HALT_REG] = {0};
826 struct device_node *syscon;
827 struct resource *res;
828 int ret;
829
830 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qdsp6");
831 if (!res)
832 return -EINVAL;
833
834 wcss->reg_base = devm_ioremap(dev: &pdev->dev, offset: res->start,
835 size: resource_size(res));
836 if (!wcss->reg_base)
837 return -ENOMEM;
838
839 if (wcss->version == WCSS_IPQ8074) {
840 wcss->rmb_base = devm_platform_ioremap_resource_byname(pdev, name: "rmb");
841 if (IS_ERR(ptr: wcss->rmb_base))
842 return PTR_ERR(ptr: wcss->rmb_base);
843 }
844
845 syscon = of_parse_phandle(np: pdev->dev.of_node,
846 phandle_name: "qcom,halt-regs", index: 0);
847 if (!syscon) {
848 dev_err(&pdev->dev, "failed to parse qcom,halt-regs\n");
849 return -EINVAL;
850 }
851
852 wcss->halt_map = syscon_node_to_regmap(np: syscon);
853 of_node_put(node: syscon);
854 if (IS_ERR(ptr: wcss->halt_map))
855 return PTR_ERR(ptr: wcss->halt_map);
856
857 ret = of_property_read_variable_u32_array(np: pdev->dev.of_node,
858 propname: "qcom,halt-regs",
859 out_values: halt_reg, sz_min: 0,
860 MAX_HALT_REG);
861 if (ret < 0) {
862 dev_err(&pdev->dev, "failed to parse qcom,halt-regs\n");
863 return -EINVAL;
864 }
865
866 wcss->halt_q6 = halt_reg[0];
867 wcss->halt_wcss = halt_reg[1];
868 wcss->halt_nc = halt_reg[2];
869
870 return 0;
871}
872
873static int q6v5_alloc_memory_region(struct q6v5_wcss *wcss)
874{
875 struct reserved_mem *rmem = NULL;
876 struct device_node *node;
877 struct device *dev = wcss->dev;
878
879 node = of_parse_phandle(np: dev->of_node, phandle_name: "memory-region", index: 0);
880 if (node)
881 rmem = of_reserved_mem_lookup(np: node);
882 of_node_put(node);
883
884 if (!rmem) {
885 dev_err(dev, "unable to acquire memory-region\n");
886 return -EINVAL;
887 }
888
889 wcss->mem_phys = rmem->base;
890 wcss->mem_reloc = rmem->base;
891 wcss->mem_size = rmem->size;
892 wcss->mem_region = devm_ioremap_wc(dev, offset: wcss->mem_phys, size: wcss->mem_size);
893 if (!wcss->mem_region) {
894 dev_err(dev, "unable to map memory region: %pa+%pa\n",
895 &rmem->base, &rmem->size);
896 return -EBUSY;
897 }
898
899 return 0;
900}
901
902static int q6v5_wcss_init_clock(struct q6v5_wcss *wcss)
903{
904 int ret;
905
906 wcss->xo = devm_clk_get(dev: wcss->dev, id: "xo");
907 if (IS_ERR(ptr: wcss->xo)) {
908 ret = PTR_ERR(ptr: wcss->xo);
909 if (ret != -EPROBE_DEFER)
910 dev_err(wcss->dev, "failed to get xo clock");
911 return ret;
912 }
913
914 wcss->gcc_abhs_cbcr = devm_clk_get(dev: wcss->dev, id: "gcc_abhs_cbcr");
915 if (IS_ERR(ptr: wcss->gcc_abhs_cbcr)) {
916 ret = PTR_ERR(ptr: wcss->gcc_abhs_cbcr);
917 if (ret != -EPROBE_DEFER)
918 dev_err(wcss->dev, "failed to get gcc abhs clock");
919 return ret;
920 }
921
922 wcss->gcc_axim_cbcr = devm_clk_get(dev: wcss->dev, id: "gcc_axim_cbcr");
923 if (IS_ERR(ptr: wcss->gcc_axim_cbcr)) {
924 ret = PTR_ERR(ptr: wcss->gcc_axim_cbcr);
925 if (ret != -EPROBE_DEFER)
926 dev_err(wcss->dev, "failed to get gcc axim clock\n");
927 return ret;
928 }
929
930 wcss->ahbfabric_cbcr_clk = devm_clk_get(dev: wcss->dev,
931 id: "lcc_ahbfabric_cbc");
932 if (IS_ERR(ptr: wcss->ahbfabric_cbcr_clk)) {
933 ret = PTR_ERR(ptr: wcss->ahbfabric_cbcr_clk);
934 if (ret != -EPROBE_DEFER)
935 dev_err(wcss->dev, "failed to get ahbfabric clock\n");
936 return ret;
937 }
938
939 wcss->lcc_csr_cbcr = devm_clk_get(dev: wcss->dev, id: "tcsr_lcc_cbc");
940 if (IS_ERR(ptr: wcss->lcc_csr_cbcr)) {
941 ret = PTR_ERR(ptr: wcss->lcc_csr_cbcr);
942 if (ret != -EPROBE_DEFER)
943 dev_err(wcss->dev, "failed to get csr cbcr clk\n");
944 return ret;
945 }
946
947 wcss->ahbs_cbcr = devm_clk_get(dev: wcss->dev,
948 id: "lcc_abhs_cbc");
949 if (IS_ERR(ptr: wcss->ahbs_cbcr)) {
950 ret = PTR_ERR(ptr: wcss->ahbs_cbcr);
951 if (ret != -EPROBE_DEFER)
952 dev_err(wcss->dev, "failed to get ahbs_cbcr clk\n");
953 return ret;
954 }
955
956 wcss->tcm_slave_cbcr = devm_clk_get(dev: wcss->dev,
957 id: "lcc_tcm_slave_cbc");
958 if (IS_ERR(ptr: wcss->tcm_slave_cbcr)) {
959 ret = PTR_ERR(ptr: wcss->tcm_slave_cbcr);
960 if (ret != -EPROBE_DEFER)
961 dev_err(wcss->dev, "failed to get tcm cbcr clk\n");
962 return ret;
963 }
964
965 wcss->qdsp6ss_abhm_cbcr = devm_clk_get(dev: wcss->dev, id: "lcc_abhm_cbc");
966 if (IS_ERR(ptr: wcss->qdsp6ss_abhm_cbcr)) {
967 ret = PTR_ERR(ptr: wcss->qdsp6ss_abhm_cbcr);
968 if (ret != -EPROBE_DEFER)
969 dev_err(wcss->dev, "failed to get abhm cbcr clk\n");
970 return ret;
971 }
972
973 wcss->qdsp6ss_axim_cbcr = devm_clk_get(dev: wcss->dev, id: "lcc_axim_cbc");
974 if (IS_ERR(ptr: wcss->qdsp6ss_axim_cbcr)) {
975 ret = PTR_ERR(ptr: wcss->qdsp6ss_axim_cbcr);
976 if (ret != -EPROBE_DEFER)
977 dev_err(wcss->dev, "failed to get axim cbcr clk\n");
978 return ret;
979 }
980
981 wcss->lcc_bcr_sleep = devm_clk_get(dev: wcss->dev, id: "lcc_bcr_sleep");
982 if (IS_ERR(ptr: wcss->lcc_bcr_sleep)) {
983 ret = PTR_ERR(ptr: wcss->lcc_bcr_sleep);
984 if (ret != -EPROBE_DEFER)
985 dev_err(wcss->dev, "failed to get bcr cbcr clk\n");
986 return ret;
987 }
988
989 return 0;
990}
991
992static int q6v5_wcss_init_regulator(struct q6v5_wcss *wcss)
993{
994 wcss->cx_supply = devm_regulator_get(dev: wcss->dev, id: "cx");
995 if (IS_ERR(ptr: wcss->cx_supply))
996 return PTR_ERR(ptr: wcss->cx_supply);
997
998 regulator_set_load(regulator: wcss->cx_supply, load_uA: 100000);
999
1000 return 0;
1001}
1002
1003static int q6v5_wcss_probe(struct platform_device *pdev)
1004{
1005 const struct wcss_data *desc;
1006 struct q6v5_wcss *wcss;
1007 struct rproc *rproc;
1008 int ret;
1009
1010 desc = device_get_match_data(dev: &pdev->dev);
1011 if (!desc)
1012 return -EINVAL;
1013
1014 rproc = rproc_alloc(dev: &pdev->dev, name: pdev->name, ops: desc->ops,
1015 firmware: desc->firmware_name, len: sizeof(*wcss));
1016 if (!rproc) {
1017 dev_err(&pdev->dev, "failed to allocate rproc\n");
1018 return -ENOMEM;
1019 }
1020
1021 wcss = rproc->priv;
1022 wcss->dev = &pdev->dev;
1023 wcss->version = desc->version;
1024
1025 wcss->version = desc->version;
1026 wcss->requires_force_stop = desc->requires_force_stop;
1027
1028 ret = q6v5_wcss_init_mmio(wcss, pdev);
1029 if (ret)
1030 goto free_rproc;
1031
1032 ret = q6v5_alloc_memory_region(wcss);
1033 if (ret)
1034 goto free_rproc;
1035
1036 if (wcss->version == WCSS_QCS404) {
1037 ret = q6v5_wcss_init_clock(wcss);
1038 if (ret)
1039 goto free_rproc;
1040
1041 ret = q6v5_wcss_init_regulator(wcss);
1042 if (ret)
1043 goto free_rproc;
1044 }
1045
1046 ret = q6v5_wcss_init_reset(wcss, desc);
1047 if (ret)
1048 goto free_rproc;
1049
1050 ret = qcom_q6v5_init(q6v5: &wcss->q6v5, pdev, rproc, crash_reason: desc->crash_reason_smem, NULL, NULL);
1051 if (ret)
1052 goto free_rproc;
1053
1054 qcom_add_glink_subdev(rproc, glink: &wcss->glink_subdev, ssr_name: "q6wcss");
1055 qcom_add_ssr_subdev(rproc, ssr: &wcss->ssr_subdev, ssr_name: "q6wcss");
1056
1057 if (desc->ssctl_id)
1058 wcss->sysmon = qcom_add_sysmon_subdev(rproc,
1059 name: desc->sysmon_name,
1060 ssctl_instance: desc->ssctl_id);
1061
1062 ret = rproc_add(rproc);
1063 if (ret)
1064 goto free_rproc;
1065
1066 platform_set_drvdata(pdev, data: rproc);
1067
1068 return 0;
1069
1070free_rproc:
1071 rproc_free(rproc);
1072
1073 return ret;
1074}
1075
1076static void q6v5_wcss_remove(struct platform_device *pdev)
1077{
1078 struct rproc *rproc = platform_get_drvdata(pdev);
1079 struct q6v5_wcss *wcss = rproc->priv;
1080
1081 qcom_q6v5_deinit(q6v5: &wcss->q6v5);
1082 rproc_del(rproc);
1083 rproc_free(rproc);
1084}
1085
1086static const struct wcss_data wcss_ipq8074_res_init = {
1087 .firmware_name = "IPQ8074/q6_fw.mdt",
1088 .crash_reason_smem = WCSS_CRASH_REASON,
1089 .aon_reset_required = true,
1090 .wcss_q6_reset_required = true,
1091 .ops = &q6v5_wcss_ipq8074_ops,
1092 .requires_force_stop = true,
1093};
1094
1095static const struct wcss_data wcss_qcs404_res_init = {
1096 .crash_reason_smem = WCSS_CRASH_REASON,
1097 .firmware_name = "wcnss.mdt",
1098 .version = WCSS_QCS404,
1099 .aon_reset_required = false,
1100 .wcss_q6_reset_required = false,
1101 .ssr_name = "mpss",
1102 .sysmon_name = "wcnss",
1103 .ssctl_id = 0x12,
1104 .ops = &q6v5_wcss_qcs404_ops,
1105 .requires_force_stop = false,
1106};
1107
1108static const struct of_device_id q6v5_wcss_of_match[] = {
1109 { .compatible = "qcom,ipq8074-wcss-pil", .data = &wcss_ipq8074_res_init },
1110 { .compatible = "qcom,qcs404-wcss-pil", .data = &wcss_qcs404_res_init },
1111 { },
1112};
1113MODULE_DEVICE_TABLE(of, q6v5_wcss_of_match);
1114
1115static struct platform_driver q6v5_wcss_driver = {
1116 .probe = q6v5_wcss_probe,
1117 .remove_new = q6v5_wcss_remove,
1118 .driver = {
1119 .name = "qcom-q6v5-wcss-pil",
1120 .of_match_table = q6v5_wcss_of_match,
1121 },
1122};
1123module_platform_driver(q6v5_wcss_driver);
1124
1125MODULE_DESCRIPTION("Hexagon WCSS Peripheral Image Loader");
1126MODULE_LICENSE("GPL v2");
1127

source code of linux/drivers/remoteproc/qcom_q6v5_wcss.c