xref: /linux/drivers/remoteproc/qcom_q6v5_wcss.c (revision 69bfec7548f4c1595bac0e3ddfc0458a5af31f4c)
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
89 enum {
90 	WCSS_IPQ8074,
91 	WCSS_QCS404,
92 };
93 
94 struct 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 
107 struct 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 
154 static 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(wcss->reg_base + Q6SS_RESET_REG);
162 	val |= Q6SS_CORE_ARES | Q6SS_BUS_ARES_ENABLE | Q6SS_STOP_CORE;
163 	writel(val, wcss->reg_base + Q6SS_RESET_REG);
164 
165 	/* BHS require xo cbcr to be enabled */
166 	val = readl(wcss->reg_base + Q6SS_XO_CBCR);
167 	val |= 0x1;
168 	writel(val, 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(wcss->reg_base + Q6SS_PWR_CTL_REG);
181 	val |= Q6SS_BHS_ON;
182 	writel(val, 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, wcss->reg_base + Q6SS_PWR_CTL_REG);
188 
189 	/* Deassert Q6 compiler memory clamp */
190 	val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
191 	val &= ~Q6SS_CLAMP_QMC_MEM;
192 	writel(val, 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, wcss->reg_base + Q6SS_PWR_CTL_REG);
197 
198 	/* Turn on L1, L2, ETB and JU memories 1 at a time */
199 	val = readl(wcss->reg_base + Q6SS_MEM_PWR_CTL);
200 	for (i = MEM_BANKS; i >= 0; i--) {
201 		val |= BIT(i);
202 		writel(val, 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(wcss->reg_base + Q6SS_MEM_PWR_CTL);
209 		udelay(1);
210 	}
211 	/* Remove word line clamp */
212 	val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
213 	val &= ~Q6SS_CLAMP_WL;
214 	writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
215 
216 	/* Remove IO clamp */
217 	val &= ~Q6SS_CLAMP_IO;
218 	writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
219 
220 	/* Bring core out of reset */
221 	val = readl(wcss->reg_base + Q6SS_RESET_REG);
222 	val &= ~Q6SS_CORE_ARES;
223 	writel(val, wcss->reg_base + Q6SS_RESET_REG);
224 
225 	/* Turn on core clock */
226 	val = readl(wcss->reg_base + Q6SS_GFMUX_CTL_REG);
227 	val |= Q6SS_CLK_ENABLE;
228 	writel(val, wcss->reg_base + Q6SS_GFMUX_CTL_REG);
229 
230 	/* Start core execution */
231 	val = readl(wcss->reg_base + Q6SS_RESET_REG);
232 	val &= ~Q6SS_STOP_CORE;
233 	writel(val, wcss->reg_base + Q6SS_RESET_REG);
234 
235 	return 0;
236 }
237 
238 static int q6v5_wcss_start(struct rproc *rproc)
239 {
240 	struct q6v5_wcss *wcss = rproc->priv;
241 	int ret;
242 
243 	qcom_q6v5_prepare(&wcss->q6v5);
244 
245 	/* Release Q6 and WCSS reset */
246 	ret = reset_control_deassert(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(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(wcss->halt_map,
260 				 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(wcss->halt_map,
267 				 wcss->halt_nc + TCSR_GLOBAL_CFG1,
268 				 1, 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(rproc->bootaddr >> 4, 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(&wcss->q6v5, 5 * HZ);
280 	if (ret == -ETIMEDOUT)
281 		dev_err(wcss->dev, "start timed out\n");
282 
283 	return ret;
284 
285 wcss_q6_reset:
286 	reset_control_assert(wcss->wcss_q6_reset);
287 
288 wcss_reset:
289 	reset_control_assert(wcss->wcss_reset);
290 
291 	return ret;
292 }
293 
294 static 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(wcss->wcss_reset);
301 	usleep_range(200, 300);
302 	reset_control_deassert(wcss->wcss_reset);
303 	usleep_range(200, 300);
304 
305 	/* Enable GCC_WDSP_Q6SS_AHBS_CBCR clock */
306 	ret = clk_prepare_enable(wcss->gcc_abhs_cbcr);
307 	if (ret)
308 		return ret;
309 
310 	/* Remove reset to the WCNSS QDSP6SS */
311 	reset_control_deassert(wcss->wcss_q6_bcr_reset);
312 
313 	/* Enable Q6SSTOP_AHBFABRIC_CBCR clock */
314 	ret = clk_prepare_enable(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(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(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(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(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(wcss->qdsp6ss_axim_cbcr);
340 	if (ret)
341 		goto disable_abhm_cbcr_clk;
342 
343 	/* Enable the Q6SS XO CBC */
344 	val = readl(wcss->reg_base + Q6SS_XO_CBCR);
345 	val |= BIT(0);
346 	writel(val, 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(0, wcss->reg_base + Q6SS_CGC_OVERRIDE);
358 
359 	/* Enable QDSP6 sleep clock clock */
360 	val = readl(wcss->reg_base + Q6SS_SLEEP_CBCR);
361 	val |= BIT(0);
362 	writel(val, 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(wcss->gcc_axim_cbcr);
366 	if (ret)
367 		goto disable_sleep_cbcr_clk;
368 
369 	/* Assert resets, stop core */
370 	val = readl(wcss->reg_base + Q6SS_RESET_REG);
371 	val |= Q6SS_CORE_ARES | Q6SS_BUS_ARES_ENABLE | Q6SS_STOP_CORE;
372 	writel(val, wcss->reg_base + Q6SS_RESET_REG);
373 
374 	/* Program the QDSP6SS PWR_CTL register */
375 	writel(0x01700000, wcss->reg_base + Q6SS_PWR_CTL_REG);
376 
377 	writel(0x03700000, wcss->reg_base + Q6SS_PWR_CTL_REG);
378 
379 	writel(0x03300000, wcss->reg_base + Q6SS_PWR_CTL_REG);
380 
381 	writel(0x033C0000, 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((readl(wcss->reg_base + Q6SS_MEM_PWR_CTL) |
389 			(1 << idx)), wcss->reg_base + Q6SS_MEM_PWR_CTL);
390 	}
391 
392 	writel(0x031C0000, wcss->reg_base + Q6SS_PWR_CTL_REG);
393 	writel(0x030C0000, wcss->reg_base + Q6SS_PWR_CTL_REG);
394 
395 	val = readl(wcss->reg_base + Q6SS_RESET_REG);
396 	val &= ~Q6SS_CORE_ARES;
397 	writel(val, wcss->reg_base + Q6SS_RESET_REG);
398 
399 	/* Enable the Q6 core clock at the GFM, Q6SSTOP_QDSP6SS_GFMUX_CTL */
400 	val = readl(wcss->reg_base + Q6SS_GFMUX_CTL_REG);
401 	val |= Q6SS_CLK_ENABLE | Q6SS_SWITCH_CLK_SRC;
402 	writel(val, wcss->reg_base + Q6SS_GFMUX_CTL_REG);
403 
404 	/* Enable sleep clock branch needed for BCR circuit */
405 	ret = clk_prepare_enable(wcss->lcc_bcr_sleep);
406 	if (ret)
407 		goto disable_core_gfmux_clk;
408 
409 	return 0;
410 
411 disable_core_gfmux_clk:
412 	val = readl(wcss->reg_base + Q6SS_GFMUX_CTL_REG);
413 	val &= ~(Q6SS_CLK_ENABLE | Q6SS_SWITCH_CLK_SRC);
414 	writel(val, wcss->reg_base + Q6SS_GFMUX_CTL_REG);
415 	clk_disable_unprepare(wcss->gcc_axim_cbcr);
416 disable_sleep_cbcr_clk:
417 	val = readl(wcss->reg_base + Q6SS_SLEEP_CBCR);
418 	val &= ~Q6SS_CLK_ENABLE;
419 	writel(val, wcss->reg_base + Q6SS_SLEEP_CBCR);
420 disable_xo_cbcr_clk:
421 	val = readl(wcss->reg_base + Q6SS_XO_CBCR);
422 	val &= ~Q6SS_CLK_ENABLE;
423 	writel(val, wcss->reg_base + Q6SS_XO_CBCR);
424 	clk_disable_unprepare(wcss->qdsp6ss_axim_cbcr);
425 disable_abhm_cbcr_clk:
426 	clk_disable_unprepare(wcss->qdsp6ss_abhm_cbcr);
427 disable_tcm_slave_cbcr_clk:
428 	clk_disable_unprepare(wcss->tcm_slave_cbcr);
429 disable_ahbs_cbcr_clk:
430 	clk_disable_unprepare(wcss->ahbs_cbcr);
431 disable_csr_cbcr_clk:
432 	clk_disable_unprepare(wcss->lcc_csr_cbcr);
433 disable_ahbfabric_cbcr_clk:
434 	clk_disable_unprepare(wcss->ahbfabric_cbcr_clk);
435 disable_gcc_abhs_cbcr_clk:
436 	clk_disable_unprepare(wcss->gcc_abhs_cbcr);
437 
438 	return ret;
439 }
440 
441 static inline int q6v5_wcss_qcs404_reset(struct q6v5_wcss *wcss)
442 {
443 	unsigned long val;
444 
445 	writel(0x80800000, wcss->reg_base + Q6SS_STRAP_ACC);
446 
447 	/* Start core execution */
448 	val = readl(wcss->reg_base + Q6SS_RESET_REG);
449 	val &= ~Q6SS_STOP_CORE;
450 	writel(val, wcss->reg_base + Q6SS_RESET_REG);
451 
452 	return 0;
453 }
454 
455 static 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(wcss->xo);
461 	if (ret)
462 		return ret;
463 
464 	ret = regulator_enable(wcss->cx_supply);
465 	if (ret)
466 		goto disable_xo_clk;
467 
468 	qcom_q6v5_prepare(&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(rproc->bootaddr >> 4, wcss->reg_base + Q6SS_RST_EVB);
477 
478 	q6v5_wcss_qcs404_reset(wcss);
479 
480 	ret = qcom_q6v5_wait_for_start(&wcss->q6v5, 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 
488 disable_cx_supply:
489 	regulator_disable(wcss->cx_supply);
490 disable_xo_clk:
491 	clk_disable_unprepare(wcss->xo);
492 
493 	return ret;
494 }
495 
496 static 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(halt_map, offset + AXI_IDLE_REG, &val);
506 	if (!ret && val)
507 		return;
508 
509 	/* Assert halt request */
510 	regmap_write(halt_map, offset + AXI_HALTREQ_REG, 1);
511 
512 	/* Wait for halt */
513 	timeout = jiffies + msecs_to_jiffies(HALT_ACK_TIMEOUT_MS);
514 	for (;;) {
515 		ret = regmap_read(halt_map, offset + AXI_HALTACK_REG, &val);
516 		if (ret || val || time_after(jiffies, timeout))
517 			break;
518 
519 		msleep(1);
520 	}
521 
522 	ret = regmap_read(halt_map, offset + AXI_IDLE_REG, &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(halt_map, offset + AXI_HALTREQ_REG, 0);
528 }
529 
530 static 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, wcss->halt_map, wcss->halt_wcss);
536 
537 	/* assert clamps to avoid MX current inrush */
538 	val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
539 	val |= (Q6SS_CLAMP_IO | Q6SS_CLAMP_WL | Q6SS_CLAMP_QMC_MEM);
540 	writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
541 
542 	/* Disable memories by turning off memory foot/headswitch */
543 	writel((readl(wcss->reg_base + Q6SS_MEM_PWR_CTL) &
544 		~QDSS_Q6_MEMORIES),
545 		wcss->reg_base + Q6SS_MEM_PWR_CTL);
546 
547 	/* Clear the BHS_ON bit */
548 	val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
549 	val &= ~Q6SS_BHS_ON;
550 	writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
551 
552 	clk_disable_unprepare(wcss->ahbfabric_cbcr_clk);
553 	clk_disable_unprepare(wcss->lcc_csr_cbcr);
554 	clk_disable_unprepare(wcss->tcm_slave_cbcr);
555 	clk_disable_unprepare(wcss->qdsp6ss_abhm_cbcr);
556 	clk_disable_unprepare(wcss->qdsp6ss_axim_cbcr);
557 
558 	val = readl(wcss->reg_base + Q6SS_SLEEP_CBCR);
559 	val &= ~BIT(0);
560 	writel(val, wcss->reg_base + Q6SS_SLEEP_CBCR);
561 
562 	val = readl(wcss->reg_base + Q6SS_XO_CBCR);
563 	val &= ~BIT(0);
564 	writel(val, wcss->reg_base + Q6SS_XO_CBCR);
565 
566 	clk_disable_unprepare(wcss->ahbs_cbcr);
567 	clk_disable_unprepare(wcss->lcc_bcr_sleep);
568 
569 	val = readl(wcss->reg_base + Q6SS_GFMUX_CTL_REG);
570 	val &= ~(Q6SS_CLK_ENABLE | Q6SS_SWITCH_CLK_SRC);
571 	writel(val, wcss->reg_base + Q6SS_GFMUX_CTL_REG);
572 
573 	clk_disable_unprepare(wcss->gcc_abhs_cbcr);
574 
575 	ret = reset_control_assert(wcss->wcss_reset);
576 	if (ret) {
577 		dev_err(wcss->dev, "wcss_reset failed\n");
578 		return ret;
579 	}
580 	usleep_range(200, 300);
581 
582 	ret = reset_control_deassert(wcss->wcss_reset);
583 	if (ret) {
584 		dev_err(wcss->dev, "wcss_reset failed\n");
585 		return ret;
586 	}
587 	usleep_range(200, 300);
588 
589 	clk_disable_unprepare(wcss->gcc_axim_cbcr);
590 
591 	return 0;
592 }
593 
594 static 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, wcss->halt_map, wcss->halt_wcss);
601 
602 	/* 2 - Enable WCSSAON_CONFIG */
603 	val = readl(wcss->rmb_base + SSCAON_CONFIG);
604 	val |= SSCAON_ENABLE;
605 	writel(val, 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, wcss->rmb_base + SSCAON_CONFIG);
611 
612 	/* 4 - SSCAON_CONFIG 1 */
613 	val |= BIT(1);
614 	writel(val, 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(wcss->wcss_aon_reset);
628 
629 	/* 7 - Disable WCSSAON_CONFIG 13 */
630 	val = readl(wcss->rmb_base + SSCAON_CONFIG);
631 	val &= ~SSCAON_ENABLE;
632 	writel(val, wcss->rmb_base + SSCAON_CONFIG);
633 
634 	/* 8 - De-assert WCSS/Q6 HALTREQ */
635 	reset_control_assert(wcss->wcss_reset);
636 
637 	return 0;
638 }
639 
640 static 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, wcss->halt_map, wcss->halt_q6);
648 
649 	/* 2 - Disable Q6 Core clock */
650 	val = readl(wcss->reg_base + Q6SS_GFMUX_CTL_REG);
651 	val &= ~Q6SS_CLK_ENABLE;
652 	writel(val, wcss->reg_base + Q6SS_GFMUX_CTL_REG);
653 
654 	/* 3 - Clamp I/O */
655 	val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
656 	val |= Q6SS_CLAMP_IO;
657 	writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
658 
659 	/* 4 - Clamp WL */
660 	val |= QDSS_BHS_ON;
661 	writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
662 
663 	/* 5 - Clear Erase standby */
664 	val &= ~Q6SS_L2DATA_STBY_N;
665 	writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
666 
667 	/* 6 - Clear Sleep RTN */
668 	val &= ~Q6SS_SLP_RET_N;
669 	writel(val, 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(wcss->reg_base + Q6SS_MEM_PWR_CTL);
674 		val &= ~BIT(i);
675 		writel(val, wcss->reg_base + Q6SS_MEM_PWR_CTL);
676 		mdelay(1);
677 	}
678 
679 	/* 8 - Assert QMC memory RTN */
680 	val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
681 	val |= Q6SS_CLAMP_QMC_MEM;
682 	writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
683 
684 	/* 9 - Turn off BHS */
685 	val &= ~Q6SS_BHS_ON;
686 	writel(val, 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(wcss->wcss_reset);
700 
701 	/* 12 - Assert Q6 reset */
702 	reset_control_assert(wcss->wcss_q6_reset);
703 
704 	return 0;
705 }
706 
707 static 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(&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(&wcss->q6v5);
737 
738 	return 0;
739 }
740 
741 static 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 
753 static 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(wcss->dev, fw, rproc->firmware,
759 				    0, wcss->mem_region, wcss->mem_phys,
760 				    wcss->mem_size, &wcss->mem_reloc);
761 	if (ret)
762 		return ret;
763 
764 	qcom_pil_info_store("wcnss", wcss->mem_phys, wcss->mem_size);
765 
766 	return ret;
767 }
768 
769 static 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 
777 static 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 
786 static 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, "wcss_aon_reset");
793 		if (IS_ERR(wcss->wcss_aon_reset)) {
794 			dev_err(wcss->dev, "fail to acquire wcss_aon_reset\n");
795 			return PTR_ERR(wcss->wcss_aon_reset);
796 		}
797 	}
798 
799 	wcss->wcss_reset = devm_reset_control_get_exclusive(dev, "wcss_reset");
800 	if (IS_ERR(wcss->wcss_reset)) {
801 		dev_err(wcss->dev, "unable to acquire wcss_reset\n");
802 		return PTR_ERR(wcss->wcss_reset);
803 	}
804 
805 	if (desc->wcss_q6_reset_required) {
806 		wcss->wcss_q6_reset = devm_reset_control_get_exclusive(dev, "wcss_q6_reset");
807 		if (IS_ERR(wcss->wcss_q6_reset)) {
808 			dev_err(wcss->dev, "unable to acquire wcss_q6_reset\n");
809 			return PTR_ERR(wcss->wcss_q6_reset);
810 		}
811 	}
812 
813 	wcss->wcss_q6_bcr_reset = devm_reset_control_get_exclusive(dev, "wcss_q6_bcr_reset");
814 	if (IS_ERR(wcss->wcss_q6_bcr_reset)) {
815 		dev_err(wcss->dev, "unable to acquire wcss_q6_bcr_reset\n");
816 		return PTR_ERR(wcss->wcss_q6_bcr_reset);
817 	}
818 
819 	return 0;
820 }
821 
822 static 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(&pdev->dev, res->start,
835 				      resource_size(res));
836 	if (!wcss->reg_base)
837 		return -ENOMEM;
838 
839 	if (wcss->version == WCSS_IPQ8074) {
840 		res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rmb");
841 		wcss->rmb_base = devm_ioremap_resource(&pdev->dev, res);
842 		if (IS_ERR(wcss->rmb_base))
843 			return PTR_ERR(wcss->rmb_base);
844 	}
845 
846 	syscon = of_parse_phandle(pdev->dev.of_node,
847 				  "qcom,halt-regs", 0);
848 	if (!syscon) {
849 		dev_err(&pdev->dev, "failed to parse qcom,halt-regs\n");
850 		return -EINVAL;
851 	}
852 
853 	wcss->halt_map = syscon_node_to_regmap(syscon);
854 	of_node_put(syscon);
855 	if (IS_ERR(wcss->halt_map))
856 		return PTR_ERR(wcss->halt_map);
857 
858 	ret = of_property_read_variable_u32_array(pdev->dev.of_node,
859 						  "qcom,halt-regs",
860 						  halt_reg, 0,
861 						  MAX_HALT_REG);
862 	if (ret < 0) {
863 		dev_err(&pdev->dev, "failed to parse qcom,halt-regs\n");
864 		return -EINVAL;
865 	}
866 
867 	wcss->halt_q6 = halt_reg[0];
868 	wcss->halt_wcss = halt_reg[1];
869 	wcss->halt_nc = halt_reg[2];
870 
871 	return 0;
872 }
873 
874 static int q6v5_alloc_memory_region(struct q6v5_wcss *wcss)
875 {
876 	struct reserved_mem *rmem = NULL;
877 	struct device_node *node;
878 	struct device *dev = wcss->dev;
879 
880 	node = of_parse_phandle(dev->of_node, "memory-region", 0);
881 	if (node)
882 		rmem = of_reserved_mem_lookup(node);
883 	of_node_put(node);
884 
885 	if (!rmem) {
886 		dev_err(dev, "unable to acquire memory-region\n");
887 		return -EINVAL;
888 	}
889 
890 	wcss->mem_phys = rmem->base;
891 	wcss->mem_reloc = rmem->base;
892 	wcss->mem_size = rmem->size;
893 	wcss->mem_region = devm_ioremap_wc(dev, wcss->mem_phys, wcss->mem_size);
894 	if (!wcss->mem_region) {
895 		dev_err(dev, "unable to map memory region: %pa+%pa\n",
896 			&rmem->base, &rmem->size);
897 		return -EBUSY;
898 	}
899 
900 	return 0;
901 }
902 
903 static int q6v5_wcss_init_clock(struct q6v5_wcss *wcss)
904 {
905 	int ret;
906 
907 	wcss->xo = devm_clk_get(wcss->dev, "xo");
908 	if (IS_ERR(wcss->xo)) {
909 		ret = PTR_ERR(wcss->xo);
910 		if (ret != -EPROBE_DEFER)
911 			dev_err(wcss->dev, "failed to get xo clock");
912 		return ret;
913 	}
914 
915 	wcss->gcc_abhs_cbcr = devm_clk_get(wcss->dev, "gcc_abhs_cbcr");
916 	if (IS_ERR(wcss->gcc_abhs_cbcr)) {
917 		ret = PTR_ERR(wcss->gcc_abhs_cbcr);
918 		if (ret != -EPROBE_DEFER)
919 			dev_err(wcss->dev, "failed to get gcc abhs clock");
920 		return ret;
921 	}
922 
923 	wcss->gcc_axim_cbcr = devm_clk_get(wcss->dev, "gcc_axim_cbcr");
924 	if (IS_ERR(wcss->gcc_axim_cbcr)) {
925 		ret = PTR_ERR(wcss->gcc_axim_cbcr);
926 		if (ret != -EPROBE_DEFER)
927 			dev_err(wcss->dev, "failed to get gcc axim clock\n");
928 		return ret;
929 	}
930 
931 	wcss->ahbfabric_cbcr_clk = devm_clk_get(wcss->dev,
932 						"lcc_ahbfabric_cbc");
933 	if (IS_ERR(wcss->ahbfabric_cbcr_clk)) {
934 		ret = PTR_ERR(wcss->ahbfabric_cbcr_clk);
935 		if (ret != -EPROBE_DEFER)
936 			dev_err(wcss->dev, "failed to get ahbfabric clock\n");
937 		return ret;
938 	}
939 
940 	wcss->lcc_csr_cbcr = devm_clk_get(wcss->dev, "tcsr_lcc_cbc");
941 	if (IS_ERR(wcss->lcc_csr_cbcr)) {
942 		ret = PTR_ERR(wcss->lcc_csr_cbcr);
943 		if (ret != -EPROBE_DEFER)
944 			dev_err(wcss->dev, "failed to get csr cbcr clk\n");
945 		return ret;
946 	}
947 
948 	wcss->ahbs_cbcr = devm_clk_get(wcss->dev,
949 				       "lcc_abhs_cbc");
950 	if (IS_ERR(wcss->ahbs_cbcr)) {
951 		ret = PTR_ERR(wcss->ahbs_cbcr);
952 		if (ret != -EPROBE_DEFER)
953 			dev_err(wcss->dev, "failed to get ahbs_cbcr clk\n");
954 		return ret;
955 	}
956 
957 	wcss->tcm_slave_cbcr = devm_clk_get(wcss->dev,
958 					    "lcc_tcm_slave_cbc");
959 	if (IS_ERR(wcss->tcm_slave_cbcr)) {
960 		ret = PTR_ERR(wcss->tcm_slave_cbcr);
961 		if (ret != -EPROBE_DEFER)
962 			dev_err(wcss->dev, "failed to get tcm cbcr clk\n");
963 		return ret;
964 	}
965 
966 	wcss->qdsp6ss_abhm_cbcr = devm_clk_get(wcss->dev, "lcc_abhm_cbc");
967 	if (IS_ERR(wcss->qdsp6ss_abhm_cbcr)) {
968 		ret = PTR_ERR(wcss->qdsp6ss_abhm_cbcr);
969 		if (ret != -EPROBE_DEFER)
970 			dev_err(wcss->dev, "failed to get abhm cbcr clk\n");
971 		return ret;
972 	}
973 
974 	wcss->qdsp6ss_axim_cbcr = devm_clk_get(wcss->dev, "lcc_axim_cbc");
975 	if (IS_ERR(wcss->qdsp6ss_axim_cbcr)) {
976 		ret = PTR_ERR(wcss->qdsp6ss_axim_cbcr);
977 		if (ret != -EPROBE_DEFER)
978 			dev_err(wcss->dev, "failed to get axim cbcr clk\n");
979 		return ret;
980 	}
981 
982 	wcss->lcc_bcr_sleep = devm_clk_get(wcss->dev, "lcc_bcr_sleep");
983 	if (IS_ERR(wcss->lcc_bcr_sleep)) {
984 		ret = PTR_ERR(wcss->lcc_bcr_sleep);
985 		if (ret != -EPROBE_DEFER)
986 			dev_err(wcss->dev, "failed to get bcr cbcr clk\n");
987 		return ret;
988 	}
989 
990 	return 0;
991 }
992 
993 static int q6v5_wcss_init_regulator(struct q6v5_wcss *wcss)
994 {
995 	wcss->cx_supply = devm_regulator_get(wcss->dev, "cx");
996 	if (IS_ERR(wcss->cx_supply))
997 		return PTR_ERR(wcss->cx_supply);
998 
999 	regulator_set_load(wcss->cx_supply, 100000);
1000 
1001 	return 0;
1002 }
1003 
1004 static int q6v5_wcss_probe(struct platform_device *pdev)
1005 {
1006 	const struct wcss_data *desc;
1007 	struct q6v5_wcss *wcss;
1008 	struct rproc *rproc;
1009 	int ret;
1010 
1011 	desc = device_get_match_data(&pdev->dev);
1012 	if (!desc)
1013 		return -EINVAL;
1014 
1015 	rproc = rproc_alloc(&pdev->dev, pdev->name, desc->ops,
1016 			    desc->firmware_name, sizeof(*wcss));
1017 	if (!rproc) {
1018 		dev_err(&pdev->dev, "failed to allocate rproc\n");
1019 		return -ENOMEM;
1020 	}
1021 
1022 	wcss = rproc->priv;
1023 	wcss->dev = &pdev->dev;
1024 	wcss->version = desc->version;
1025 
1026 	wcss->version = desc->version;
1027 	wcss->requires_force_stop = desc->requires_force_stop;
1028 
1029 	ret = q6v5_wcss_init_mmio(wcss, pdev);
1030 	if (ret)
1031 		goto free_rproc;
1032 
1033 	ret = q6v5_alloc_memory_region(wcss);
1034 	if (ret)
1035 		goto free_rproc;
1036 
1037 	if (wcss->version == WCSS_QCS404) {
1038 		ret = q6v5_wcss_init_clock(wcss);
1039 		if (ret)
1040 			goto free_rproc;
1041 
1042 		ret = q6v5_wcss_init_regulator(wcss);
1043 		if (ret)
1044 			goto free_rproc;
1045 	}
1046 
1047 	ret = q6v5_wcss_init_reset(wcss, desc);
1048 	if (ret)
1049 		goto free_rproc;
1050 
1051 	ret = qcom_q6v5_init(&wcss->q6v5, pdev, rproc, desc->crash_reason_smem, NULL, NULL);
1052 	if (ret)
1053 		goto free_rproc;
1054 
1055 	qcom_add_glink_subdev(rproc, &wcss->glink_subdev, "q6wcss");
1056 	qcom_add_ssr_subdev(rproc, &wcss->ssr_subdev, "q6wcss");
1057 
1058 	if (desc->ssctl_id)
1059 		wcss->sysmon = qcom_add_sysmon_subdev(rproc,
1060 						      desc->sysmon_name,
1061 						      desc->ssctl_id);
1062 
1063 	ret = rproc_add(rproc);
1064 	if (ret)
1065 		goto free_rproc;
1066 
1067 	platform_set_drvdata(pdev, rproc);
1068 
1069 	return 0;
1070 
1071 free_rproc:
1072 	rproc_free(rproc);
1073 
1074 	return ret;
1075 }
1076 
1077 static int q6v5_wcss_remove(struct platform_device *pdev)
1078 {
1079 	struct rproc *rproc = platform_get_drvdata(pdev);
1080 	struct q6v5_wcss *wcss = rproc->priv;
1081 
1082 	qcom_q6v5_deinit(&wcss->q6v5);
1083 	rproc_del(rproc);
1084 	rproc_free(rproc);
1085 
1086 	return 0;
1087 }
1088 
1089 static const struct wcss_data wcss_ipq8074_res_init = {
1090 	.firmware_name = "IPQ8074/q6_fw.mdt",
1091 	.crash_reason_smem = WCSS_CRASH_REASON,
1092 	.aon_reset_required = true,
1093 	.wcss_q6_reset_required = true,
1094 	.ops = &q6v5_wcss_ipq8074_ops,
1095 	.requires_force_stop = true,
1096 };
1097 
1098 static const struct wcss_data wcss_qcs404_res_init = {
1099 	.crash_reason_smem = WCSS_CRASH_REASON,
1100 	.firmware_name = "wcnss.mdt",
1101 	.version = WCSS_QCS404,
1102 	.aon_reset_required = false,
1103 	.wcss_q6_reset_required = false,
1104 	.ssr_name = "mpss",
1105 	.sysmon_name = "wcnss",
1106 	.ssctl_id = 0x12,
1107 	.ops = &q6v5_wcss_qcs404_ops,
1108 	.requires_force_stop = false,
1109 };
1110 
1111 static const struct of_device_id q6v5_wcss_of_match[] = {
1112 	{ .compatible = "qcom,ipq8074-wcss-pil", .data = &wcss_ipq8074_res_init },
1113 	{ .compatible = "qcom,qcs404-wcss-pil", .data = &wcss_qcs404_res_init },
1114 	{ },
1115 };
1116 MODULE_DEVICE_TABLE(of, q6v5_wcss_of_match);
1117 
1118 static struct platform_driver q6v5_wcss_driver = {
1119 	.probe = q6v5_wcss_probe,
1120 	.remove = q6v5_wcss_remove,
1121 	.driver = {
1122 		.name = "qcom-q6v5-wcss-pil",
1123 		.of_match_table = q6v5_wcss_of_match,
1124 	},
1125 };
1126 module_platform_driver(q6v5_wcss_driver);
1127 
1128 MODULE_DESCRIPTION("Hexagon WCSS Peripheral Image Loader");
1129 MODULE_LICENSE("GPL v2");
1130