Skip to content

Commit 214d94e

Browse files
Vikash Garodiagouravk-qualcomm
authored andcommitted
BACKPORT: media: iris: Introduce vpu ops for vpu4 with necessary hooks
Add power sequence for vpu4 by reusing from previous generation wherever possible. Hook up vpu4 op with vpu4 specific implemtation or resue from earlier generation wherever feasible, like clock calculation in this case. Co-developed-by: Vishnu Reddy <busanna.reddy@oss.qualcomm.com> Signed-off-by: Vishnu Reddy <busanna.reddy@oss.qualcomm.com> Signed-off-by: Vikash Garodia <vikash.garodia@oss.qualcomm.com> Reviewed-by: Dikshita Agarwal <dikshita.agarwal@oss.qualcomm.com> Signed-off-by: Bryan O'Donoghue <bod@kernel.org> Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org> Link: https://lore.kernel.org/all/20251210-knp_video-v4-6-8d11d840358a@oss.qualcomm.com/ (cherry picked from commit dde659d)
1 parent 72cbe7f commit 214d94e

4 files changed

Lines changed: 378 additions & 0 deletions

File tree

drivers/media/platform/qcom/iris/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ qcom-iris-objs += iris_buffer.o \
2222
iris_venc.o \
2323
iris_vpu2.o \
2424
iris_vpu3x.o \
25+
iris_vpu4x.o \
2526
iris_vpu_buffer.o \
2627
iris_vpu_common.o \
2728

drivers/media/platform/qcom/iris/iris_platform_common.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ enum platform_clk_type {
5757
IRIS_AXI1_CLK,
5858
IRIS_CTRL_FREERUN_CLK,
5959
IRIS_HW_FREERUN_CLK,
60+
IRIS_BSE_HW_CLK,
61+
IRIS_VPP0_HW_CLK,
62+
IRIS_VPP1_HW_CLK,
63+
IRIS_APV_HW_CLK,
6064
};
6165

6266
struct platform_clk_data {
@@ -203,6 +207,9 @@ struct icc_vote_data {
203207
enum platform_pm_domain_type {
204208
IRIS_CTRL_POWER_DOMAIN,
205209
IRIS_HW_POWER_DOMAIN,
210+
IRIS_VPP0_HW_POWER_DOMAIN,
211+
IRIS_VPP1_HW_POWER_DOMAIN,
212+
IRIS_APV_HW_POWER_DOMAIN,
206213
};
207214

208215
struct iris_platform_data {
Lines changed: 369 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,369 @@
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+
};

0 commit comments

Comments
 (0)