#include <dt-bindings/power/sc2-pd.h>
#include <linux/amlogic/pwr_ctrl.h>
+#include <linux/of_device.h>
+#include "vdec_power_ctrl.h"
static DEFINE_MUTEX(vdec_mutex);
u32 debug = VDEC_DBG_ALWAYS_LOAD_FW;
EXPORT_SYMBOL(debug);
-static int hevc_max_reset_count;
+int hevc_max_reset_count;
+EXPORT_SYMBOL(hevc_max_reset_count);
+
+int no_powerdown;
+EXPORT_SYMBOL(no_powerdown);
-static int no_powerdown;
static int parallel_decode = 1;
static int fps_detection;
static int fps_clear;
struct decode_fps_s decode_fps[MAX_INSTANCE_MUN];
unsigned long buff_flag;
unsigned long stream_buff_flag;
+ struct power_manager_s *pm;
};
struct canvas_status_s {
}
EXPORT_SYMBOL(update_vdec_clk_config_settings);
-static bool hevc_workaround_needed(void)
-{
- return (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_GXBB) &&
- (get_meson_cpu_version(MESON_CPU_VERSION_LVL_MINOR)
- == GXBB_REV_A_MINOR);
-}
-
struct device *get_codec_cma_device(void)
{
return vdec_core->cma_dev;
}
}
- pr_debug("vdec_create instance %p, total %d\n", vdec,
- atomic_read(&vdec_core->vdec_nr));
+ pr_debug("vdec_create instance %p, total %d, PM: %s\n", vdec,
+ atomic_read(&vdec_core->vdec_nr),
+ get_pm_name(vdec_core->pm->pm_type));
//trace_vdec_create(vdec); /*DEBUG_TMP*/
}
#if 1 /* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */
-static bool test_hevc(u32 decomp_addr, u32 us_delay)
-{
- int i;
-
- /* SW_RESET IPP */
- WRITE_VREG(HEVCD_IPP_TOP_CNTL, 1);
- WRITE_VREG(HEVCD_IPP_TOP_CNTL, 0);
-
- /* initialize all canvas table */
- WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 0);
- for (i = 0; i < 32; i++)
- WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR,
- 0x1 | (i << 8) | decomp_addr);
- WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 1);
- WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, (0 << 8) | (0<<1) | 1);
- for (i = 0; i < 32; i++)
- WRITE_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR, 0);
-
- /* Initialize mcrcc */
- WRITE_VREG(HEVCD_MCRCC_CTL1, 0x2);
- WRITE_VREG(HEVCD_MCRCC_CTL2, 0x0);
- WRITE_VREG(HEVCD_MCRCC_CTL3, 0x0);
- WRITE_VREG(HEVCD_MCRCC_CTL1, 0xff0);
-
- /* Decomp initialize */
- WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, 0x0);
- WRITE_VREG(HEVCD_MPP_DECOMP_CTL2, 0x0);
-
- /* Frame level initialization */
- WRITE_VREG(HEVCD_IPP_TOP_FRMCONFIG, 0x100 | (0x100 << 16));
- WRITE_VREG(HEVCD_IPP_TOP_TILECONFIG3, 0x0);
- WRITE_VREG(HEVCD_IPP_TOP_LCUCONFIG, 0x1 << 5);
- WRITE_VREG(HEVCD_IPP_BITDEPTH_CONFIG, 0x2 | (0x2 << 2));
-
- WRITE_VREG(HEVCD_IPP_CONFIG, 0x0);
- WRITE_VREG(HEVCD_IPP_LINEBUFF_BASE, 0x0);
-
- /* Enable SWIMP mode */
- WRITE_VREG(HEVCD_IPP_SWMPREDIF_CONFIG, 0x1);
-
- /* Enable frame */
- WRITE_VREG(HEVCD_IPP_TOP_CNTL, 0x2);
- WRITE_VREG(HEVCD_IPP_TOP_FRMCTL, 0x1);
-
- /* Send SW-command CTB info */
- WRITE_VREG(HEVCD_IPP_SWMPREDIF_CTBINFO, 0x1 << 31);
-
- /* Send PU_command */
- WRITE_VREG(HEVCD_IPP_SWMPREDIF_PUINFO0, (0x4 << 9) | (0x4 << 16));
- WRITE_VREG(HEVCD_IPP_SWMPREDIF_PUINFO1, 0x1 << 3);
- WRITE_VREG(HEVCD_IPP_SWMPREDIF_PUINFO2, 0x0);
- WRITE_VREG(HEVCD_IPP_SWMPREDIF_PUINFO3, 0x0);
-
- udelay(us_delay);
-
- WRITE_VREG(HEVCD_IPP_DBG_SEL, 0x2 << 4);
-
- return (READ_VREG(HEVCD_IPP_DBG_DATA) & 3) == 1;
-}
-
void vdec_power_reset(void)
{
/* enable vdec1 isolation */
void vdec_poweron(enum vdec_type_e core)
{
- void *decomp_addr = NULL;
- dma_addr_t decomp_dma_addr;
- u32 decomp_addr_aligned = 0;
- int hevc_loop = 0;
- int sleep_val, iso_val;
- bool is_power_ctrl_ver2 = false;
-
if (core >= VDEC_MAX)
return;
return;
}
- if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SC2) {
- if (core == VDEC_1)
- pwr_ctrl_psci_smc(PDID_DOS_VDEC, PWR_ON);
- else if (core == VDEC_HEVC) {
- pwr_ctrl_psci_smc(PDID_DOS_HEVC, PWR_ON);
-
- /* wait 10uS */
- udelay(10);
- /* hevc soft reset */
- WRITE_VREG(DOS_SW_RESET3, 0xffffffff);
- WRITE_VREG(DOS_SW_RESET3, 0);
- /* enable hevc clock */
- amports_switch_gate("clk_hevcf_mux", 1);
- if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A)
- amports_switch_gate("clk_hevcb_mux", 1);
- hevc_clock_hi_enable();
- hevc_back_clock_hi_enable();
- /* power up hevc memories */
- WRITE_VREG(DOS_MEM_PD_HEVC, 0);
- /* remove hevc isolation */
- } else if (core == VDEC_HCODEC)
- pwr_ctrl_psci_smc(PDID_DOS_HCODEC, PWR_ON);
-
- mutex_unlock(&vdec_mutex);
-
- return;
- }
-
if (vdec_on(core)) {
mutex_unlock(&vdec_mutex);
return;
}
- is_power_ctrl_ver2 =
- ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) &&
- (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_TL1)) ? true : false;
-
- if (hevc_workaround_needed() &&
- (core == VDEC_HEVC)) {
- decomp_addr = codec_mm_dma_alloc_coherent(MEM_NAME,
- SZ_64K + SZ_4K, &decomp_dma_addr, GFP_KERNEL, 0);
-
- if (decomp_addr) {
- decomp_addr_aligned = ALIGN(decomp_dma_addr, SZ_64K);
- memset((u8 *)decomp_addr +
- (decomp_addr_aligned - decomp_dma_addr),
- 0xff, SZ_4K);
- } else
- pr_err("vdec: alloc HEVC gxbb decomp buffer failed.\n");
- }
-
- if (core == VDEC_1) {
- sleep_val = is_power_ctrl_ver2 ? 0x2 : 0xc;
- iso_val = is_power_ctrl_ver2 ? 0x2 : 0xc0;
-
- /* vdec1 power on */
-#ifdef CONFIG_AMLOGIC_POWER
- if (is_support_power_ctrl()) {
- if (power_ctrl_sleep_mask(true, sleep_val, 0)) {
- mutex_unlock(&vdec_mutex);
- pr_err("vdec-1 power on ctrl sleep fail.\n");
- return;
- }
- } else {
- WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
- READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) & ~sleep_val);
- }
-#else
- WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
- READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) & ~sleep_val);
-#endif
- /* wait 10uS */
- udelay(10);
- /* vdec1 soft reset */
- WRITE_VREG(DOS_SW_RESET0, 0xfffffffc);
- WRITE_VREG(DOS_SW_RESET0, 0);
- /* enable vdec1 clock */
- /*
- *add power on vdec clock level setting,only for m8 chip,
- * m8baby and m8m2 can dynamic adjust vdec clock,
- * power on with default clock level
- */
- amports_switch_gate("clk_vdec_mux", 1);
- vdec_clock_hi_enable();
- /* power up vdec memories */
- WRITE_VREG(DOS_MEM_PD_VDEC, 0);
-
- /* remove vdec1 isolation */
-#ifdef CONFIG_AMLOGIC_POWER
- if (is_support_power_ctrl()) {
- if (power_ctrl_iso_mask(true, iso_val, 0)) {
- mutex_unlock(&vdec_mutex);
- pr_err("vdec-1 power on ctrl iso fail.\n");
- return;
- }
- } else {
- WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
- READ_AOREG(AO_RTI_GEN_PWR_ISO0) & ~iso_val);
- }
-#else
- WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
- READ_AOREG(AO_RTI_GEN_PWR_ISO0) & ~iso_val);
-#endif
- /* reset DOS top registers */
- WRITE_VREG(DOS_VDEC_MCRCC_STALL_CTRL, 0);
- } else if (core == VDEC_2) {
- if (has_vdec2()) {
- /* vdec2 power on */
- WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
- READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) &
- ~0x30);
- /* wait 10uS */
- udelay(10);
- /* vdec2 soft reset */
- WRITE_VREG(DOS_SW_RESET2, 0xffffffff);
- WRITE_VREG(DOS_SW_RESET2, 0);
- /* enable vdec1 clock */
- vdec2_clock_hi_enable();
- /* power up vdec memories */
- WRITE_VREG(DOS_MEM_PD_VDEC2, 0);
- /* remove vdec2 isolation */
- WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
- READ_AOREG(AO_RTI_GEN_PWR_ISO0) &
- ~0x300);
- /* reset DOS top registers */
- WRITE_VREG(DOS_VDEC2_MCRCC_STALL_CTRL, 0);
- }
- } else if (core == VDEC_HCODEC) {
- if (has_hdec()) {
- sleep_val = is_power_ctrl_ver2 ? 0x1 : 0x3;
- iso_val = is_power_ctrl_ver2 ? 0x1 : 0x30;
-
- /* hcodec power on */
-#ifdef CONFIG_AMLOGIC_POWER
- if (is_support_power_ctrl()) {
- if (power_ctrl_sleep_mask(true, sleep_val, 0)) {
- mutex_unlock(&vdec_mutex);
- pr_err("hcodec power on ctrl sleep fail.\n");
- return;
- }
- } else {
- WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
- READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) & ~sleep_val);
- }
-#else
- WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
- READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) & ~sleep_val);
-#endif
- /* wait 10uS */
- udelay(10);
- /* hcodec soft reset */
- WRITE_VREG(DOS_SW_RESET1, 0xffffffff);
- WRITE_VREG(DOS_SW_RESET1, 0);
- /* enable hcodec clock */
- hcodec_clock_enable();
- /* power up hcodec memories */
- WRITE_VREG(DOS_MEM_PD_HCODEC, 0);
- /* remove hcodec isolation */
-#ifdef CONFIG_AMLOGIC_POWER
- if (is_support_power_ctrl()) {
- if (power_ctrl_iso_mask(true, iso_val, 0)) {
- mutex_unlock(&vdec_mutex);
- pr_err("hcodec power on ctrl iso fail.\n");
- return;
- }
- } else {
- WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
- READ_AOREG(AO_RTI_GEN_PWR_ISO0) & ~iso_val);
- }
-#else
- WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
- READ_AOREG(AO_RTI_GEN_PWR_ISO0) & ~iso_val);
-#endif
- }
- } else if (core == VDEC_HEVC) {
- if (has_hevc_vdec()) {
- bool hevc_fixed = false;
-
- sleep_val = is_power_ctrl_ver2 ? 0x4 : 0xc0;
- iso_val = is_power_ctrl_ver2 ? 0x4 : 0xc00;
-
- while (!hevc_fixed) {
- /* hevc power on */
-#ifdef CONFIG_AMLOGIC_POWER
- if (is_support_power_ctrl()) {
- if (power_ctrl_sleep_mask(true, sleep_val, 0)) {
- mutex_unlock(&vdec_mutex);
- pr_err("hevc power on ctrl sleep fail.\n");
- return;
- }
- } else {
- WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
- READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) & ~sleep_val);
- }
-#else
- WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
- READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) & ~sleep_val);
-#endif
- /* wait 10uS */
- udelay(10);
- /* hevc soft reset */
- WRITE_VREG(DOS_SW_RESET3, 0xffffffff);
- WRITE_VREG(DOS_SW_RESET3, 0);
- /* enable hevc clock */
- amports_switch_gate("clk_hevc_mux", 1);
- if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A)
- amports_switch_gate("clk_hevcb_mux", 1);
- hevc_clock_hi_enable();
- hevc_back_clock_hi_enable();
- /* power up hevc memories */
- WRITE_VREG(DOS_MEM_PD_HEVC, 0);
- /* remove hevc isolation */
-#ifdef CONFIG_AMLOGIC_POWER
- if (is_support_power_ctrl()) {
- if (power_ctrl_iso_mask(true, iso_val, 0)) {
- mutex_unlock(&vdec_mutex);
- pr_err("hevc power on ctrl iso fail.\n");
- return;
- }
- } else {
- WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
- READ_AOREG(AO_RTI_GEN_PWR_ISO0) & ~iso_val);
- }
-#else
- WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
- READ_AOREG(AO_RTI_GEN_PWR_ISO0) & ~iso_val);
-#endif
- if (!hevc_workaround_needed())
- break;
-
- if (decomp_addr)
- hevc_fixed = test_hevc(
- decomp_addr_aligned, 20);
-
- if (!hevc_fixed) {
- hevc_loop++;
-
- mutex_unlock(&vdec_mutex);
-
- if (hevc_loop >= HEVC_TEST_LIMIT) {
- pr_warn("hevc power sequence over limit\n");
- pr_warn("=====================================================\n");
- pr_warn(" This chip is identified to have HW failure.\n");
- pr_warn(" Please contact sqa-platform to replace the platform.\n");
- pr_warn("=====================================================\n");
-
- panic("Force panic for chip detection !!!\n");
-
- break;
- }
-
- vdec_poweroff(VDEC_HEVC);
-
- mdelay(10);
-
- mutex_lock(&vdec_mutex);
- }
- }
-
- if (hevc_loop > hevc_max_reset_count)
- hevc_max_reset_count = hevc_loop;
-
- WRITE_VREG(DOS_SW_RESET3, 0xffffffff);
- udelay(10);
- WRITE_VREG(DOS_SW_RESET3, 0);
- }
- }
-
- if (decomp_addr)
- codec_mm_dma_free_coherent(MEM_NAME,
- SZ_64K + SZ_4K, decomp_addr, decomp_dma_addr, 0);
+ vdec_core->pm->power_on(vdec_core->cma_dev, core);
mutex_unlock(&vdec_mutex);
}
void vdec_poweroff(enum vdec_type_e core)
{
- int sleep_val, iso_val;
- bool is_power_ctrl_ver2 = false;
-
if (core >= VDEC_MAX)
return;
return;
}
- if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SC2) {
- if (core == VDEC_1)
- pwr_ctrl_psci_smc(PDID_DOS_VDEC, PWR_OFF);
- else if (core == VDEC_HEVC) {
- pwr_ctrl_psci_smc(PDID_DOS_HEVC, PWR_OFF);
-
- /* disable hevc clock */
- hevc_clock_off();
- if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A)
- hevc_back_clock_off();
- }
- else if (core == VDEC_HCODEC)
- pwr_ctrl_psci_smc(PDID_DOS_HCODEC, PWR_OFF);
-
- mutex_unlock(&vdec_mutex);
- return;
- }
-
- is_power_ctrl_ver2 =
- ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) &&
- (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_TL1)) ? true : false;
-
- if (core == VDEC_1) {
- sleep_val = is_power_ctrl_ver2 ? 0x2 : 0xc;
- iso_val = is_power_ctrl_ver2 ? 0x2 : 0xc0;
-
- /* enable vdec1 isolation */
-#ifdef CONFIG_AMLOGIC_POWER
- if (is_support_power_ctrl()) {
- if (power_ctrl_iso_mask(false, iso_val, 0)) {
- mutex_unlock(&vdec_mutex);
- pr_err("vdec-1 power off ctrl iso fail.\n");
- return;
- }
- } else {
- WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
- READ_AOREG(AO_RTI_GEN_PWR_ISO0) | iso_val);
- }
-#else
- WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
- READ_AOREG(AO_RTI_GEN_PWR_ISO0) | iso_val);
-#endif
- /* power off vdec1 memories */
- WRITE_VREG(DOS_MEM_PD_VDEC, 0xffffffffUL);
- /* disable vdec1 clock */
- vdec_clock_off();
- /* vdec1 power off */
-#ifdef CONFIG_AMLOGIC_POWER
- if (is_support_power_ctrl()) {
- if (power_ctrl_sleep_mask(false, sleep_val, 0)) {
- mutex_unlock(&vdec_mutex);
- pr_err("vdec-1 power off ctrl sleep fail.\n");
- return;
- }
- } else {
- WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
- READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) | sleep_val);
- }
-#else
- WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
- READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) | sleep_val);
-#endif
- } else if (core == VDEC_2) {
- if (has_vdec2()) {
- /* enable vdec2 isolation */
- WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
- READ_AOREG(AO_RTI_GEN_PWR_ISO0) |
- 0x300);
- /* power off vdec2 memories */
- WRITE_VREG(DOS_MEM_PD_VDEC2, 0xffffffffUL);
- /* disable vdec2 clock */
- vdec2_clock_off();
- /* vdec2 power off */
- WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
- READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) |
- 0x30);
- }
- } else if (core == VDEC_HCODEC) {
- if (has_hdec()) {
- sleep_val = is_power_ctrl_ver2 ? 0x1 : 0x3;
- iso_val = is_power_ctrl_ver2 ? 0x1 : 0x30;
-
- /* enable hcodec isolation */
-#ifdef CONFIG_AMLOGIC_POWER
- if (is_support_power_ctrl()) {
- if (power_ctrl_iso_mask(false, iso_val, 0)) {
- mutex_unlock(&vdec_mutex);
- pr_err("hcodec power off ctrl iso fail.\n");
- return;
- }
- } else {
- WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
- READ_AOREG(AO_RTI_GEN_PWR_ISO0) | iso_val);
- }
-#else
- WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
- READ_AOREG(AO_RTI_GEN_PWR_ISO0) | iso_val);
-#endif
- /* power off hcodec memories */
- WRITE_VREG(DOS_MEM_PD_HCODEC, 0xffffffffUL);
- /* disable hcodec clock */
- hcodec_clock_off();
- /* hcodec power off */
-#ifdef CONFIG_AMLOGIC_POWER
- if (is_support_power_ctrl()) {
- if (power_ctrl_sleep_mask(false, sleep_val, 0)) {
- mutex_unlock(&vdec_mutex);
- pr_err("hcodec power off ctrl sleep fail.\n");
- return;
- }
- } else {
- WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
- READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) | sleep_val);
- }
-#else
- WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
- READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) | sleep_val);
-#endif
- }
- } else if (core == VDEC_HEVC) {
- if (has_hevc_vdec()) {
- sleep_val = is_power_ctrl_ver2 ? 0x4 : 0xc0;
- iso_val = is_power_ctrl_ver2 ? 0x4 : 0xc00;
-
- if (no_powerdown == 0) {
- /* enable hevc isolation */
-#ifdef CONFIG_AMLOGIC_POWER
- if (is_support_power_ctrl()) {
- if (power_ctrl_iso_mask(false, iso_val, 0)) {
- mutex_unlock(&vdec_mutex);
- pr_err("hevc power off ctrl iso fail.\n");
- return;
- }
- } else {
- WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
- READ_AOREG(AO_RTI_GEN_PWR_ISO0) | iso_val);
- }
-#else
- WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
- READ_AOREG(AO_RTI_GEN_PWR_ISO0) | iso_val);
-#endif
- /* power off hevc memories */
- WRITE_VREG(DOS_MEM_PD_HEVC, 0xffffffffUL);
-
- /* disable hevc clock */
- hevc_clock_off();
- if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A)
- hevc_back_clock_off();
+ vdec_core->pm->power_off(vdec_core->cma_dev, core);
- /* hevc power off */
-#ifdef CONFIG_AMLOGIC_POWER
- if (is_support_power_ctrl()) {
- if (power_ctrl_sleep_mask(false, sleep_val, 0)) {
- mutex_unlock(&vdec_mutex);
- pr_err("hevc power off ctrl sleep fail.\n");
- return;
- }
- } else {
- WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
- READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) | sleep_val);
- }
-#else
- WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
- READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) | sleep_val);
-#endif
- } else {
- pr_info("!!!!!!!!not power down\n");
- hevc_reset_core(NULL);
- no_powerdown = 0;
- }
- }
- }
mutex_unlock(&vdec_mutex);
}
EXPORT_SYMBOL(vdec_poweroff);
bool vdec_on(enum vdec_type_e core)
{
- bool ret = false;
-
- if (core == VDEC_1) {
- if (((READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) &
- (((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) &&
- (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_TL1))
- ? 0x2 : 0xc)) == 0) &&
- (READ_HHI_REG(HHI_VDEC_CLK_CNTL) & 0x100))
- ret = true;
- } else if (core == VDEC_2) {
- if (has_vdec2()) {
- if (((READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) & 0x30) == 0) &&
- (READ_HHI_REG(HHI_VDEC2_CLK_CNTL) & 0x100))
- ret = true;
- }
- } else if (core == VDEC_HCODEC) {
- if (has_hdec()) {
- if (((READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) &
- (((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) &&
- (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_TL1))
- ? 0x1 : 0x3)) == 0) &&
- (READ_HHI_REG(HHI_VDEC_CLK_CNTL) & 0x1000000))
- ret = true;
- }
- } else if (core == VDEC_HEVC) {
- if (has_hevc_vdec()) {
- if (((READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) &
- (((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) &&
- (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_TL1))
- ? 0x4 : 0xc0)) == 0) &&
- (READ_HHI_REG(HHI_VDEC2_CLK_CNTL) & 0x1000000))
- ret = true;
- }
- }
-
- return ret;
+ return vdec_core->pm->power_state(vdec_core->cma_dev, core);
}
EXPORT_SYMBOL(vdec_on);
vdec_core->vdec_core_wq = alloc_ordered_workqueue("%s",__WQ_LEGACY |
WQ_MEM_RECLAIM |WQ_HIGHPRI/*high priority*/, "vdec-work");
/*work queue priority lower than vdec-core.*/
+
+ /* power manager init. */
+ vdec_core->pm = (struct power_manager_s *)
+ of_device_get_match_data(&pdev->dev);
+ if (vdec_core->pm->init) {
+ r = vdec_core->pm->init(&pdev->dev);
+ if (r) {
+ pr_err("vdec power manager init failed\n");
+ return r;
+ }
+ }
+
return 0;
}
kthread_stop(vdec_core->thread);
destroy_workqueue(vdec_core->vdec_core_wq);
+
+ if (vdec_core->pm->release)
+ vdec_core->pm->release(&pdev->dev);
+
class_unregister(&vdec_class);
return 0;
}
-static const struct of_device_id amlogic_vdec_dt_match[] = {
- {
- .compatible = "amlogic, vdec",
- },
- {},
-};
-
static struct mconfig vdec_configs[] = {
MC_PU32("debug_trace_num", &debug_trace_num),
MC_PI32("hevc_max_reset_count", &hevc_max_reset_count),
};
static struct mconfig_node vdec_node;
+extern const struct of_device_id amlogic_vdec_matches[];
+
static struct platform_driver vdec_driver = {
.probe = vdec_probe,
.remove = vdec_remove,
.driver = {
.name = "vdec",
- .of_match_table = amlogic_vdec_dt_match,
+ .of_match_table = amlogic_vdec_matches,
}
};
--- /dev/null
+/*
+ * drivers/amlogic/media/frame_provider/decoder/utils/vdec_power_ctrl.c
+ *
+ * Copyright (C) 2016 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#define DEBUG
+#include "vdec_power_ctrl.h"
+#include <linux/amlogic/media/utils/vdec_reg.h>
+#include <linux/amlogic/power_ctrl.h>
+#include <dt-bindings/power/sc2-pd.h>
+#include <linux/amlogic/pwr_ctrl.h>
+#include <linux/amlogic/media/codec_mm/codec_mm.h>
+#include "../../../common/media_clock/switch/amports_gate.h"
+#include "../../../common/chips/decoder_cpu_ver_info.h"
+#include "../../../common/media_clock/clk/clk.h"
+
+#define HEVC_TEST_LIMIT (100)
+#define GXBB_REV_A_MINOR (0xa)
+
+extern int no_powerdown;
+extern int hevc_max_reset_count;
+
+struct pm_name_s {
+ int type;
+ const char *name;
+};
+
+static const struct pm_name_s pm_name[] = {
+ {PM_POWER_CTRL_RW_REG, "legacy"},
+ {PM_POWER_CTRL_API, "power-ctrl-api"},
+ {PM_POWER_DOMAIN, "power-domain"},
+ {PM_POWER_DOMAIN_SEC_API, "pd-sec-api"},
+ {PM_POWER_DOMAIN_NONSEC_API, "pd-non-sec-api"},
+};
+
+const char *get_pm_name(int type)
+{
+ const char *name = "unknown";
+ int i, size = ARRAY_SIZE(pm_name);
+
+ for (i = 0; i < size; i++) {
+ if (type == pm_name[i].type)
+ name = pm_name[i].name;
+ }
+
+ return name;
+}
+EXPORT_SYMBOL(get_pm_name);
+
+static struct pm_pd_s pm_domain_data[] = {
+ { .name = "pwrc-vdec", },
+ { .name = "pwrc-hcodec",},
+ { .name = "pwrc-vdec-2", },
+ { .name = "pwrc-hevc", },
+ { .name = "pwrc-hevc-b", },
+ { .name = "pwrc-wave", },
+};
+
+static void pm_vdec_power_switch(struct pm_pd_s *pd, int id, bool on)
+{
+ struct device *dev = pd[id].dev;
+
+ if (on)
+ pm_runtime_get_sync(dev);
+ else
+ pm_runtime_put_sync(dev);
+
+ pr_debug("the %-15s power %s\n",
+ pd[id].name, on ? "on" : "off");
+}
+
+static int pm_vdec_power_domain_init(struct device *dev)
+{
+ int i, err;
+ const struct power_manager_s *pm = of_device_get_match_data(dev);
+ struct pm_pd_s *pd = pm->pd_data;
+
+ for (i = 0; i < ARRAY_SIZE(pm_domain_data); i++) {
+ pd[i].dev = dev_pm_domain_attach_by_name(dev, pd[i].name);
+ if (IS_ERR_OR_NULL(pd[i].dev)) {
+ err = PTR_ERR(pd[i].dev);
+ dev_err(dev, "Get %s failed, pm-domain: %d\n",
+ pd[i].name, err);
+ continue;
+ }
+
+ pd[i].link = device_link_add(dev, pd[i].dev,
+ DL_FLAG_PM_RUNTIME |
+ DL_FLAG_STATELESS);
+ if (IS_ERR_OR_NULL(pd[i].link)) {
+ dev_err(dev, "Adding %s device link failed!\n",
+ pd[i].name);
+ return -ENODEV;
+ }
+
+ pr_debug("power domain: name: %s, dev: %px, link: %px\n",
+ pd[i].name, pd[i].dev, pd[i].link);
+ }
+
+ return 0;
+}
+
+static void pm_vdec_power_domain_relese(struct device *dev)
+{
+ int i;
+ const struct power_manager_s *pm = of_device_get_match_data(dev);
+ struct pm_pd_s *pd = pm->pd_data;
+
+ for (i = 0; i < ARRAY_SIZE(pm_domain_data); i++) {
+ if (!IS_ERR_OR_NULL(pd[i].link))
+ device_link_del(pd[i].link);
+
+ if (!IS_ERR_OR_NULL(pd[i].dev))
+ dev_pm_domain_detach(pd[i].dev, true);
+ }
+}
+
+static void pm_vdec_clock_on(int id)
+{
+ if (id == VDEC_1) {
+ amports_switch_gate("clk_vdec_mux", 1);
+ vdec_clock_hi_enable();
+ } else if (id == VDEC_HCODEC) {
+ hcodec_clock_enable();
+ } else if (id == VDEC_HEVC) {
+ /* enable hevc clock */
+ amports_switch_gate("clk_hevc_mux", 1);
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A)
+ amports_switch_gate("clk_hevcb_mux", 1);
+ hevc_clock_hi_enable();
+ hevc_back_clock_hi_enable();
+ }
+}
+
+static void pm_vdec_clock_off(int id)
+{
+ if (id == VDEC_1) {
+ vdec_clock_off();
+ } else if (id == VDEC_HCODEC) {
+ hcodec_clock_off();
+ } else if (id == VDEC_HEVC) {
+ /* disable hevc clock */
+ hevc_clock_off();
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A)
+ hevc_back_clock_off();
+ }
+}
+
+static void pm_vdec_power_domain_power_on(struct device *dev, int id)
+{
+ const struct power_manager_s *pm = of_device_get_match_data(dev);
+
+ pm_vdec_clock_on(id);
+ pm_vdec_power_switch(pm->pd_data, id, true);
+}
+
+static void pm_vdec_power_domain_power_off(struct device *dev, int id)
+{
+ const struct power_manager_s *pm = of_device_get_match_data(dev);
+
+ pm_vdec_clock_off(id);
+ pm_vdec_power_switch(pm->pd_data, id, false);
+}
+
+static bool pm_vdec_power_domain_power_state(struct device *dev, int id)
+{
+ const struct power_manager_s *pm = of_device_get_match_data(dev);
+
+ return pm_runtime_active(pm->pd_data[id].dev);
+}
+
+static bool test_hevc(u32 decomp_addr, u32 us_delay)
+{
+ int i;
+
+ /* SW_RESET IPP */
+ WRITE_VREG(HEVCD_IPP_TOP_CNTL, 1);
+ WRITE_VREG(HEVCD_IPP_TOP_CNTL, 0);
+
+ /* initialize all canvas table */
+ WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 0);
+ for (i = 0; i < 32; i++)
+ WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR,
+ 0x1 | (i << 8) | decomp_addr);
+ WRITE_VREG(HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 1);
+ WRITE_VREG(HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, (0 << 8) | (0<<1) | 1);
+ for (i = 0; i < 32; i++)
+ WRITE_VREG(HEVCD_MPP_ANC_CANVAS_DATA_ADDR, 0);
+
+ /* Initialize mcrcc */
+ WRITE_VREG(HEVCD_MCRCC_CTL1, 0x2);
+ WRITE_VREG(HEVCD_MCRCC_CTL2, 0x0);
+ WRITE_VREG(HEVCD_MCRCC_CTL3, 0x0);
+ WRITE_VREG(HEVCD_MCRCC_CTL1, 0xff0);
+
+ /* Decomp initialize */
+ WRITE_VREG(HEVCD_MPP_DECOMP_CTL1, 0x0);
+ WRITE_VREG(HEVCD_MPP_DECOMP_CTL2, 0x0);
+
+ /* Frame level initialization */
+ WRITE_VREG(HEVCD_IPP_TOP_FRMCONFIG, 0x100 | (0x100 << 16));
+ WRITE_VREG(HEVCD_IPP_TOP_TILECONFIG3, 0x0);
+ WRITE_VREG(HEVCD_IPP_TOP_LCUCONFIG, 0x1 << 5);
+ WRITE_VREG(HEVCD_IPP_BITDEPTH_CONFIG, 0x2 | (0x2 << 2));
+
+ WRITE_VREG(HEVCD_IPP_CONFIG, 0x0);
+ WRITE_VREG(HEVCD_IPP_LINEBUFF_BASE, 0x0);
+
+ /* Enable SWIMP mode */
+ WRITE_VREG(HEVCD_IPP_SWMPREDIF_CONFIG, 0x1);
+
+ /* Enable frame */
+ WRITE_VREG(HEVCD_IPP_TOP_CNTL, 0x2);
+ WRITE_VREG(HEVCD_IPP_TOP_FRMCTL, 0x1);
+
+ /* Send SW-command CTB info */
+ WRITE_VREG(HEVCD_IPP_SWMPREDIF_CTBINFO, 0x1 << 31);
+
+ /* Send PU_command */
+ WRITE_VREG(HEVCD_IPP_SWMPREDIF_PUINFO0, (0x4 << 9) | (0x4 << 16));
+ WRITE_VREG(HEVCD_IPP_SWMPREDIF_PUINFO1, 0x1 << 3);
+ WRITE_VREG(HEVCD_IPP_SWMPREDIF_PUINFO2, 0x0);
+ WRITE_VREG(HEVCD_IPP_SWMPREDIF_PUINFO3, 0x0);
+
+ udelay(us_delay);
+
+ WRITE_VREG(HEVCD_IPP_DBG_SEL, 0x2 << 4);
+
+ return (READ_VREG(HEVCD_IPP_DBG_DATA) & 3) == 1;
+}
+
+static bool hevc_workaround_needed(void)
+{
+ return (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_GXBB) &&
+ (get_meson_cpu_version(MESON_CPU_VERSION_LVL_MINOR)
+ == GXBB_REV_A_MINOR);
+}
+
+static void pm_vdec_legacy_power_off(struct device *dev, int id);
+
+static void pm_vdec_legacy_power_on(struct device *dev, int id)
+{
+ void *decomp_addr = NULL;
+ dma_addr_t decomp_dma_addr;
+ u32 decomp_addr_aligned = 0;
+ int hevc_loop = 0;
+ int sleep_val, iso_val;
+ bool is_power_ctrl_ver2 = false;
+
+ is_power_ctrl_ver2 =
+ ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) &&
+ (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_TL1)) ? true : false;
+
+ if (hevc_workaround_needed() &&
+ (id == VDEC_HEVC)) {
+ decomp_addr = codec_mm_dma_alloc_coherent("vdec_prealloc",
+ SZ_64K + SZ_4K, &decomp_dma_addr, GFP_KERNEL, 0);
+
+ if (decomp_addr) {
+ decomp_addr_aligned = ALIGN(decomp_dma_addr, SZ_64K);
+ memset((u8 *)decomp_addr +
+ (decomp_addr_aligned - decomp_dma_addr),
+ 0xff, SZ_4K);
+ } else
+ pr_err("vdec: alloc HEVC gxbb decomp buffer failed.\n");
+ }
+
+ if (id == VDEC_1) {
+ sleep_val = is_power_ctrl_ver2 ? 0x2 : 0xc;
+ iso_val = is_power_ctrl_ver2 ? 0x2 : 0xc0;
+
+ /* vdec1 power on */
+#ifdef CONFIG_AMLOGIC_POWER
+ if (is_support_power_ctrl()) {
+ if (power_ctrl_sleep_mask(true, sleep_val, 0)) {
+ pr_err("vdec-1 power on ctrl sleep fail.\n");
+ return;
+ }
+ } else {
+ WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
+ READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) & ~sleep_val);
+ }
+#else
+ WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
+ READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) & ~sleep_val);
+#endif
+ /* wait 10uS */
+ udelay(10);
+ /* vdec1 soft reset */
+ WRITE_VREG(DOS_SW_RESET0, 0xfffffffc);
+ WRITE_VREG(DOS_SW_RESET0, 0);
+ /* enable vdec1 clock */
+ /*
+ *add power on vdec clock level setting,only for m8 chip,
+ * m8baby and m8m2 can dynamic adjust vdec clock,
+ * power on with default clock level
+ */
+ amports_switch_gate("clk_vdec_mux", 1);
+ vdec_clock_hi_enable();
+ /* power up vdec memories */
+ WRITE_VREG(DOS_MEM_PD_VDEC, 0);
+
+ /* remove vdec1 isolation */
+#ifdef CONFIG_AMLOGIC_POWER
+ if (is_support_power_ctrl()) {
+ if (power_ctrl_iso_mask(true, iso_val, 0)) {
+ pr_err("vdec-1 power on ctrl iso fail.\n");
+ return;
+ }
+ } else {
+ WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
+ READ_AOREG(AO_RTI_GEN_PWR_ISO0) & ~iso_val);
+ }
+#else
+ WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
+ READ_AOREG(AO_RTI_GEN_PWR_ISO0) & ~iso_val);
+#endif
+ /* reset DOS top registers */
+ WRITE_VREG(DOS_VDEC_MCRCC_STALL_CTRL, 0);
+ } else if (id == VDEC_2) {
+ if (has_vdec2()) {
+ /* vdec2 power on */
+ WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
+ READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) &
+ ~0x30);
+ /* wait 10uS */
+ udelay(10);
+ /* vdec2 soft reset */
+ WRITE_VREG(DOS_SW_RESET2, 0xffffffff);
+ WRITE_VREG(DOS_SW_RESET2, 0);
+ /* enable vdec1 clock */
+ vdec2_clock_hi_enable();
+ /* power up vdec memories */
+ WRITE_VREG(DOS_MEM_PD_VDEC2, 0);
+ /* remove vdec2 isolation */
+ WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
+ READ_AOREG(AO_RTI_GEN_PWR_ISO0) &
+ ~0x300);
+ /* reset DOS top registers */
+ WRITE_VREG(DOS_VDEC2_MCRCC_STALL_CTRL, 0);
+ }
+ } else if (id == VDEC_HCODEC) {
+ if (has_hdec()) {
+ sleep_val = is_power_ctrl_ver2 ? 0x1 : 0x3;
+ iso_val = is_power_ctrl_ver2 ? 0x1 : 0x30;
+
+ /* hcodec power on */
+#ifdef CONFIG_AMLOGIC_POWER
+ if (is_support_power_ctrl()) {
+ if (power_ctrl_sleep_mask(true, sleep_val, 0)) {
+ pr_err("hcodec power on ctrl sleep fail.\n");
+ return;
+ }
+ } else {
+ WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
+ READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) & ~sleep_val);
+ }
+#else
+ WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
+ READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) & ~sleep_val);
+#endif
+ /* wait 10uS */
+ udelay(10);
+ /* hcodec soft reset */
+ WRITE_VREG(DOS_SW_RESET1, 0xffffffff);
+ WRITE_VREG(DOS_SW_RESET1, 0);
+ /* enable hcodec clock */
+ hcodec_clock_enable();
+ /* power up hcodec memories */
+ WRITE_VREG(DOS_MEM_PD_HCODEC, 0);
+ /* remove hcodec isolation */
+#ifdef CONFIG_AMLOGIC_POWER
+ if (is_support_power_ctrl()) {
+ if (power_ctrl_iso_mask(true, iso_val, 0)) {
+ pr_err("hcodec power on ctrl iso fail.\n");
+ return;
+ }
+ } else {
+ WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
+ READ_AOREG(AO_RTI_GEN_PWR_ISO0) & ~iso_val);
+ }
+#else
+ WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
+ READ_AOREG(AO_RTI_GEN_PWR_ISO0) & ~iso_val);
+#endif
+ }
+ } else if (id == VDEC_HEVC) {
+ if (has_hevc_vdec()) {
+ bool hevc_fixed = false;
+
+ sleep_val = is_power_ctrl_ver2 ? 0x4 : 0xc0;
+ iso_val = is_power_ctrl_ver2 ? 0x4 : 0xc00;
+
+ while (!hevc_fixed) {
+ /* hevc power on */
+#ifdef CONFIG_AMLOGIC_POWER
+ if (is_support_power_ctrl()) {
+ if (power_ctrl_sleep_mask(true, sleep_val, 0)) {
+ pr_err("hevc power on ctrl sleep fail.\n");
+ return;
+ }
+ } else {
+ WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
+ READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) & ~sleep_val);
+ }
+#else
+ WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
+ READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) & ~sleep_val);
+#endif
+ /* wait 10uS */
+ udelay(10);
+ /* hevc soft reset */
+ WRITE_VREG(DOS_SW_RESET3, 0xffffffff);
+ WRITE_VREG(DOS_SW_RESET3, 0);
+ /* enable hevc clock */
+ amports_switch_gate("clk_hevc_mux", 1);
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A)
+ amports_switch_gate("clk_hevcb_mux", 1);
+ hevc_clock_hi_enable();
+ hevc_back_clock_hi_enable();
+ /* power up hevc memories */
+ WRITE_VREG(DOS_MEM_PD_HEVC, 0);
+ /* remove hevc isolation */
+#ifdef CONFIG_AMLOGIC_POWER
+ if (is_support_power_ctrl()) {
+ if (power_ctrl_iso_mask(true, iso_val, 0)) {
+ pr_err("hevc power on ctrl iso fail.\n");
+ return;
+ }
+ } else {
+ WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
+ READ_AOREG(AO_RTI_GEN_PWR_ISO0) & ~iso_val);
+ }
+#else
+ WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
+ READ_AOREG(AO_RTI_GEN_PWR_ISO0) & ~iso_val);
+#endif
+ if (!hevc_workaround_needed())
+ break;
+
+ if (decomp_addr)
+ hevc_fixed = test_hevc(
+ decomp_addr_aligned, 20);
+
+ if (!hevc_fixed) {
+ hevc_loop++;
+ if (hevc_loop >= HEVC_TEST_LIMIT) {
+ pr_warn("hevc power sequence over limit\n");
+ pr_warn("=====================================================\n");
+ pr_warn(" This chip is identified to have HW failure.\n");
+ pr_warn(" Please contact sqa-platform to replace the platform.\n");
+ pr_warn("=====================================================\n");
+
+ panic("Force panic for chip detection !!!\n");
+
+ break;
+ }
+
+ pm_vdec_legacy_power_off(NULL, VDEC_HEVC);
+
+ mdelay(10);
+ }
+ }
+
+ if (hevc_loop > hevc_max_reset_count)
+ hevc_max_reset_count = hevc_loop;
+
+ WRITE_VREG(DOS_SW_RESET3, 0xffffffff);
+ udelay(10);
+ WRITE_VREG(DOS_SW_RESET3, 0);
+ }
+ }
+
+ if (decomp_addr)
+ codec_mm_dma_free_coherent("vdec_prealloc",
+ SZ_64K + SZ_4K, decomp_addr, decomp_dma_addr, 0);
+}
+
+static void pm_vdec_legacy_power_off(struct device *dev, int id)
+{
+ int sleep_val, iso_val;
+ bool is_power_ctrl_ver2 = false;
+
+ is_power_ctrl_ver2 =
+ ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) &&
+ (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_TL1)) ? true : false;
+
+ if (id == VDEC_1) {
+ sleep_val = is_power_ctrl_ver2 ? 0x2 : 0xc;
+ iso_val = is_power_ctrl_ver2 ? 0x2 : 0xc0;
+
+ /* enable vdec1 isolation */
+#ifdef CONFIG_AMLOGIC_POWER
+ if (is_support_power_ctrl()) {
+ if (power_ctrl_iso_mask(false, iso_val, 0)) {
+ pr_err("vdec-1 power off ctrl iso fail.\n");
+ return;
+ }
+ } else {
+ WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
+ READ_AOREG(AO_RTI_GEN_PWR_ISO0) | iso_val);
+ }
+#else
+ WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
+ READ_AOREG(AO_RTI_GEN_PWR_ISO0) | iso_val);
+#endif
+ /* power off vdec1 memories */
+ WRITE_VREG(DOS_MEM_PD_VDEC, 0xffffffffUL);
+ /* disable vdec1 clock */
+ vdec_clock_off();
+ /* vdec1 power off */
+#ifdef CONFIG_AMLOGIC_POWER
+ if (is_support_power_ctrl()) {
+ if (power_ctrl_sleep_mask(false, sleep_val, 0)) {
+ pr_err("vdec-1 power off ctrl sleep fail.\n");
+ return;
+ }
+ } else {
+ WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
+ READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) | sleep_val);
+ }
+#else
+ WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
+ READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) | sleep_val);
+#endif
+ } else if (id == VDEC_2) {
+ if (has_vdec2()) {
+ /* enable vdec2 isolation */
+ WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
+ READ_AOREG(AO_RTI_GEN_PWR_ISO0) |
+ 0x300);
+ /* power off vdec2 memories */
+ WRITE_VREG(DOS_MEM_PD_VDEC2, 0xffffffffUL);
+ /* disable vdec2 clock */
+ vdec2_clock_off();
+ /* vdec2 power off */
+ WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
+ READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) |
+ 0x30);
+ }
+ } else if (id == VDEC_HCODEC) {
+ if (has_hdec()) {
+ sleep_val = is_power_ctrl_ver2 ? 0x1 : 0x3;
+ iso_val = is_power_ctrl_ver2 ? 0x1 : 0x30;
+
+ /* enable hcodec isolation */
+#ifdef CONFIG_AMLOGIC_POWER
+ if (is_support_power_ctrl()) {
+ if (power_ctrl_iso_mask(false, iso_val, 0)) {
+ pr_err("hcodec power off ctrl iso fail.\n");
+ return;
+ }
+ } else {
+ WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
+ READ_AOREG(AO_RTI_GEN_PWR_ISO0) | iso_val);
+ }
+#else
+ WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
+ READ_AOREG(AO_RTI_GEN_PWR_ISO0) | iso_val);
+#endif
+ /* power off hcodec memories */
+ WRITE_VREG(DOS_MEM_PD_HCODEC, 0xffffffffUL);
+ /* disable hcodec clock */
+ hcodec_clock_off();
+ /* hcodec power off */
+#ifdef CONFIG_AMLOGIC_POWER
+ if (is_support_power_ctrl()) {
+ if (power_ctrl_sleep_mask(false, sleep_val, 0)) {
+ pr_err("hcodec power off ctrl sleep fail.\n");
+ return;
+ }
+ } else {
+ WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
+ READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) | sleep_val);
+ }
+#else
+ WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
+ READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) | sleep_val);
+#endif
+ }
+ } else if (id == VDEC_HEVC) {
+ if (has_hevc_vdec()) {
+ sleep_val = is_power_ctrl_ver2 ? 0x4 : 0xc0;
+ iso_val = is_power_ctrl_ver2 ? 0x4 : 0xc00;
+
+ if (no_powerdown == 0) {
+ /* enable hevc isolation */
+#ifdef CONFIG_AMLOGIC_POWER
+ if (is_support_power_ctrl()) {
+ if (power_ctrl_iso_mask(false, iso_val, 0)) {
+ pr_err("hevc power off ctrl iso fail.\n");
+ return;
+ }
+ } else {
+ WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
+ READ_AOREG(AO_RTI_GEN_PWR_ISO0) | iso_val);
+ }
+#else
+ WRITE_AOREG(AO_RTI_GEN_PWR_ISO0,
+ READ_AOREG(AO_RTI_GEN_PWR_ISO0) | iso_val);
+#endif
+ /* power off hevc memories */
+ WRITE_VREG(DOS_MEM_PD_HEVC, 0xffffffffUL);
+
+ /* disable hevc clock */
+ hevc_clock_off();
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A)
+ hevc_back_clock_off();
+
+ /* hevc power off */
+#ifdef CONFIG_AMLOGIC_POWER
+ if (is_support_power_ctrl()) {
+ if (power_ctrl_sleep_mask(false, sleep_val, 0)) {
+ pr_err("hevc power off ctrl sleep fail.\n");
+ return;
+ }
+ } else {
+ WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
+ READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) | sleep_val);
+ }
+#else
+ WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0,
+ READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) | sleep_val);
+#endif
+ } else {
+ pr_info("!!!!!!!!not power down\n");
+ hevc_reset_core(NULL);
+ no_powerdown = 0;
+ }
+ }
+ }
+}
+
+static bool pm_vdec_legacy_power_state(struct device *dev, int id)
+{
+ bool ret = false;
+
+ if (id == VDEC_1) {
+ if (((READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) &
+ (((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) &&
+ (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_TL1))
+ ? 0x2 : 0xc)) == 0) &&
+ (READ_HHI_REG(HHI_VDEC_CLK_CNTL) & 0x100))
+ ret = true;
+ } else if (id == VDEC_2) {
+ if (has_vdec2()) {
+ if (((READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) & 0x30) == 0) &&
+ (READ_HHI_REG(HHI_VDEC2_CLK_CNTL) & 0x100))
+ ret = true;
+ }
+ } else if (id == VDEC_HCODEC) {
+ if (has_hdec()) {
+ if (((READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) &
+ (((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) &&
+ (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_TL1))
+ ? 0x1 : 0x3)) == 0) &&
+ (READ_HHI_REG(HHI_VDEC_CLK_CNTL) & 0x1000000))
+ ret = true;
+ }
+ } else if (id == VDEC_HEVC) {
+ if (has_hevc_vdec()) {
+ if (((READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) &
+ (((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) &&
+ (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_TL1))
+ ? 0x4 : 0xc0)) == 0) &&
+ (READ_HHI_REG(HHI_VDEC2_CLK_CNTL) & 0x1000000))
+ ret = true;
+ }
+ }
+
+ return ret;
+}
+
+static void pm_vdec_pd_sec_api_power_on(struct device *dev, int id)
+{
+ int pd_id = (id == VDEC_1) ? PDID_DOS_VDEC :
+ (id == VDEC_HEVC) ? PDID_DOS_HEVC :
+ PDID_DOS_HCODEC;
+
+ pm_vdec_clock_on(id);
+ pwr_ctrl_psci_smc(pd_id, PWR_ON);
+
+}
+
+static void pm_vdec_pd_sec_api_power_off(struct device *dev, int id)
+{
+ int pd_id = (id == VDEC_1) ? PDID_DOS_VDEC :
+ (id == VDEC_HEVC) ? PDID_DOS_HEVC :
+ PDID_DOS_HCODEC;
+
+ pm_vdec_clock_off(id);
+ pwr_ctrl_psci_smc(pd_id, PWR_OFF);
+}
+
+static bool pm_vdec_pd_sec_api_power_state(struct device *dev, int id)
+{
+ int pd_id = (id == VDEC_1) ? PDID_DOS_VDEC :
+ (id == VDEC_HEVC) ? PDID_DOS_HEVC :
+ PDID_DOS_HCODEC;
+
+ return !pwr_ctrl_status_psci_smc(pd_id);
+}
+
+static void pm_vdec_pd_nosec_api_power_on(struct device *dev, int id)
+{
+#if 0
+ int pd_id = (id == VDEC_1) ? PM_DOS_VDEC :
+ (id == VDEC_HEVC) ? PM_DOS_HEVC :
+ PM_DOS_HCODEC;
+
+ pm_vdec_clock_on(id);
+ power_domain_switch(pd_id, PWR_ON);
+#endif
+}
+
+static void pm_vdec_pd_nosec_api_power_off(struct device *dev, int id)
+{
+#if 0
+ int pd_id = (id == VDEC_1) ? PM_DOS_VDEC :
+ (id == VDEC_HEVC) ? PM_DOS_HEVC :
+ PM_DOS_HCODEC;
+
+ pm_vdec_clock_off(id);
+ power_domain_switch(pd_id, PWR_OFF);
+#endif
+}
+
+static bool pm_vdec_pd_nosec_api_power_state(struct device *dev, int id)
+{
+ return pm_vdec_legacy_power_state(dev, id);
+}
+
+static const struct power_manager_s pm_rw_reg_data = {
+ .pm_type = PM_POWER_CTRL_RW_REG,
+ .power_on = pm_vdec_legacy_power_on,
+ .power_off = pm_vdec_legacy_power_off,
+ .power_state = pm_vdec_legacy_power_state,
+};
+
+static const struct power_manager_s pm_ctrl_api_data = {
+ .pm_type = PM_POWER_CTRL_API,
+ .power_on = pm_vdec_legacy_power_on,
+ .power_off = pm_vdec_legacy_power_off,
+ .power_state = pm_vdec_legacy_power_state,
+};
+
+static const struct power_manager_s pm_pd_data = {
+ .pm_type = PM_POWER_DOMAIN,
+ .pd_data = pm_domain_data,
+ .init = pm_vdec_power_domain_init,
+ .release = pm_vdec_power_domain_relese,
+ .power_on = pm_vdec_power_domain_power_on,
+ .power_off = pm_vdec_power_domain_power_off,
+ .power_state = pm_vdec_power_domain_power_state,
+};
+
+static const struct power_manager_s pm_pd_sec_api_data = {
+ .pm_type = PM_POWER_DOMAIN_SEC_API,
+ .power_on = pm_vdec_pd_sec_api_power_on,
+ .power_off = pm_vdec_pd_sec_api_power_off,
+ .power_state = pm_vdec_pd_sec_api_power_state,
+};
+
+static const struct power_manager_s pm_pd_nosec_api_data = {
+ .pm_type = PM_POWER_DOMAIN_NONSEC_API,
+ .power_on = pm_vdec_pd_nosec_api_power_on,
+ .power_off = pm_vdec_pd_nosec_api_power_off,
+ .power_state = pm_vdec_pd_nosec_api_power_state,
+};
+
+const struct of_device_id amlogic_vdec_matches[] = {
+ { .compatible = "amlogic, vdec", .data = &pm_rw_reg_data },
+ { .compatible = "amlogic, vdec-pm-api", .data = &pm_ctrl_api_data },
+ { .compatible = "amlogic, vdec-pm-pd", .data = &pm_pd_data },
+ { .compatible = "amlogic, vdec-pm-pd-sec-api", .data = &pm_pd_sec_api_data },
+ { .compatible = "amlogic, vdec-pm-pd-nsec-api", .data = &pm_pd_nosec_api_data },
+ {},
+};
+EXPORT_SYMBOL(amlogic_vdec_matches);
+