xref: /linux/drivers/media/platform/qcom/iris/iris_vpu3x.c (revision 1fd1dc41724319406b0aff221a352a400b0ddfc5)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
4  * Copyright (c) 2025 Linaro Ltd
5  */
6 
7 #include <linux/iopoll.h>
8 #include <linux/reset.h>
9 
10 #include "iris_instance.h"
11 #include "iris_vpu_common.h"
12 #include "iris_vpu_register_defines.h"
13 
14 #define AON_WRAPPER_MVP_NOC_CORE_SW_RESET	(AON_BASE_OFFS + 0x18)
15 #define SW_RESET				BIT(0)
16 #define AON_WRAPPER_MVP_NOC_CORE_CLK_CONTROL	(AON_BASE_OFFS + 0x20)
17 #define NOC_HALT				BIT(0)
18 #define AON_WRAPPER_SPARE			(AON_BASE_OFFS + 0x28)
19 
20 static bool iris_vpu3x_hw_power_collapsed(struct iris_core *core)
21 {
22 	u32 value, pwr_status;
23 
24 	value = readl(core->reg_base + WRAPPER_CORE_POWER_STATUS);
25 	pwr_status = value & BIT(1);
26 
27 	return pwr_status ? false : true;
28 }
29 
30 static void iris_vpu3_power_off_hardware(struct iris_core *core)
31 {
32 	u32 reg_val = 0, value, i;
33 	int ret;
34 
35 	if (iris_vpu3x_hw_power_collapsed(core))
36 		goto disable_power;
37 
38 	dev_err(core->dev, "video hw is power on\n");
39 
40 	value = readl(core->reg_base + WRAPPER_CORE_CLOCK_CONFIG);
41 	if (value)
42 		writel(CORE_CLK_RUN, core->reg_base + WRAPPER_CORE_CLOCK_CONFIG);
43 
44 	for (i = 0; i < core->iris_platform_data->num_vpp_pipe; i++) {
45 		ret = readl_poll_timeout(core->reg_base + VCODEC_SS_IDLE_STATUSN + 4 * i,
46 					 reg_val, reg_val & 0x400000, 2000, 20000);
47 		if (ret)
48 			goto disable_power;
49 	}
50 
51 	writel(VIDEO_NOC_RESET_REQ, core->reg_base + AON_WRAPPER_MVP_NOC_RESET_REQ);
52 
53 	ret = readl_poll_timeout(core->reg_base + AON_WRAPPER_MVP_NOC_RESET_ACK,
54 				 reg_val, reg_val & 0x3, 200, 2000);
55 	if (ret)
56 		goto disable_power;
57 
58 	writel(0x0, core->reg_base + AON_WRAPPER_MVP_NOC_RESET_REQ);
59 
60 	ret = readl_poll_timeout(core->reg_base + AON_WRAPPER_MVP_NOC_RESET_ACK,
61 				 reg_val, !(reg_val & 0x3), 200, 2000);
62 	if (ret)
63 		goto disable_power;
64 
65 	writel(CORE_BRIDGE_SW_RESET | CORE_BRIDGE_HW_RESET_DISABLE,
66 	       core->reg_base + CPU_CS_AHB_BRIDGE_SYNC_RESET);
67 	writel(CORE_BRIDGE_HW_RESET_DISABLE, core->reg_base + CPU_CS_AHB_BRIDGE_SYNC_RESET);
68 	writel(0x0, core->reg_base + CPU_CS_AHB_BRIDGE_SYNC_RESET);
69 
70 disable_power:
71 	iris_vpu_power_off_hw(core);
72 }
73 
74 static void iris_vpu33_power_off_hardware(struct iris_core *core)
75 {
76 	bool handshake_done = false, handshake_busy = false;
77 	u32 reg_val = 0, value, i;
78 	u32 count = 0;
79 	int ret;
80 
81 	if (iris_vpu3x_hw_power_collapsed(core))
82 		goto disable_power;
83 
84 	dev_err(core->dev, "video hw is power on\n");
85 
86 	value = readl(core->reg_base + WRAPPER_CORE_CLOCK_CONFIG);
87 	if (value)
88 		writel(CORE_CLK_RUN, core->reg_base + WRAPPER_CORE_CLOCK_CONFIG);
89 
90 	for (i = 0; i < core->iris_platform_data->num_vpp_pipe; i++) {
91 		ret = readl_poll_timeout(core->reg_base + VCODEC_SS_IDLE_STATUSN + 4 * i,
92 					 reg_val, reg_val & 0x400000, 2000, 20000);
93 		if (ret)
94 			goto disable_power;
95 	}
96 
97 	/* Retry up to 1000 times as recommended by hardware documentation */
98 	do {
99 		/* set MNoC to low power */
100 		writel(REQ_POWER_DOWN_PREP, core->reg_base + AON_WRAPPER_MVP_NOC_LPI_CONTROL);
101 
102 		udelay(15);
103 
104 		value = readl(core->reg_base + AON_WRAPPER_MVP_NOC_LPI_STATUS);
105 
106 		handshake_done = value & NOC_LPI_STATUS_DONE;
107 		handshake_busy = value & (NOC_LPI_STATUS_DENY | NOC_LPI_STATUS_ACTIVE);
108 
109 		if (handshake_done || !handshake_busy)
110 			break;
111 
112 		writel(0, core->reg_base + AON_WRAPPER_MVP_NOC_LPI_CONTROL);
113 
114 		udelay(15);
115 
116 	} while (++count < 1000);
117 
118 	if (!handshake_done && handshake_busy)
119 		dev_err(core->dev, "LPI handshake timeout\n");
120 
121 	ret = readl_poll_timeout(core->reg_base + AON_WRAPPER_MVP_NOC_LPI_STATUS,
122 				 reg_val, reg_val & BIT(0), 200, 2000);
123 	if (ret)
124 		goto disable_power;
125 
126 	writel(0, core->reg_base + AON_WRAPPER_MVP_NOC_LPI_CONTROL);
127 
128 	writel(CORE_BRIDGE_SW_RESET | CORE_BRIDGE_HW_RESET_DISABLE,
129 	       core->reg_base + CPU_CS_AHB_BRIDGE_SYNC_RESET);
130 	writel(CORE_BRIDGE_HW_RESET_DISABLE, core->reg_base + CPU_CS_AHB_BRIDGE_SYNC_RESET);
131 	writel(0x0, core->reg_base + CPU_CS_AHB_BRIDGE_SYNC_RESET);
132 
133 disable_power:
134 	iris_vpu_power_off_hw(core);
135 }
136 
137 static int iris_vpu33_power_off_controller(struct iris_core *core)
138 {
139 	u32 xo_rst_tbl_size = core->iris_platform_data->controller_rst_tbl_size;
140 	u32 clk_rst_tbl_size = core->iris_platform_data->clk_rst_tbl_size;
141 	u32 val = 0;
142 	int ret;
143 
144 	writel(MSK_SIGNAL_FROM_TENSILICA | MSK_CORE_POWER_ON, core->reg_base + CPU_CS_X2RPMH);
145 
146 	writel(REQ_POWER_DOWN_PREP, core->reg_base + WRAPPER_IRIS_CPU_NOC_LPI_CONTROL);
147 
148 	ret = readl_poll_timeout(core->reg_base + WRAPPER_IRIS_CPU_NOC_LPI_STATUS,
149 				 val, val & BIT(0), 200, 2000);
150 	if (ret)
151 		goto disable_power;
152 
153 	writel(0x0, core->reg_base + WRAPPER_DEBUG_BRIDGE_LPI_CONTROL);
154 
155 	ret = readl_poll_timeout(core->reg_base + WRAPPER_DEBUG_BRIDGE_LPI_STATUS,
156 				 val, val == 0, 200, 2000);
157 	if (ret)
158 		goto disable_power;
159 
160 	writel(CTL_AXI_CLK_HALT | CTL_CLK_HALT,
161 	       core->reg_base + WRAPPER_TZ_CTL_AXI_CLOCK_CONFIG);
162 	writel(RESET_HIGH, core->reg_base + WRAPPER_TZ_QNS4PDXFIFO_RESET);
163 	writel(0x0, core->reg_base + WRAPPER_TZ_QNS4PDXFIFO_RESET);
164 	writel(0x0, core->reg_base + WRAPPER_TZ_CTL_AXI_CLOCK_CONFIG);
165 
166 	reset_control_bulk_reset(clk_rst_tbl_size, core->resets);
167 
168 	/* Disable MVP NoC clock */
169 	val = readl(core->reg_base + AON_WRAPPER_MVP_NOC_CORE_CLK_CONTROL);
170 	val |= NOC_HALT;
171 	writel(val, core->reg_base + AON_WRAPPER_MVP_NOC_CORE_CLK_CONTROL);
172 
173 	/* enable MVP NoC reset */
174 	val = readl(core->reg_base + AON_WRAPPER_MVP_NOC_CORE_SW_RESET);
175 	val |= SW_RESET;
176 	writel(val, core->reg_base + AON_WRAPPER_MVP_NOC_CORE_SW_RESET);
177 
178 	/* poll AON spare register bit0 to become zero with 50ms timeout */
179 	ret = readl_poll_timeout(core->reg_base + AON_WRAPPER_SPARE,
180 				 val, (val & BIT(0)) == 0, 1000, 50000);
181 	if (ret)
182 		goto disable_power;
183 
184 	/* enable bit(1) to avoid cvp noc xo reset */
185 	val = readl(core->reg_base + AON_WRAPPER_SPARE);
186 	val |= BIT(1);
187 	writel(val, core->reg_base + AON_WRAPPER_SPARE);
188 
189 	reset_control_bulk_assert(xo_rst_tbl_size, core->controller_resets);
190 
191 	/* De-assert MVP NoC reset */
192 	val = readl(core->reg_base + AON_WRAPPER_MVP_NOC_CORE_SW_RESET);
193 	val &= ~SW_RESET;
194 	writel(val, core->reg_base + AON_WRAPPER_MVP_NOC_CORE_SW_RESET);
195 
196 	usleep_range(80, 100);
197 
198 	reset_control_bulk_deassert(xo_rst_tbl_size, core->controller_resets);
199 
200 	/* reset AON spare register */
201 	writel(0, core->reg_base + AON_WRAPPER_SPARE);
202 
203 	/* Enable MVP NoC clock */
204 	val = readl(core->reg_base + AON_WRAPPER_MVP_NOC_CORE_CLK_CONTROL);
205 	val &= ~NOC_HALT;
206 	writel(val, core->reg_base + AON_WRAPPER_MVP_NOC_CORE_CLK_CONTROL);
207 
208 	iris_disable_unprepare_clock(core, IRIS_CTRL_CLK);
209 
210 disable_power:
211 	iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_CTRL_POWER_DOMAIN]);
212 	iris_disable_unprepare_clock(core, IRIS_AXI_CLK);
213 
214 	return 0;
215 }
216 
217 static int iris_vpu35_power_on_hw(struct iris_core *core)
218 {
219 	int ret;
220 
221 	ret = iris_enable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_HW_POWER_DOMAIN]);
222 	if (ret)
223 		return ret;
224 
225 	ret = iris_prepare_enable_clock(core, IRIS_AXI_CLK);
226 	if (ret)
227 		goto err_disable_power;
228 
229 	ret = iris_prepare_enable_clock(core, IRIS_HW_FREERUN_CLK);
230 	if (ret)
231 		goto err_disable_axi_clk;
232 
233 	ret = iris_prepare_enable_clock(core, IRIS_HW_CLK);
234 	if (ret)
235 		goto err_disable_hw_free_clk;
236 
237 	ret = dev_pm_genpd_set_hwmode(core->pmdomain_tbl->pd_devs[IRIS_HW_POWER_DOMAIN], true);
238 	if (ret)
239 		goto err_disable_hw_clk;
240 
241 	return 0;
242 
243 err_disable_hw_clk:
244 	iris_disable_unprepare_clock(core, IRIS_HW_CLK);
245 err_disable_hw_free_clk:
246 	iris_disable_unprepare_clock(core, IRIS_HW_FREERUN_CLK);
247 err_disable_axi_clk:
248 	iris_disable_unprepare_clock(core, IRIS_AXI_CLK);
249 err_disable_power:
250 	iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_HW_POWER_DOMAIN]);
251 
252 	return ret;
253 }
254 
255 static void iris_vpu35_power_off_hw(struct iris_core *core)
256 {
257 	iris_vpu33_power_off_hardware(core);
258 
259 	iris_disable_unprepare_clock(core, IRIS_HW_FREERUN_CLK);
260 	iris_disable_unprepare_clock(core, IRIS_AXI_CLK);
261 }
262 
263 const struct vpu_ops iris_vpu3_ops = {
264 	.power_off_hw = iris_vpu3_power_off_hardware,
265 	.power_on_hw = iris_vpu_power_on_hw,
266 	.power_off_controller = iris_vpu_power_off_controller,
267 	.power_on_controller = iris_vpu_power_on_controller,
268 	.calc_freq = iris_vpu3x_vpu4x_calculate_frequency,
269 };
270 
271 const struct vpu_ops iris_vpu33_ops = {
272 	.power_off_hw = iris_vpu33_power_off_hardware,
273 	.power_on_hw = iris_vpu_power_on_hw,
274 	.power_off_controller = iris_vpu33_power_off_controller,
275 	.power_on_controller = iris_vpu_power_on_controller,
276 	.calc_freq = iris_vpu3x_vpu4x_calculate_frequency,
277 };
278 
279 const struct vpu_ops iris_vpu35_ops = {
280 	.power_off_hw = iris_vpu35_power_off_hw,
281 	.power_on_hw = iris_vpu35_power_on_hw,
282 	.power_off_controller = iris_vpu35_vpu4x_power_off_controller,
283 	.power_on_controller = iris_vpu35_vpu4x_power_on_controller,
284 	.program_bootup_registers = iris_vpu35_vpu4x_program_bootup_registers,
285 	.calc_freq = iris_vpu3x_vpu4x_calculate_frequency,
286 };
287