blob: 36fe9d080eb8ab6ffe8cdaee7786585219a39d68
1 | /* |
2 | * drivers/amlogic/media/frame_provider/decoder/utils/vdec_power_ctrl.c |
3 | * |
4 | * Copyright (C) 2016 Amlogic, Inc. All rights reserved. |
5 | * |
6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by |
8 | * the Free Software Foundation; either version 2 of the License, or |
9 | * (at your option) any later version. |
10 | * |
11 | * This program is distributed in the hope that it will be useful, but WITHOUT |
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
14 | * more details. |
15 | * |
16 | */ |
17 | |
18 | #define DEBUG |
19 | #include "vdec_power_ctrl.h" |
20 | #include <linux/amlogic/media/utils/vdec_reg.h> |
21 | #include <linux/amlogic/power_ctrl.h> |
22 | //#include <dt-bindings/power/sc2-pd.h> |
23 | #include <linux/amlogic/pwr_ctrl.h> |
24 | #include <linux/amlogic/media/codec_mm/codec_mm.h> |
25 | #include "../../../common/media_clock/switch/amports_gate.h" |
26 | #include "../../../common/chips/decoder_cpu_ver_info.h" |
27 | #include "../../../common/media_clock/clk/clk.h" |
28 | |
29 | #define HEVC_TEST_LIMIT (100) |
30 | #define GXBB_REV_A_MINOR (0xa) |
31 | |
32 | /* wait other module to support this function */ |
33 | bool is_support_power_ctrl(void) { return 0; } |
34 | |
35 | extern int no_powerdown; |
36 | extern int hevc_max_reset_count; |
37 | |
38 | struct pm_name_s { |
39 | int type; |
40 | const char *name; |
41 | }; |
42 | |
43 | static const struct pm_name_s pm_name[] = { |
44 | {PM_POWER_CTRL_RW_REG, "legacy"}, |
45 | {PM_POWER_CTRL_API, "power-ctrl-api"}, |
46 | {PM_POWER_DOMAIN, "power-domain"}, |
47 | {PM_POWER_DOMAIN_SEC_API, "pd-sec-api"}, |
48 | {PM_POWER_DOMAIN_NONSEC_API, "pd-non-sec-api"}, |
49 | }; |
50 | |
51 | const char *get_pm_name(int type) |
52 | { |
53 | const char *name = "unknown"; |
54 | int i, size = ARRAY_SIZE(pm_name); |
55 | |
56 | for (i = 0; i < size; i++) { |
57 | if (type == pm_name[i].type) |
58 | name = pm_name[i].name; |
59 | } |
60 | |
61 | return name; |
62 | } |
63 | EXPORT_SYMBOL(get_pm_name); |
64 | |
65 | static struct pm_pd_s pm_domain_data[] = { |
66 | { .name = "pwrc-vdec", }, |
67 | { .name = "pwrc-hcodec",}, |
68 | { .name = "pwrc-vdec-2", }, |
69 | { .name = "pwrc-hevc", }, |
70 | { .name = "pwrc-hevc-b", }, |
71 | { .name = "pwrc-wave", }, |
72 | }; |
73 | |
74 | static void pm_vdec_power_switch(struct pm_pd_s *pd, int id, bool on) |
75 | { |
76 | struct device *dev = pd[id].dev; |
77 | |
78 | if (on) |
79 | pm_runtime_get_sync(dev); |
80 | else |
81 | pm_runtime_put_sync(dev); |
82 | |
83 | pr_debug("the %-15s power %s\n", |
84 | pd[id].name, on ? "on" : "off"); |
85 | } |
86 | |
87 | static int pm_vdec_power_domain_init(struct device *dev) |
88 | { |
89 | int i, err; |
90 | const struct power_manager_s *pm = of_device_get_match_data(dev); |
91 | struct pm_pd_s *pd = pm->pd_data; |
92 | |
93 | for (i = 0; i < ARRAY_SIZE(pm_domain_data); i++) { |
94 | pd[i].dev = dev_pm_domain_attach_by_name(dev, pd[i].name); |
95 | if (IS_ERR_OR_NULL(pd[i].dev)) { |
96 | err = PTR_ERR(pd[i].dev); |
97 | dev_err(dev, "Get %s failed, pm-domain: %d\n", |
98 | pd[i].name, err); |
99 | continue; |
100 | } |
101 | |
102 | pd[i].link = device_link_add(dev, pd[i].dev, |
103 | DL_FLAG_PM_RUNTIME | |
104 | DL_FLAG_STATELESS); |
105 | if (IS_ERR_OR_NULL(pd[i].link)) { |
106 | dev_err(dev, "Adding %s device link failed!\n", |
107 | pd[i].name); |
108 | return -ENODEV; |
109 | } |
110 | |
111 | pr_debug("power domain: name: %s, dev: %px, link: %px\n", |
112 | pd[i].name, pd[i].dev, pd[i].link); |
113 | } |
114 | |
115 | return 0; |
116 | } |
117 | |
118 | static void pm_vdec_power_domain_relese(struct device *dev) |
119 | { |
120 | int i; |
121 | const struct power_manager_s *pm = of_device_get_match_data(dev); |
122 | struct pm_pd_s *pd = pm->pd_data; |
123 | |
124 | for (i = 0; i < ARRAY_SIZE(pm_domain_data); i++) { |
125 | if (!IS_ERR_OR_NULL(pd[i].link)) |
126 | device_link_del(pd[i].link); |
127 | |
128 | if (!IS_ERR_OR_NULL(pd[i].dev)) |
129 | dev_pm_domain_detach(pd[i].dev, true); |
130 | } |
131 | } |
132 | |
133 | static void pm_vdec_clock_on(int id) |
134 | { |
135 | if (id == VDEC_1) { |
136 | amports_switch_gate("clk_vdec_mux", 1); |
137 | vdec_clock_hi_enable(); |
138 | } else if (id == VDEC_HCODEC) { |
139 | hcodec_clock_enable(); |
140 | } else if (id == VDEC_HEVC) { |
141 | /* enable hevc clock */ |
142 | amports_switch_gate("clk_hevc_mux", 1); |
143 | if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) |
144 | amports_switch_gate("clk_hevcb_mux", 1); |
145 | hevc_clock_hi_enable(); |
146 | hevc_back_clock_hi_enable(); |
147 | } |
148 | } |
149 | |
150 | static void pm_vdec_clock_off(int id) |
151 | { |
152 | if (id == VDEC_1) { |
153 | vdec_clock_off(); |
154 | } else if (id == VDEC_HCODEC) { |
155 | hcodec_clock_off(); |
156 | } else if (id == VDEC_HEVC) { |
157 | /* disable hevc clock */ |
158 | hevc_clock_off(); |
159 | if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) |
160 | hevc_back_clock_off(); |
161 | } |
162 | } |
163 | |
164 | static void pm_vdec_power_domain_power_on(struct device *dev, int id) |
165 | { |
166 | const struct power_manager_s *pm = of_device_get_match_data(dev); |
167 | |
168 | pm_vdec_clock_on(id); |
169 | pm_vdec_power_switch(pm->pd_data, id, true); |
170 | } |
171 | |
172 | static void pm_vdec_power_domain_power_off(struct device *dev, int id) |
173 | { |
174 | const struct power_manager_s *pm = of_device_get_match_data(dev); |
175 | |
176 | pm_vdec_clock_off(id); |
177 | pm_vdec_power_switch(pm->pd_data, id, false); |
178 | } |
179 | |
180 | static bool pm_vdec_power_domain_power_state(struct device *dev, int id) |
181 | { |
182 | const struct power_manager_s *pm = of_device_get_match_data(dev); |
183 | |
184 | return pm_runtime_active(pm->pd_data[id].dev); |
185 | } |
186 | |
187 | static bool test_hevc(u32 decomp_addr, u32 us_delay) |
188 | { |
189 | int i; |
190 | |
191 | /* SW_RESET IPP */ |
192 | WRITE_VREG(HEVCD_IPP_TOP_CNTL, 1); |
193 | WRITE_VREG(HEVCD_IPP_TOP_CNTL, 0); |
194 | |
195 | /* initialize all canvas table */ |
196 | WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 0); |
197 | for (i = 0; i < 32; i++) |
198 | WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, |
199 | 0x1 | (i << 8) | decomp_addr); |
200 | WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 1); |
201 | WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, (0 << 8) | (0<<1) | 1); |
202 | for (i = 0; i < 32; i++) |
203 | WRITE_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR, 0); |
204 | |
205 | /* Initialize mcrcc */ |
206 | WRITE_VREG(HEVCD_MCRCC_CTL1, 0x2); |
207 | WRITE_VREG(HEVCD_MCRCC_CTL2, 0x0); |
208 | WRITE_VREG(HEVCD_MCRCC_CTL3, 0x0); |
209 | WRITE_VREG(HEVCD_MCRCC_CTL1, 0xff0); |
210 | |
211 | /* Decomp initialize */ |
212 | WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, 0x0); |
213 | WRITE_VREG(HEVCD_MPP_DECOMP_CTL2, 0x0); |
214 | |
215 | /* Frame level initialization */ |
216 | WRITE_VREG(HEVCD_IPP_TOP_FRMCONFIG, 0x100 | (0x100 << 16)); |
217 | WRITE_VREG(HEVCD_IPP_TOP_TILECONFIG3, 0x0); |
218 | WRITE_VREG(HEVCD_IPP_TOP_LCUCONFIG, 0x1 << 5); |
219 | WRITE_VREG(HEVCD_IPP_BITDEPTH_CONFIG, 0x2 | (0x2 << 2)); |
220 | |
221 | WRITE_VREG(HEVCD_IPP_CONFIG, 0x0); |
222 | WRITE_VREG(HEVCD_IPP_LINEBUFF_BASE, 0x0); |
223 | |
224 | /* Enable SWIMP mode */ |
225 | WRITE_VREG(HEVCD_IPP_SWMPREDIF_CONFIG, 0x1); |
226 | |
227 | /* Enable frame */ |
228 | WRITE_VREG(HEVCD_IPP_TOP_CNTL, 0x2); |
229 | WRITE_VREG(HEVCD_IPP_TOP_FRMCTL, 0x1); |
230 | |
231 | /* Send SW-command CTB info */ |
232 | WRITE_VREG(HEVCD_IPP_SWMPREDIF_CTBINFO, 0x1 << 31); |
233 | |
234 | /* Send PU_command */ |
235 | WRITE_VREG(HEVCD_IPP_SWMPREDIF_PUINFO0, (0x4 << 9) | (0x4 << 16)); |
236 | WRITE_VREG(HEVCD_IPP_SWMPREDIF_PUINFO1, 0x1 << 3); |
237 | WRITE_VREG(HEVCD_IPP_SWMPREDIF_PUINFO2, 0x0); |
238 | WRITE_VREG(HEVCD_IPP_SWMPREDIF_PUINFO3, 0x0); |
239 | |
240 | udelay(us_delay); |
241 | |
242 | WRITE_VREG(HEVCD_IPP_DBG_SEL, 0x2 << 4); |
243 | |
244 | return (READ_VREG(HEVCD_IPP_DBG_DATA) & 3) == 1; |
245 | } |
246 | |
247 | static bool hevc_workaround_needed(void) |
248 | { |
249 | return (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_GXBB) && |
250 | (get_meson_cpu_version(MESON_CPU_VERSION_LVL_MINOR) |
251 | == GXBB_REV_A_MINOR); |
252 | } |
253 | |
254 | static void pm_vdec_legacy_power_off(struct device *dev, int id); |
255 | |
256 | static void pm_vdec_legacy_power_on(struct device *dev, int id) |
257 | { |
258 | void *decomp_addr = NULL; |
259 | dma_addr_t decomp_dma_addr; |
260 | u32 decomp_addr_aligned = 0; |
261 | int hevc_loop = 0; |
262 | int sleep_val, iso_val; |
263 | bool is_power_ctrl_ver2 = false; |
264 | |
265 | is_power_ctrl_ver2 = |
266 | ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) && |
267 | (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_TL1)) ? true : false; |
268 | |
269 | if (hevc_workaround_needed() && |
270 | (id == VDEC_HEVC)) { |
271 | decomp_addr = codec_mm_dma_alloc_coherent("vdec_prealloc", |
272 | SZ_64K + SZ_4K, &decomp_dma_addr, GFP_KERNEL, 0); |
273 | |
274 | if (decomp_addr) { |
275 | decomp_addr_aligned = ALIGN(decomp_dma_addr, SZ_64K); |
276 | memset((u8 *)decomp_addr + |
277 | (decomp_addr_aligned - decomp_dma_addr), |
278 | 0xff, SZ_4K); |
279 | } else |
280 | pr_err("vdec: alloc HEVC gxbb decomp buffer failed.\n"); |
281 | } |
282 | |
283 | if (id == VDEC_1) { |
284 | sleep_val = is_power_ctrl_ver2 ? 0x2 : 0xc; |
285 | iso_val = is_power_ctrl_ver2 ? 0x2 : 0xc0; |
286 | |
287 | /* vdec1 power on */ |
288 | #ifdef CONFIG_AMLOGIC_POWER |
289 | if (is_support_power_ctrl()) { |
290 | if (power_ctrl_sleep_mask(true, sleep_val, 0)) { |
291 | pr_err("vdec-1 power on ctrl sleep fail.\n"); |
292 | return; |
293 | } |
294 | } else { |
295 | WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0, |
296 | READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) & ~sleep_val); |
297 | } |
298 | #else |
299 | WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0, |
300 | READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) & ~sleep_val); |
301 | #endif |
302 | /* wait 10uS */ |
303 | udelay(10); |
304 | /* vdec1 soft reset */ |
305 | WRITE_VREG(DOS_SW_RESET0, 0xfffffffc); |
306 | WRITE_VREG(DOS_SW_RESET0, 0); |
307 | /* enable vdec1 clock */ |
308 | /* |
309 | *add power on vdec clock level setting,only for m8 chip, |
310 | * m8baby and m8m2 can dynamic adjust vdec clock, |
311 | * power on with default clock level |
312 | */ |
313 | amports_switch_gate("clk_vdec_mux", 1); |
314 | vdec_clock_hi_enable(); |
315 | /* power up vdec memories */ |
316 | WRITE_VREG(DOS_MEM_PD_VDEC, 0); |
317 | |
318 | /* remove vdec1 isolation */ |
319 | #ifdef CONFIG_AMLOGIC_POWER |
320 | if (is_support_power_ctrl()) { |
321 | if (power_ctrl_iso_mask(true, iso_val, 0)) { |
322 | pr_err("vdec-1 power on ctrl iso fail.\n"); |
323 | return; |
324 | } |
325 | } else { |
326 | WRITE_AOREG(AO_RTI_GEN_PWR_ISO0, |
327 | READ_AOREG(AO_RTI_GEN_PWR_ISO0) & ~iso_val); |
328 | } |
329 | #else |
330 | WRITE_AOREG(AO_RTI_GEN_PWR_ISO0, |
331 | READ_AOREG(AO_RTI_GEN_PWR_ISO0) & ~iso_val); |
332 | #endif |
333 | /* reset DOS top registers */ |
334 | WRITE_VREG(DOS_VDEC_MCRCC_STALL_CTRL, 0); |
335 | } else if (id == VDEC_2) { |
336 | if (has_vdec2()) { |
337 | /* vdec2 power on */ |
338 | WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0, |
339 | READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) & |
340 | ~0x30); |
341 | /* wait 10uS */ |
342 | udelay(10); |
343 | /* vdec2 soft reset */ |
344 | WRITE_VREG(DOS_SW_RESET2, 0xffffffff); |
345 | WRITE_VREG(DOS_SW_RESET2, 0); |
346 | /* enable vdec1 clock */ |
347 | vdec2_clock_hi_enable(); |
348 | /* power up vdec memories */ |
349 | WRITE_VREG(DOS_MEM_PD_VDEC2, 0); |
350 | /* remove vdec2 isolation */ |
351 | WRITE_AOREG(AO_RTI_GEN_PWR_ISO0, |
352 | READ_AOREG(AO_RTI_GEN_PWR_ISO0) & |
353 | ~0x300); |
354 | /* reset DOS top registers */ |
355 | WRITE_VREG(DOS_VDEC2_MCRCC_STALL_CTRL, 0); |
356 | } |
357 | } else if (id == VDEC_HCODEC) { |
358 | if (has_hdec()) { |
359 | sleep_val = is_power_ctrl_ver2 ? 0x1 : 0x3; |
360 | iso_val = is_power_ctrl_ver2 ? 0x1 : 0x30; |
361 | |
362 | /* hcodec power on */ |
363 | #ifdef CONFIG_AMLOGIC_POWER |
364 | if (is_support_power_ctrl()) { |
365 | if (power_ctrl_sleep_mask(true, sleep_val, 0)) { |
366 | pr_err("hcodec power on ctrl sleep fail.\n"); |
367 | return; |
368 | } |
369 | } else { |
370 | WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0, |
371 | READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) & ~sleep_val); |
372 | } |
373 | #else |
374 | WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0, |
375 | READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) & ~sleep_val); |
376 | #endif |
377 | /* wait 10uS */ |
378 | udelay(10); |
379 | /* hcodec soft reset */ |
380 | WRITE_VREG(DOS_SW_RESET1, 0xffffffff); |
381 | WRITE_VREG(DOS_SW_RESET1, 0); |
382 | /* enable hcodec clock */ |
383 | hcodec_clock_enable(); |
384 | /* power up hcodec memories */ |
385 | WRITE_VREG(DOS_MEM_PD_HCODEC, 0); |
386 | /* remove hcodec isolation */ |
387 | #ifdef CONFIG_AMLOGIC_POWER |
388 | if (is_support_power_ctrl()) { |
389 | if (power_ctrl_iso_mask(true, iso_val, 0)) { |
390 | pr_err("hcodec power on ctrl iso fail.\n"); |
391 | return; |
392 | } |
393 | } else { |
394 | WRITE_AOREG(AO_RTI_GEN_PWR_ISO0, |
395 | READ_AOREG(AO_RTI_GEN_PWR_ISO0) & ~iso_val); |
396 | } |
397 | #else |
398 | WRITE_AOREG(AO_RTI_GEN_PWR_ISO0, |
399 | READ_AOREG(AO_RTI_GEN_PWR_ISO0) & ~iso_val); |
400 | #endif |
401 | } |
402 | } else if (id == VDEC_HEVC) { |
403 | if (has_hevc_vdec()) { |
404 | bool hevc_fixed = false; |
405 | |
406 | sleep_val = is_power_ctrl_ver2 ? 0x4 : 0xc0; |
407 | iso_val = is_power_ctrl_ver2 ? 0x4 : 0xc00; |
408 | |
409 | while (!hevc_fixed) { |
410 | /* hevc power on */ |
411 | #ifdef CONFIG_AMLOGIC_POWER |
412 | if (is_support_power_ctrl()) { |
413 | if (power_ctrl_sleep_mask(true, sleep_val, 0)) { |
414 | pr_err("hevc power on ctrl sleep fail.\n"); |
415 | return; |
416 | } |
417 | } else { |
418 | WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0, |
419 | READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) & ~sleep_val); |
420 | } |
421 | #else |
422 | WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0, |
423 | READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) & ~sleep_val); |
424 | #endif |
425 | /* wait 10uS */ |
426 | udelay(10); |
427 | /* hevc soft reset */ |
428 | WRITE_VREG(DOS_SW_RESET3, 0xffffffff); |
429 | WRITE_VREG(DOS_SW_RESET3, 0); |
430 | /* enable hevc clock */ |
431 | amports_switch_gate("clk_hevc_mux", 1); |
432 | if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) |
433 | amports_switch_gate("clk_hevcb_mux", 1); |
434 | hevc_clock_hi_enable(); |
435 | hevc_back_clock_hi_enable(); |
436 | /* power up hevc memories */ |
437 | WRITE_VREG(DOS_MEM_PD_HEVC, 0); |
438 | /* remove hevc isolation */ |
439 | #ifdef CONFIG_AMLOGIC_POWER |
440 | if (is_support_power_ctrl()) { |
441 | if (power_ctrl_iso_mask(true, iso_val, 0)) { |
442 | pr_err("hevc power on ctrl iso fail.\n"); |
443 | return; |
444 | } |
445 | } else { |
446 | WRITE_AOREG(AO_RTI_GEN_PWR_ISO0, |
447 | READ_AOREG(AO_RTI_GEN_PWR_ISO0) & ~iso_val); |
448 | } |
449 | #else |
450 | WRITE_AOREG(AO_RTI_GEN_PWR_ISO0, |
451 | READ_AOREG(AO_RTI_GEN_PWR_ISO0) & ~iso_val); |
452 | #endif |
453 | if (!hevc_workaround_needed()) |
454 | break; |
455 | |
456 | if (decomp_addr) |
457 | hevc_fixed = test_hevc( |
458 | decomp_addr_aligned, 20); |
459 | |
460 | if (!hevc_fixed) { |
461 | hevc_loop++; |
462 | if (hevc_loop >= HEVC_TEST_LIMIT) { |
463 | pr_warn("hevc power sequence over limit\n"); |
464 | pr_warn("=====================================================\n"); |
465 | pr_warn(" This chip is identified to have HW failure.\n"); |
466 | pr_warn(" Please contact sqa-platform to replace the platform.\n"); |
467 | pr_warn("=====================================================\n"); |
468 | |
469 | panic("Force panic for chip detection !!!\n"); |
470 | |
471 | break; |
472 | } |
473 | |
474 | pm_vdec_legacy_power_off(NULL, VDEC_HEVC); |
475 | |
476 | mdelay(10); |
477 | } |
478 | } |
479 | |
480 | if (hevc_loop > hevc_max_reset_count) |
481 | hevc_max_reset_count = hevc_loop; |
482 | |
483 | WRITE_VREG(DOS_SW_RESET3, 0xffffffff); |
484 | udelay(10); |
485 | WRITE_VREG(DOS_SW_RESET3, 0); |
486 | } |
487 | } |
488 | |
489 | if (decomp_addr) |
490 | codec_mm_dma_free_coherent("vdec_prealloc", |
491 | SZ_64K + SZ_4K, decomp_addr, decomp_dma_addr, 0); |
492 | } |
493 | |
494 | static void pm_vdec_legacy_power_off(struct device *dev, int id) |
495 | { |
496 | int sleep_val, iso_val; |
497 | bool is_power_ctrl_ver2 = false; |
498 | |
499 | is_power_ctrl_ver2 = |
500 | ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) && |
501 | (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_TL1)) ? true : false; |
502 | |
503 | if (id == VDEC_1) { |
504 | sleep_val = is_power_ctrl_ver2 ? 0x2 : 0xc; |
505 | iso_val = is_power_ctrl_ver2 ? 0x2 : 0xc0; |
506 | |
507 | /* enable vdec1 isolation */ |
508 | #ifdef CONFIG_AMLOGIC_POWER |
509 | if (is_support_power_ctrl()) { |
510 | if (power_ctrl_iso_mask(false, iso_val, 0)) { |
511 | pr_err("vdec-1 power off ctrl iso fail.\n"); |
512 | return; |
513 | } |
514 | } else { |
515 | WRITE_AOREG(AO_RTI_GEN_PWR_ISO0, |
516 | READ_AOREG(AO_RTI_GEN_PWR_ISO0) | iso_val); |
517 | } |
518 | #else |
519 | WRITE_AOREG(AO_RTI_GEN_PWR_ISO0, |
520 | READ_AOREG(AO_RTI_GEN_PWR_ISO0) | iso_val); |
521 | #endif |
522 | /* power off vdec1 memories */ |
523 | WRITE_VREG(DOS_MEM_PD_VDEC, 0xffffffffUL); |
524 | /* disable vdec1 clock */ |
525 | vdec_clock_off(); |
526 | /* vdec1 power off */ |
527 | #ifdef CONFIG_AMLOGIC_POWER |
528 | if (is_support_power_ctrl()) { |
529 | if (power_ctrl_sleep_mask(false, sleep_val, 0)) { |
530 | pr_err("vdec-1 power off ctrl sleep fail.\n"); |
531 | return; |
532 | } |
533 | } else { |
534 | WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0, |
535 | READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) | sleep_val); |
536 | } |
537 | #else |
538 | WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0, |
539 | READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) | sleep_val); |
540 | #endif |
541 | } else if (id == VDEC_2) { |
542 | if (has_vdec2()) { |
543 | /* enable vdec2 isolation */ |
544 | WRITE_AOREG(AO_RTI_GEN_PWR_ISO0, |
545 | READ_AOREG(AO_RTI_GEN_PWR_ISO0) | |
546 | 0x300); |
547 | /* power off vdec2 memories */ |
548 | WRITE_VREG(DOS_MEM_PD_VDEC2, 0xffffffffUL); |
549 | /* disable vdec2 clock */ |
550 | vdec2_clock_off(); |
551 | /* vdec2 power off */ |
552 | WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0, |
553 | READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) | |
554 | 0x30); |
555 | } |
556 | } else if (id == VDEC_HCODEC) { |
557 | if (has_hdec()) { |
558 | sleep_val = is_power_ctrl_ver2 ? 0x1 : 0x3; |
559 | iso_val = is_power_ctrl_ver2 ? 0x1 : 0x30; |
560 | |
561 | /* enable hcodec isolation */ |
562 | #ifdef CONFIG_AMLOGIC_POWER |
563 | if (is_support_power_ctrl()) { |
564 | if (power_ctrl_iso_mask(false, iso_val, 0)) { |
565 | pr_err("hcodec power off ctrl iso fail.\n"); |
566 | return; |
567 | } |
568 | } else { |
569 | WRITE_AOREG(AO_RTI_GEN_PWR_ISO0, |
570 | READ_AOREG(AO_RTI_GEN_PWR_ISO0) | iso_val); |
571 | } |
572 | #else |
573 | WRITE_AOREG(AO_RTI_GEN_PWR_ISO0, |
574 | READ_AOREG(AO_RTI_GEN_PWR_ISO0) | iso_val); |
575 | #endif |
576 | /* power off hcodec memories */ |
577 | WRITE_VREG(DOS_MEM_PD_HCODEC, 0xffffffffUL); |
578 | /* disable hcodec clock */ |
579 | hcodec_clock_off(); |
580 | /* hcodec power off */ |
581 | #ifdef CONFIG_AMLOGIC_POWER |
582 | if (is_support_power_ctrl()) { |
583 | if (power_ctrl_sleep_mask(false, sleep_val, 0)) { |
584 | pr_err("hcodec power off ctrl sleep fail.\n"); |
585 | return; |
586 | } |
587 | } else { |
588 | WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0, |
589 | READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) | sleep_val); |
590 | } |
591 | #else |
592 | WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0, |
593 | READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) | sleep_val); |
594 | #endif |
595 | } |
596 | } else if (id == VDEC_HEVC) { |
597 | if (has_hevc_vdec()) { |
598 | sleep_val = is_power_ctrl_ver2 ? 0x4 : 0xc0; |
599 | iso_val = is_power_ctrl_ver2 ? 0x4 : 0xc00; |
600 | |
601 | if (no_powerdown == 0) { |
602 | /* enable hevc isolation */ |
603 | #ifdef CONFIG_AMLOGIC_POWER |
604 | if (is_support_power_ctrl()) { |
605 | if (power_ctrl_iso_mask(false, iso_val, 0)) { |
606 | pr_err("hevc power off ctrl iso fail.\n"); |
607 | return; |
608 | } |
609 | } else { |
610 | WRITE_AOREG(AO_RTI_GEN_PWR_ISO0, |
611 | READ_AOREG(AO_RTI_GEN_PWR_ISO0) | iso_val); |
612 | } |
613 | #else |
614 | WRITE_AOREG(AO_RTI_GEN_PWR_ISO0, |
615 | READ_AOREG(AO_RTI_GEN_PWR_ISO0) | iso_val); |
616 | #endif |
617 | /* power off hevc memories */ |
618 | WRITE_VREG(DOS_MEM_PD_HEVC, 0xffffffffUL); |
619 | |
620 | /* disable hevc clock */ |
621 | hevc_clock_off(); |
622 | if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) |
623 | hevc_back_clock_off(); |
624 | |
625 | /* hevc power off */ |
626 | #ifdef CONFIG_AMLOGIC_POWER |
627 | if (is_support_power_ctrl()) { |
628 | if (power_ctrl_sleep_mask(false, sleep_val, 0)) { |
629 | pr_err("hevc power off ctrl sleep fail.\n"); |
630 | return; |
631 | } |
632 | } else { |
633 | WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0, |
634 | READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) | sleep_val); |
635 | } |
636 | #else |
637 | WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0, |
638 | READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) | sleep_val); |
639 | #endif |
640 | } else { |
641 | pr_info("!!!!!!!!not power down\n"); |
642 | hevc_reset_core(NULL); |
643 | no_powerdown = 0; |
644 | } |
645 | } |
646 | } |
647 | } |
648 | |
649 | static bool pm_vdec_legacy_power_state(struct device *dev, int id) |
650 | { |
651 | bool ret = false; |
652 | |
653 | if (id == VDEC_1) { |
654 | if (((READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) & |
655 | (((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) && |
656 | (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_TL1)) |
657 | ? 0x2 : 0xc)) == 0) && |
658 | (READ_HHI_REG(HHI_VDEC_CLK_CNTL) & 0x100)) |
659 | ret = true; |
660 | } else if (id == VDEC_2) { |
661 | if (has_vdec2()) { |
662 | if (((READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) & 0x30) == 0) && |
663 | (READ_HHI_REG(HHI_VDEC2_CLK_CNTL) & 0x100)) |
664 | ret = true; |
665 | } |
666 | } else if (id == VDEC_HCODEC) { |
667 | if (has_hdec()) { |
668 | if (((READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) & |
669 | (((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) && |
670 | (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_TL1)) |
671 | ? 0x1 : 0x3)) == 0) && |
672 | (READ_HHI_REG(HHI_VDEC_CLK_CNTL) & 0x1000000)) |
673 | ret = true; |
674 | } |
675 | } else if (id == VDEC_HEVC) { |
676 | if (has_hevc_vdec()) { |
677 | if (((READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) & |
678 | (((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) && |
679 | (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_TL1)) |
680 | ? 0x4 : 0xc0)) == 0) && |
681 | (READ_HHI_REG(HHI_VDEC2_CLK_CNTL) & 0x1000000)) |
682 | ret = true; |
683 | } |
684 | } |
685 | |
686 | return ret; |
687 | } |
688 | |
689 | static void pm_vdec_pd_sec_api_power_on(struct device *dev, int id) |
690 | { |
691 | #if 0 |
692 | int pd_id = (id == VDEC_1) ? PDID_DOS_VDEC : |
693 | (id == VDEC_HEVC) ? PDID_DOS_HEVC : |
694 | PDID_DOS_HCODEC; |
695 | |
696 | pm_vdec_clock_on(id); |
697 | pwr_ctrl_psci_smc(pd_id, PWR_ON); |
698 | #endif |
699 | } |
700 | |
701 | static void pm_vdec_pd_sec_api_power_off(struct device *dev, int id) |
702 | { |
703 | #if 0 |
704 | int pd_id = (id == VDEC_1) ? PDID_DOS_VDEC : |
705 | (id == VDEC_HEVC) ? PDID_DOS_HEVC : |
706 | PDID_DOS_HCODEC; |
707 | |
708 | pm_vdec_clock_off(id); |
709 | pwr_ctrl_psci_smc(pd_id, PWR_OFF); |
710 | #endif |
711 | } |
712 | |
713 | static bool pm_vdec_pd_sec_api_power_state(struct device *dev, int id) |
714 | { |
715 | #if 0 |
716 | int pd_id = (id == VDEC_1) ? PDID_DOS_VDEC : |
717 | (id == VDEC_HEVC) ? PDID_DOS_HEVC : |
718 | PDID_DOS_HCODEC; |
719 | |
720 | return !pwr_ctrl_status_psci_smc(pd_id); |
721 | #endif |
722 | return 0; |
723 | } |
724 | |
725 | static void pm_vdec_pd_nosec_api_power_on(struct device *dev, int id) |
726 | { |
727 | #if 0 |
728 | int pd_id = (id == VDEC_1) ? PM_DOS_VDEC : |
729 | (id == VDEC_HEVC) ? PM_DOS_HEVC : |
730 | PM_DOS_HCODEC; |
731 | |
732 | pm_vdec_clock_on(id); |
733 | power_domain_switch(pd_id, PWR_ON); |
734 | #endif |
735 | } |
736 | |
737 | static void pm_vdec_pd_nosec_api_power_off(struct device *dev, int id) |
738 | { |
739 | #if 0 |
740 | int pd_id = (id == VDEC_1) ? PM_DOS_VDEC : |
741 | (id == VDEC_HEVC) ? PM_DOS_HEVC : |
742 | PM_DOS_HCODEC; |
743 | |
744 | pm_vdec_clock_off(id); |
745 | power_domain_switch(pd_id, PWR_OFF); |
746 | #endif |
747 | } |
748 | |
749 | static bool pm_vdec_pd_nosec_api_power_state(struct device *dev, int id) |
750 | { |
751 | return pm_vdec_legacy_power_state(dev, id); |
752 | } |
753 | |
754 | static const struct power_manager_s pm_rw_reg_data = { |
755 | .pm_type = PM_POWER_CTRL_RW_REG, |
756 | .power_on = pm_vdec_legacy_power_on, |
757 | .power_off = pm_vdec_legacy_power_off, |
758 | .power_state = pm_vdec_legacy_power_state, |
759 | }; |
760 | |
761 | static const struct power_manager_s pm_ctrl_api_data = { |
762 | .pm_type = PM_POWER_CTRL_API, |
763 | .power_on = pm_vdec_legacy_power_on, |
764 | .power_off = pm_vdec_legacy_power_off, |
765 | .power_state = pm_vdec_legacy_power_state, |
766 | }; |
767 | |
768 | static const struct power_manager_s pm_pd_data = { |
769 | .pm_type = PM_POWER_DOMAIN, |
770 | .pd_data = pm_domain_data, |
771 | .init = pm_vdec_power_domain_init, |
772 | .release = pm_vdec_power_domain_relese, |
773 | .power_on = pm_vdec_power_domain_power_on, |
774 | .power_off = pm_vdec_power_domain_power_off, |
775 | .power_state = pm_vdec_power_domain_power_state, |
776 | }; |
777 | |
778 | static const struct power_manager_s pm_pd_sec_api_data = { |
779 | .pm_type = PM_POWER_DOMAIN_SEC_API, |
780 | .power_on = pm_vdec_pd_sec_api_power_on, |
781 | .power_off = pm_vdec_pd_sec_api_power_off, |
782 | .power_state = pm_vdec_pd_sec_api_power_state, |
783 | }; |
784 | |
785 | static const struct power_manager_s pm_pd_nosec_api_data = { |
786 | .pm_type = PM_POWER_DOMAIN_NONSEC_API, |
787 | .power_on = pm_vdec_pd_nosec_api_power_on, |
788 | .power_off = pm_vdec_pd_nosec_api_power_off, |
789 | .power_state = pm_vdec_pd_nosec_api_power_state, |
790 | }; |
791 | |
792 | const struct of_device_id amlogic_vdec_matches[] = { |
793 | { .compatible = "amlogic, vdec", .data = &pm_rw_reg_data }, |
794 | { .compatible = "amlogic, vdec-pm-api", .data = &pm_ctrl_api_data }, |
795 | { .compatible = "amlogic, vdec-pm-pd", .data = &pm_pd_data }, |
796 | { .compatible = "amlogic, vdec-pm-pd-sec-api", .data = &pm_pd_sec_api_data }, |
797 | { .compatible = "amlogic, vdec-pm-pd-nsec-api", .data = &pm_pd_nosec_api_data }, |
798 | {}, |
799 | }; |
800 | EXPORT_SYMBOL(amlogic_vdec_matches); |
801 | |
802 |