xref: /linux/drivers/media/platform/qcom/iris/iris_vpu4x.c (revision 1fd1dc41724319406b0aff221a352a400b0ddfc5)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved.
4  */
5 
6 #include <linux/iopoll.h>
7 #include <linux/reset.h>
8 
9 #include "iris_instance.h"
10 #include "iris_vpu_common.h"
11 #include "iris_vpu_register_defines.h"
12 
13 #define AON_WRAPPER_MVP_NOC_RESET_SYNCRST	(AON_MVP_NOC_RESET + 0x08)
14 #define CPU_CS_APV_BRIDGE_SYNC_RESET		(CPU_BASE_OFFS + 0x174)
15 #define MVP_NOC_RESET_REQ_MASK			0x70103
16 #define VPU_IDLE_BITS				0x7103
17 #define WRAPPER_EFUSE_MONITOR			(WRAPPER_BASE_OFFS + 0x08)
18 
19 #define APV_CLK_HALT		BIT(1)
20 #define CORE_CLK_HALT		BIT(0)
21 #define CORE_PWR_ON		BIT(1)
22 #define DISABLE_VIDEO_APV_BIT	BIT(27)
23 #define DISABLE_VIDEO_VPP1_BIT	BIT(28)
24 #define DISABLE_VIDEO_VPP0_BIT	BIT(29)
25 
26 static int iris_vpu4x_genpd_set_hwmode(struct iris_core *core, bool hw_mode, u32 efuse_value)
27 {
28 	int ret;
29 
30 	ret = dev_pm_genpd_set_hwmode(core->pmdomain_tbl->pd_devs[IRIS_HW_POWER_DOMAIN], hw_mode);
31 	if (ret)
32 		return ret;
33 
34 	if (!(efuse_value & DISABLE_VIDEO_VPP0_BIT)) {
35 		ret = dev_pm_genpd_set_hwmode(core->pmdomain_tbl->pd_devs
36 					      [IRIS_VPP0_HW_POWER_DOMAIN], hw_mode);
37 		if (ret)
38 			goto restore_hw_domain_mode;
39 	}
40 
41 	if (!(efuse_value & DISABLE_VIDEO_VPP1_BIT)) {
42 		ret = dev_pm_genpd_set_hwmode(core->pmdomain_tbl->pd_devs
43 					      [IRIS_VPP1_HW_POWER_DOMAIN], hw_mode);
44 		if (ret)
45 			goto restore_vpp0_domain_mode;
46 	}
47 
48 	if (!(efuse_value & DISABLE_VIDEO_APV_BIT)) {
49 		ret = dev_pm_genpd_set_hwmode(core->pmdomain_tbl->pd_devs
50 					      [IRIS_APV_HW_POWER_DOMAIN], hw_mode);
51 		if (ret)
52 			goto restore_vpp1_domain_mode;
53 	}
54 
55 	return 0;
56 
57 restore_vpp1_domain_mode:
58 	if (!(efuse_value & DISABLE_VIDEO_VPP1_BIT))
59 		dev_pm_genpd_set_hwmode(core->pmdomain_tbl->pd_devs[IRIS_VPP1_HW_POWER_DOMAIN],
60 					!hw_mode);
61 restore_vpp0_domain_mode:
62 	if (!(efuse_value & DISABLE_VIDEO_VPP0_BIT))
63 		dev_pm_genpd_set_hwmode(core->pmdomain_tbl->pd_devs[IRIS_VPP0_HW_POWER_DOMAIN],
64 					!hw_mode);
65 restore_hw_domain_mode:
66 	dev_pm_genpd_set_hwmode(core->pmdomain_tbl->pd_devs[IRIS_HW_POWER_DOMAIN], !hw_mode);
67 
68 	return ret;
69 }
70 
71 static int iris_vpu4x_power_on_apv(struct iris_core *core)
72 {
73 	int ret;
74 
75 	ret = iris_enable_power_domains(core,
76 					core->pmdomain_tbl->pd_devs[IRIS_APV_HW_POWER_DOMAIN]);
77 	if (ret)
78 		return ret;
79 
80 	ret = iris_prepare_enable_clock(core, IRIS_APV_HW_CLK);
81 	if (ret)
82 		goto disable_apv_hw_power_domain;
83 
84 	return 0;
85 
86 disable_apv_hw_power_domain:
87 	iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_APV_HW_POWER_DOMAIN]);
88 
89 	return ret;
90 }
91 
92 static void iris_vpu4x_power_off_apv(struct iris_core *core)
93 {
94 	bool handshake_done, handshake_busy;
95 	u32 value, count = 0;
96 	int ret;
97 
98 	value = readl(core->reg_base + WRAPPER_CORE_CLOCK_CONFIG);
99 
100 	if (value & APV_CLK_HALT)
101 		writel(0x0, core->reg_base + WRAPPER_CORE_CLOCK_CONFIG);
102 
103 	do {
104 		writel(REQ_POWER_DOWN_PREP, core->reg_base + AON_WRAPPER_MVP_NOC_LPI_CONTROL);
105 		usleep_range(10, 20);
106 		value = readl(core->reg_base + AON_WRAPPER_MVP_NOC_LPI_STATUS);
107 
108 		handshake_done = value & NOC_LPI_STATUS_DONE;
109 		handshake_busy = value & (NOC_LPI_STATUS_DENY | NOC_LPI_STATUS_ACTIVE);
110 
111 		if (handshake_done || !handshake_busy)
112 			break;
113 
114 		writel(0x0, core->reg_base + AON_WRAPPER_MVP_NOC_LPI_CONTROL);
115 		usleep_range(10, 20);
116 
117 	} while (++count < 1000);
118 
119 	if (!handshake_done && handshake_busy)
120 		dev_err(core->dev, "LPI handshake timeout\n");
121 
122 	writel(0x080200, core->reg_base + AON_WRAPPER_MVP_NOC_RESET_REQ);
123 	ret = readl_poll_timeout(core->reg_base + AON_WRAPPER_MVP_NOC_RESET_ACK,
124 				 value, value & 0x080200, 200, 2000);
125 	if (ret)
126 		goto disable_clocks_and_power;
127 
128 	writel(0x0, core->reg_base + AON_WRAPPER_MVP_NOC_RESET_SYNCRST);
129 	writel(0x0, core->reg_base + AON_WRAPPER_MVP_NOC_RESET_REQ);
130 	ret = readl_poll_timeout(core->reg_base + AON_WRAPPER_MVP_NOC_RESET_ACK,
131 				 value, value == 0x0, 200, 2000);
132 	if (ret)
133 		goto disable_clocks_and_power;
134 
135 	writel(CORE_BRIDGE_SW_RESET | CORE_BRIDGE_HW_RESET_DISABLE, core->reg_base +
136 	       CPU_CS_APV_BRIDGE_SYNC_RESET);
137 	writel(CORE_BRIDGE_HW_RESET_DISABLE, core->reg_base + CPU_CS_APV_BRIDGE_SYNC_RESET);
138 	writel(0x0, core->reg_base + CPU_CS_APV_BRIDGE_SYNC_RESET);
139 
140 disable_clocks_and_power:
141 	iris_disable_unprepare_clock(core, IRIS_APV_HW_CLK);
142 	iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_APV_HW_POWER_DOMAIN]);
143 }
144 
145 static void iris_vpu4x_ahb_sync_reset_apv(struct iris_core *core)
146 {
147 	writel(CORE_BRIDGE_SW_RESET | CORE_BRIDGE_HW_RESET_DISABLE, core->reg_base +
148 	       CPU_CS_APV_BRIDGE_SYNC_RESET);
149 	writel(CORE_BRIDGE_HW_RESET_DISABLE, core->reg_base + CPU_CS_APV_BRIDGE_SYNC_RESET);
150 	writel(0x0, core->reg_base + CPU_CS_APV_BRIDGE_SYNC_RESET);
151 }
152 
153 static void iris_vpu4x_ahb_sync_reset_hardware(struct iris_core *core)
154 {
155 	writel(CORE_BRIDGE_SW_RESET | CORE_BRIDGE_HW_RESET_DISABLE, core->reg_base +
156 	       CPU_CS_AHB_BRIDGE_SYNC_RESET);
157 	writel(CORE_BRIDGE_HW_RESET_DISABLE, core->reg_base + CPU_CS_AHB_BRIDGE_SYNC_RESET);
158 	writel(0x0, core->reg_base + CPU_CS_AHB_BRIDGE_SYNC_RESET);
159 }
160 
161 static int iris_vpu4x_enable_hardware_clocks(struct iris_core *core, u32 efuse_value)
162 {
163 	int ret;
164 
165 	ret = iris_prepare_enable_clock(core, IRIS_AXI_CLK);
166 	if (ret)
167 		return ret;
168 
169 	ret = iris_prepare_enable_clock(core, IRIS_HW_FREERUN_CLK);
170 	if (ret)
171 		goto disable_axi_clock;
172 
173 	ret = iris_prepare_enable_clock(core, IRIS_HW_CLK);
174 	if (ret)
175 		goto disable_hw_free_run_clock;
176 
177 	ret = iris_prepare_enable_clock(core, IRIS_BSE_HW_CLK);
178 	if (ret)
179 		goto disable_hw_clock;
180 
181 	if (!(efuse_value & DISABLE_VIDEO_VPP0_BIT)) {
182 		ret = iris_prepare_enable_clock(core, IRIS_VPP0_HW_CLK);
183 		if (ret)
184 			goto disable_bse_hw_clock;
185 	}
186 
187 	if (!(efuse_value & DISABLE_VIDEO_VPP1_BIT)) {
188 		ret = iris_prepare_enable_clock(core, IRIS_VPP1_HW_CLK);
189 		if (ret)
190 			goto disable_vpp0_hw_clock;
191 	}
192 
193 	return 0;
194 
195 disable_vpp0_hw_clock:
196 	if (!(efuse_value & DISABLE_VIDEO_VPP0_BIT))
197 		iris_disable_unprepare_clock(core, IRIS_VPP0_HW_CLK);
198 disable_bse_hw_clock:
199 	iris_disable_unprepare_clock(core, IRIS_BSE_HW_CLK);
200 disable_hw_clock:
201 	iris_disable_unprepare_clock(core, IRIS_HW_CLK);
202 disable_hw_free_run_clock:
203 	iris_disable_unprepare_clock(core, IRIS_HW_FREERUN_CLK);
204 disable_axi_clock:
205 	iris_disable_unprepare_clock(core, IRIS_AXI_CLK);
206 
207 	return ret;
208 }
209 
210 static void iris_vpu4x_disable_hardware_clocks(struct iris_core *core, u32 efuse_value)
211 {
212 	if (!(efuse_value & DISABLE_VIDEO_VPP1_BIT))
213 		iris_disable_unprepare_clock(core, IRIS_VPP1_HW_CLK);
214 
215 	if (!(efuse_value & DISABLE_VIDEO_VPP0_BIT))
216 		iris_disable_unprepare_clock(core, IRIS_VPP0_HW_CLK);
217 
218 	iris_disable_unprepare_clock(core, IRIS_BSE_HW_CLK);
219 	iris_disable_unprepare_clock(core, IRIS_HW_CLK);
220 	iris_disable_unprepare_clock(core, IRIS_HW_FREERUN_CLK);
221 	iris_disable_unprepare_clock(core, IRIS_AXI_CLK);
222 }
223 
224 static int iris_vpu4x_power_on_hardware(struct iris_core *core)
225 {
226 	u32 efuse_value = readl(core->reg_base + WRAPPER_EFUSE_MONITOR);
227 	int ret;
228 
229 	ret = iris_enable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_HW_POWER_DOMAIN]);
230 	if (ret)
231 		return ret;
232 
233 	if (!(efuse_value & DISABLE_VIDEO_VPP0_BIT)) {
234 		ret = iris_enable_power_domains(core, core->pmdomain_tbl->pd_devs
235 						[IRIS_VPP0_HW_POWER_DOMAIN]);
236 		if (ret)
237 			goto disable_hw_power_domain;
238 	}
239 
240 	if (!(efuse_value & DISABLE_VIDEO_VPP1_BIT)) {
241 		ret = iris_enable_power_domains(core, core->pmdomain_tbl->pd_devs
242 						[IRIS_VPP1_HW_POWER_DOMAIN]);
243 		if (ret)
244 			goto disable_vpp0_power_domain;
245 	}
246 
247 	ret = iris_vpu4x_enable_hardware_clocks(core, efuse_value);
248 	if (ret)
249 		goto disable_vpp1_power_domain;
250 
251 	if (!(efuse_value & DISABLE_VIDEO_APV_BIT)) {
252 		ret = iris_vpu4x_power_on_apv(core);
253 		if (ret)
254 			goto disable_hw_clocks;
255 
256 		iris_vpu4x_ahb_sync_reset_apv(core);
257 	}
258 
259 	iris_vpu4x_ahb_sync_reset_hardware(core);
260 
261 	ret = iris_vpu4x_genpd_set_hwmode(core, true, efuse_value);
262 	if (ret)
263 		goto disable_apv_power_domain;
264 
265 	return 0;
266 
267 disable_apv_power_domain:
268 	if (!(efuse_value & DISABLE_VIDEO_APV_BIT))
269 		iris_vpu4x_power_off_apv(core);
270 disable_hw_clocks:
271 	iris_vpu4x_disable_hardware_clocks(core, efuse_value);
272 disable_vpp1_power_domain:
273 	if (!(efuse_value & DISABLE_VIDEO_VPP1_BIT))
274 		iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs
275 						[IRIS_VPP1_HW_POWER_DOMAIN]);
276 disable_vpp0_power_domain:
277 	if (!(efuse_value & DISABLE_VIDEO_VPP0_BIT))
278 		iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs
279 						[IRIS_VPP0_HW_POWER_DOMAIN]);
280 disable_hw_power_domain:
281 	iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_HW_POWER_DOMAIN]);
282 
283 	return ret;
284 }
285 
286 static void iris_vpu4x_power_off_hardware(struct iris_core *core)
287 {
288 	u32 efuse_value = readl(core->reg_base + WRAPPER_EFUSE_MONITOR);
289 	bool handshake_done, handshake_busy;
290 	u32 value, count = 0;
291 	int ret;
292 
293 	iris_vpu4x_genpd_set_hwmode(core, false, efuse_value);
294 
295 	if (!(efuse_value & DISABLE_VIDEO_APV_BIT))
296 		iris_vpu4x_power_off_apv(core);
297 
298 	value = readl(core->reg_base + WRAPPER_CORE_POWER_STATUS);
299 
300 	if (!(value & CORE_PWR_ON))
301 		goto disable_clocks_and_power;
302 
303 	value = readl(core->reg_base + WRAPPER_CORE_CLOCK_CONFIG);
304 
305 	if (value & CORE_CLK_HALT)
306 		writel(0x0, core->reg_base + WRAPPER_CORE_CLOCK_CONFIG);
307 
308 	readl_poll_timeout(core->reg_base + VCODEC_SS_IDLE_STATUSN, value,
309 			   value & VPU_IDLE_BITS, 2000, 20000);
310 
311 	do {
312 		writel(REQ_POWER_DOWN_PREP, core->reg_base + AON_WRAPPER_MVP_NOC_LPI_CONTROL);
313 		usleep_range(10, 20);
314 		value = readl(core->reg_base + AON_WRAPPER_MVP_NOC_LPI_STATUS);
315 
316 		handshake_done = value & NOC_LPI_STATUS_DONE;
317 		handshake_busy = value & (NOC_LPI_STATUS_DENY | NOC_LPI_STATUS_ACTIVE);
318 
319 		if (handshake_done || !handshake_busy)
320 			break;
321 
322 		writel(0x0, core->reg_base + AON_WRAPPER_MVP_NOC_LPI_CONTROL);
323 		usleep_range(10, 20);
324 
325 	} while (++count < 1000);
326 
327 	if (!handshake_done && handshake_busy)
328 		dev_err(core->dev, "LPI handshake timeout\n");
329 
330 	writel(MVP_NOC_RESET_REQ_MASK, core->reg_base + AON_WRAPPER_MVP_NOC_RESET_REQ);
331 	ret = readl_poll_timeout(core->reg_base + AON_WRAPPER_MVP_NOC_RESET_ACK,
332 				 value, value & MVP_NOC_RESET_REQ_MASK, 200, 2000);
333 	if (ret)
334 		goto disable_clocks_and_power;
335 
336 	writel(0x0, core->reg_base + AON_WRAPPER_MVP_NOC_RESET_SYNCRST);
337 	writel(0x0, core->reg_base + AON_WRAPPER_MVP_NOC_RESET_REQ);
338 	ret = readl_poll_timeout(core->reg_base + AON_WRAPPER_MVP_NOC_RESET_ACK,
339 				 value, value == 0x0, 200, 2000);
340 	if (ret)
341 		goto disable_clocks_and_power;
342 
343 	writel(CORE_BRIDGE_SW_RESET | CORE_BRIDGE_HW_RESET_DISABLE, core->reg_base +
344 	       CPU_CS_AHB_BRIDGE_SYNC_RESET);
345 	writel(CORE_BRIDGE_HW_RESET_DISABLE, core->reg_base + CPU_CS_AHB_BRIDGE_SYNC_RESET);
346 	writel(0x0, core->reg_base + CPU_CS_AHB_BRIDGE_SYNC_RESET);
347 
348 disable_clocks_and_power:
349 	iris_vpu4x_disable_hardware_clocks(core, efuse_value);
350 
351 	if (!(efuse_value & DISABLE_VIDEO_VPP1_BIT))
352 		iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs
353 					   [IRIS_VPP1_HW_POWER_DOMAIN]);
354 
355 	if (!(efuse_value & DISABLE_VIDEO_VPP0_BIT))
356 		iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs
357 					   [IRIS_VPP0_HW_POWER_DOMAIN]);
358 
359 	iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_HW_POWER_DOMAIN]);
360 }
361 
362 const struct vpu_ops iris_vpu4x_ops = {
363 	.power_off_hw = iris_vpu4x_power_off_hardware,
364 	.power_on_hw = iris_vpu4x_power_on_hardware,
365 	.power_off_controller = iris_vpu35_vpu4x_power_off_controller,
366 	.power_on_controller = iris_vpu35_vpu4x_power_on_controller,
367 	.program_bootup_registers = iris_vpu35_vpu4x_program_bootup_registers,
368 	.calc_freq = iris_vpu3x_vpu4x_calculate_frequency,
369 };
370