summaryrefslogtreecommitdiff
path: root/drivers/frame_provider/decoder/utils/vdec_power_ctrl.c (plain)
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 */
33bool is_support_power_ctrl(void) { return 0; }
34
35extern int no_powerdown;
36extern int hevc_max_reset_count;
37
38struct pm_name_s {
39 int type;
40 const char *name;
41};
42
43static 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
51const 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}
63EXPORT_SYMBOL(get_pm_name);
64
65static 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
74static 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
87static 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
118static 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
133static 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
150static 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
164static 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
172static 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
180static 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
187static 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
247static 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
254static void pm_vdec_legacy_power_off(struct device *dev, int id);
255
256static 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
494static 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
649static 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
689static 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
701static 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
713static 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
725static 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
737static 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
749static 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
754static 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
761static 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
768static 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
778static 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
785static 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
792const 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};
800EXPORT_SYMBOL(amlogic_vdec_matches);
801
802