/*****************************************************************************
 function name  : mali_dfs_to_profile
 description    : doing dfs action to target profile
 input vars     : u32 curr
 output vars    : NA
 return value   : int
 calls          :
 called         :

 history        :
  1.data        : 07/05/2014
    author      : s00250033
    modify      : new

*****************************************************************************/
int mali_dfs_set_pll(int target)
{
    u32 i = 0;
    u32 ret = 0;
    if (g_mali_dvfs_profile[target].pllNum != g_mali_dvfs_profile[g_mali_dfs_var.dfs_CurrPrf].pllNum) 
    {
        if (g_mali_dvfs_profile[target].freq > MAX_SFT_FREQ)                                       //ASIC下,GPU频率至少100M
        {
            phy_reg_writel(SOC_MEDIA_SCTRL_BASE_ADDR,SOC_MEDIA_SCTRL_SC_MEDIA_CLKCFG2_ADDR(0),0,31,DVFS_FREQ_DIV(6));
            for (i = 0; i < MAX_CUNT; i++)
            {
                ret = phy_reg_readl(SOC_MEDIA_SCTRL_BASE_ADDR, SOC_MEDIA_SCTRL_SC_MEDIA_CLKCFG2_ADDR(0), 8, 11);
                if (MID_DIV == ret)
                {
                    break;
                }
                udelay(1);
            }
            if (MAX_CUNT == i)
            {
                MALI_DEBUG_PRINT(1,("mali dfs: ERROR! set mid div %d failed! Current div is %d!\n", g_mali_dvfs_profile[target].div, ret));
                return -1;
            }
        }
        phy_reg_writel(SOC_MEDIA_SCTRL_BASE_ADDR,SOC_MEDIA_SCTRL_SC_MEDIA_SUBSYS_CTRL5_ADDR(0),1,1,g_mali_dvfs_profile[target].pllNum);
    }
    return 0;
}
/*****************************************************************************
 function name  : mali_regulator_enable
 description    : powerup mali by calling regulator
 input vars     : void
 output vars    : NA
 return value   : void
 calls          : regulator_enable

 called         : mali_platform_powerup

 history        :
  1.data        : 04/03/2014
    author      : s00250033
    modify      : new

*****************************************************************************/
void mali_regulator_enable(void)
{
    int i, ret;
    if( IS_ERR_OR_NULL(mali_regulator) )
    {
        MALI_DEBUG_PRINT(1, ("error on mali_regulator_enable : g3d_regulator is null\n"));
        return;
    }

    ret = regulator_enable(mali_regulator);
    if(ret < 0)
    {
        return;
    }
    for (i = 0; i < 50; i++)
    {
        ret = phy_reg_readl(SOC_AO_SCTRL_BASE_ADDR, SOC_AO_SCTRL_SC_PW_MTCMOS_STAT0_ADDR(0), 1, 1);
        if (1 == ret)
        {
            MALI_DEBUG_PRINT(3, ("MTCMOS open OK\n"));
            break;
        }
        udelay(1);
    }
    if (50 == i)
    {
        MALI_DEBUG_PRINT(2, ("****error: MTCMOS open failed\n"));
        return;
    }
}
/*****************************************************************************
 function name  : mali_domain_powerup_finish
 description    : powerup finish to run
 input vars     : void
 output vars    : NA
 return value   : void
 calls          : phy_reg_writel

 called         : mali_platform_powerup

 history        :
  1.data        : 04/03/2014
    author      : s00250033
    modify      : new

*****************************************************************************/
void mali_domain_powerup_finish(void)
{
    unsigned int ret = 0;

    MALI_DEBUG_PRINT(3, ("mali power up start! \n"));
    
    phy_reg_writel(SOC_AO_SCTRL_BASE_ADDR,SOC_AO_SCTRL_SC_PW_RSTDIS0_ADDR(0),1,1,1);
    ret = phy_reg_readl(SOC_AO_SCTRL_BASE_ADDR, SOC_AO_SCTRL_SC_PW_RST_STAT0_ADDR(0), 1, 1);
    if(0 != ret)
    {
        MALI_DEBUG_PRINT(2, (" error:  SET SC_PW_RSTDIS0 failed!\n"));
    }

    phy_reg_writel(SOC_AO_SCTRL_BASE_ADDR,SOC_AO_SCTRL_SC_PW_ISODIS0_ADDR(0),1,1,1);
    ret = phy_reg_readl(SOC_AO_SCTRL_BASE_ADDR, SOC_AO_SCTRL_SC_PW_ISO_STAT0_ADDR(0), 1, 1);
    if(0 != ret)
    {
        MALI_DEBUG_PRINT(2, (" error:  SET SC_PW_ISODIS0 failed!\n"));
    }
    
    phy_reg_writel(SOC_AO_SCTRL_BASE_ADDR,SOC_AO_SCTRL_SC_PW_CLKEN0_ADDR(0),1,1,1);
    ret = phy_reg_readl(SOC_AO_SCTRL_BASE_ADDR, SOC_AO_SCTRL_SC_PW_CLK_STAT0_ADDR(0), 1, 1);
    if(1 != ret)
    {
        MALI_DEBUG_PRINT(2, (" error:  SET SC_PW_CLKEN0 failed!\n"));
    }
    
    phy_reg_writel(SOC_MEDIA_SCTRL_BASE_ADDR,SOC_MEDIA_SCTRL_SC_MEDIA_RSTDIS_ADDR(0),0,0,1);
    ret = phy_reg_readl(SOC_MEDIA_SCTRL_BASE_ADDR, SOC_MEDIA_SCTRL_SC_MEDIA_RST_STAT_ADDR(0), 0, 0);
    if(0 != ret)
    {
        MALI_DEBUG_PRINT(2, (" error:  SET SC_MEDIA_RSTDIS failed!\n"));
    }
    
    MALI_DEBUG_PRINT(3, ("mali power up end! \n"));
}
int mali_dfs_set_div(int target)
{
    u32 i = 0;
    u32 ret = 0;
    phy_reg_writel(SOC_MEDIA_SCTRL_BASE_ADDR,SOC_MEDIA_SCTRL_SC_MEDIA_CLKCFG2_ADDR(0),0,31,DVFS_FREQ_DIV(g_mali_dvfs_profile[target].div));
    
    for (i = 0; i < MAX_CUNT; i++)
    {
        ret = phy_reg_readl(SOC_MEDIA_SCTRL_BASE_ADDR, SOC_MEDIA_SCTRL_SC_MEDIA_CLKCFG2_ADDR(0), 8, 11);
        if (g_mali_dvfs_profile[target].div == ret)
        {
            return 0;
        }
        udelay(1);
    }
            
    MALI_DEBUG_PRINT(1,("mali dfs: ERROR! target %d  set div %d failed! Current div is %d!\n", target,g_mali_dvfs_profile[target].div, ret));
    return -1;
}
int video_harden_video_noc_disable(video_harden_dev_id_enum dev_id)
{
	int ret = 0;
    unsigned int reg_val = 0;
    unsigned int count = 0;

    printk(KERN_INFO "%s, dev_id is %d.\n", __func__, dev_id);

    ret = video_harden_device_id_check(dev_id);
    if (ret != 0) {
        return -1;
    }

    ret = down_interruptible(&video_harden_busy_lock);
	if (0 != ret) {
		printk(KERN_ERR "%s, video_harden_busy_lock failed.\n", __func__);
		return -1;
	}

    switch (dev_id) {
        case VIDEO_HARDEN_DEV_ID_VCODEC: /* VCODEC */
            video_harden_video_noc_vote.vcodec_bit = 0;
            break;

        case VIDEO_HARDEN_DEV_ID_JPEG: /* JPEG */
            video_harden_video_noc_vote.jpeg_bit = 0;
            break;

        case VIDEO_HARDEN_DEV_ID_ISP: /* ISP */
            video_harden_video_noc_vote.isp_bit = 0;
            break;

        default:
            break;
    }

    if ((0 == video_harden_video_noc_vote.vcodec_bit)
        && (0 == video_harden_video_noc_vote.jpeg_bit)
        && (0 == video_harden_video_noc_vote.isp_bit)) {

        /* AO_SC PW CTRL1[0x8C8]: video noc power idle req, BIT[30][14] */
        phy_reg_writel(SOC_AO_SCTRL_BASE_ADDR,
                       SOC_AO_SCTRL_SC_PW_CTRL1_ADDR(CALC_REG_OFFSET),
                       SOC_AO_SCTRL_SC_PW_CTRL1_acpu_sft_fiq_req_START,
                       SOC_AO_SCTRL_SC_PW_CTRL1_ade_domain_idlereq_msk_END,
                       0x40004000);

        /* AO_SC PW STAT1[0x854]: video noc stat */
        do {
            reg_val = phy_reg_readl(SOC_AO_SCTRL_BASE_ADDR,
                SOC_AO_SCTRL_SC_PW_STAT1_ADDR(CALC_REG_OFFSET),
                SOC_AO_SCTRL_SC_PW_STAT1_video_domain_idleack_START,
                SOC_AO_SCTRL_SC_PW_STAT1_video_domain_idle_END);
            printk(KERN_INFO "%s, SC_PW_STAT1_video_domain_idleack&idle = 0x%0x \n", __func__, reg_val);
            udelay(10);
            count ++;
            if (count >= 10) {
        		printk(KERN_ERR "%s, video noc stat is not expect.\n", __func__);
        		ret = -1;
                break;
            }
        } while (reg_val != 0x3);

        printk(KERN_INFO "%s, video noc disable is sucessful.\n", __func__);
    } else {
        printk(KERN_INFO "%s, video noc is already disabled!. \n", __func__);
    }

    up(&video_harden_busy_lock);

    printk(KERN_INFO "%s, video_noc_vote is 0x%x.\n",
        __func__, *((unsigned int *)&video_harden_video_noc_vote));

    return ret;
}
int video_harden_regdis_clkdis_isoen_rsten_check(video_harden_dev_id_enum dev_id)
{
    unsigned int regTmp = 0xff;
    unsigned int regExpect = 0x0;
	int ret = 0;

    printk(KERN_INFO "dev_Id is %d. start video_harden_rstdis_isodis_clken_check.....\n", dev_id);

    ret = video_harden_device_id_check(dev_id);
    if (ret != 0) {
        return 0;
    }

    ret = down_interruptible(&video_harden_busy_lock);
	if (0 != ret) {
		printk(KERN_ERR "video_harden_busy_lock failed\n");
		return 0;
	}

    if ((0 == video_harden_rst_iso_clk_vote.vcodec_bit)
        && (0 == video_harden_rst_iso_clk_vote.jpeg_bit)
        && (0 == video_harden_rst_iso_clk_vote.isp_bit)) {

        /*================== AO_SC PW MTCMOS STAT [0x838] ==================*/
        regTmp =  phy_reg_readl(SOC_AO_SCTRL_BASE_ADDR,
                                SOC_AO_SCTRL_SC_PW_MTCMOS_STAT0_ADDR(CALC_REG_OFFSET),
                                SOC_AO_SCTRL_SC_PW_MTCMOS_STAT0_pw_mtcmos_ack_stat0_2codecisp_START,
                                SOC_AO_SCTRL_SC_PW_MTCMOS_STAT0_pw_mtcmos_ack_stat0_2codecisp_END);
        printk(KERN_INFO "PW MTCMOS STAT = 0x%x, addr=0x%x\n", regTmp,
            (SOC_AO_SCTRL_BASE_ADDR+SOC_AO_SCTRL_SC_PW_MTCMOS_STAT0_ADDR(CALC_REG_OFFSET)));

        regExpect = 0x0;
        if (regTmp != regExpect) {
            printk(KERN_ERR "ERR: PW MTCMOS STAT = 0x%x\n", regExpect);
            ret = -1;
        }
        regExpect = 0x0;
        regTmp = 0xffff;


        /*================== AO_SC PW CLK STAT [0x808] ==================*/
        regTmp =  phy_reg_readl(SOC_AO_SCTRL_BASE_ADDR,
                                SOC_AO_SCTRL_SC_PW_CLK_STAT0_ADDR(CALC_REG_OFFSET),
                                SOC_AO_SCTRL_SC_PW_CLK_STAT0_pw_clk_stat0_2codecisp_START,
                                SOC_AO_SCTRL_SC_PW_CLK_STAT0_pw_clk_stat0_2codecisp_END);
        printk(KERN_INFO "PW CLK STAT: 2codecisp = 0x%x, addr=0x%x\n", regTmp,
            (SOC_AO_SCTRL_BASE_ADDR+SOC_AO_SCTRL_SC_PW_CLK_STAT0_ADDR(CALC_REG_OFFSET)));

        regExpect = 0x0;
        if (regTmp != regExpect) {
            printk(KERN_ERR "ERR:PW CLK STAT: 2codecisp = 0x%x\n", regExpect);
            ret = -1;
        }
        regExpect = 0x0;
        regTmp = 0xffff;


        /*================== AO_SC PW ISO STAT [0x828] ==================*/
        regTmp =  phy_reg_readl(SOC_AO_SCTRL_BASE_ADDR,
                                SOC_AO_SCTRL_SC_PW_ISO_STAT0_ADDR(CALC_REG_OFFSET),
                                SOC_AO_SCTRL_SC_PW_ISO_STAT0_pw_iso_stat0_2codecisp_START,
                                SOC_AO_SCTRL_SC_PW_ISO_STAT0_pw_iso_stat0_2codecisp_END);
        printk(KERN_INFO "PW ISO STAT: 2codecisp = 0x%x, addr=0x%x\n", regTmp,
            (SOC_AO_SCTRL_BASE_ADDR+SOC_AO_SCTRL_SC_PW_ISO_STAT0_ADDR(CALC_REG_OFFSET)));

        regExpect = 0x1;
        if (regTmp != regExpect) {
            printk(KERN_ERR "ERR:PW ISO STAT: 2codecisp = 0x%x\n", regExpect);
            ret = -1;
        }

        regExpect = 0x0;
        regTmp = 0xffff;


        /*================== AO_SC PW RST STAT [0x818] ==================*/
        regTmp =  phy_reg_readl(SOC_AO_SCTRL_BASE_ADDR,
                                SOC_AO_SCTRL_SC_PW_RST_STAT0_ADDR(CALC_REG_OFFSET),
                                SOC_AO_SCTRL_SC_PW_RST_STAT0_pw_rst_stat0_2codecisp_START,
                                SOC_AO_SCTRL_SC_PW_RST_STAT0_pw_rst_stat0_2codecisp_END);
        printk(KERN_INFO "PW RST STAT: 2codecisp = 0x%x, addr=0x%x\n", regTmp,
            (SOC_AO_SCTRL_BASE_ADDR+SOC_AO_SCTRL_SC_PW_RST_STAT0_ADDR(CALC_REG_OFFSET)));

        regExpect = 0x1;
        if (regTmp != regExpect) {
            printk(KERN_ERR "ERR:PW RST STAT: 2codecisp = 0x%x\n", regExpect);
            ret = -1;
        }

        regExpect = 0x0;
        regTmp = 0xffff;
    } else {
        printk(KERN_INFO "video_harden_regdis_clkdis_isoen_rsten_check is unnecessary!. \n");
    }

    up(&video_harden_busy_lock);

    return ret;
}
/*****************************************************************************
 function name  : init_mali_clock_regulator
 description    : mali clk and regulator init
 input vars     : void
 output vars    : NA
 return value   : mali_bool
 calls          : mali_clk_get

 called         : mali_platform_init

 history        :
  1.data        : 04/03/2014
    author      : s00250033
    modify      : new

*****************************************************************************/
static mali_bool init_mali_clock_regulator(struct platform_device *pdev)
{
    mali_bool ret       = MALI_TRUE;

    g_swGpuPowerState   = MALI_TRUE;

    /* regulator init */
    mali_regulator  = regulator_get(&pdev->dev, "G3D_PD_VDD");

    if (IS_ERR(mali_regulator))
    {
        MALI_PRINT( ("MALI Error : failed to get G3D_PD_VDD\n"));
        return MALI_FALSE;
    }

    mali_regulator_enable();

    /* clk init */

    if (mali_clock != 0)
    {
        return ret;
    }
    
    if (!mali_clk_get(pdev))
    {
        MALI_PRINT(("MALI Error: Failed to get Mali clock\n"));
        return MALI_FALSE;
    }

 
    /*使能媒体外设时钟*/
    ret = phy_reg_readl(SOC_PERI_SCTRL_BASE_ADDR, SOC_PERI_SCTRL_SC_PERIPH_CLKSTAT12_ADDR(0), 10, 10);
    if(1 != ret)
    {
        phy_reg_writel(SOC_PERI_SCTRL_BASE_ADDR,SOC_PERI_SCTRL_SC_PERIPH_CLKEN12_ADDR(0),10,10,1);
        ret = phy_reg_readl(SOC_PERI_SCTRL_BASE_ADDR, SOC_PERI_SCTRL_SC_PERIPH_CLKSTAT12_ADDR(0), 10, 10);
        if(1 != ret)
        {
            MALI_DEBUG_PRINT(2, (" error:  SET SC_PERIPH_CLKEN12 failed!\n"));
        }            
    }
    
    /* CLK on and set rate */
    mali_clock_on();

    MALI_DEBUG_PRINT(2, (" init mali clock regulator ok\n"));

    /*时钟有效指示*/
    phy_reg_writel(SOC_MEDIA_SCTRL_BASE_ADDR,SOC_MEDIA_SCTRL_SC_MEDIA_CLKCFG2_ADDR(0),15,15,1);
    ret = phy_reg_readl(SOC_MEDIA_SCTRL_BASE_ADDR, SOC_MEDIA_SCTRL_SC_MEDIA_CLKCFG2_ADDR(0), 15, 15);
    if(1 != ret)
    {
        MALI_DEBUG_PRINT(2, (" error:  SET SC_MEDIA_CLKCFG2 failed!\n"));
    }
    
    mali_domain_powerup_finish();
    
    return MALI_TRUE;

}