/* * Copyright (c) 2011-2020 yanggq.young@allwinnertech.com * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published by * the Free Software Foundation. */ #include "standby.h" #include "../mem_ccmu.h" #include "../pm_config.h" #include "standby_clock.h" #include "standby_divlib.h" static __ccmu_reg_list_t *CmuReg; /*==============================================================================*/ /* CLOCK SET FOR SYSTEM STANDBY*/ /*==============================================================================*/ #ifdef CONFIG_ARCH_SUN8I static __ccmu_pll1_reg0000_t CmuReg_Pll1Ctl_tmp; static __ccmu_sysclk_ratio_reg0050_t CmuReg_SysClkDiv_tmp; #define PIO_INT_DEB_REG (AW_GPIO_BASE_PA + 0x258) static __u32 pio_int_deb_back; static __ccmu_ahb1_ratio_reg0054_t CmuReg_ahb1_tmp; static __ccmu_ahb1_ratio_reg0054_t CmuReg_ahb1_backup; static __ccmu_apb2_ratio_reg0058_t CmuReg_apb2_tmp; static __ccmu_apb2_ratio_reg0058_t CmuReg_apb2_backup; #ifdef CONFIG_ARCH_SUN8IW10P1 static __u32 CmuReg_ee_backup; static __u32 CmuReg_de_backup; #endif /* ********************************************************************************************************* * standby_clk_init * *Description: ccu init for platform standby * *Arguments : none * *Return : result, * *Notes : * ********************************************************************************************************* */ __s32 standby_clk_init(void) { CmuReg = (__ccmu_reg_list_t *) IO_ADDRESS(AW_CCM_BASE); return 0; } /* ********************************************************************************************************* * standby_clk_exit * *Description: ccu exit for platform standby * *Arguments : none * *Return : result, * *Notes : * ********************************************************************************************************* */ __s32 standby_clk_exit(void) { return 0; } /* ********************************************************************************************************* * standby_clk_core2losc * * Description: switch core clock to 32k low osc. * * Arguments : none * * Returns : 0; ********************************************************************************************************* */ __s32 standby_clk_core2losc(void) { unsigned int tmp; /*CmuReg->SysClkDiv.CpuClkSrc = 0; */ /* cpu frequency is internal Losc hz */ tmp = readl(&(CmuReg->SysClkDiv)); tmp &= (~(0x00030000)); writel(tmp, &(CmuReg->SysClkDiv)); return 0; } /* ********************************************************************************************************* * standby_clk_core2hosc * * Description: switch core clock to 24M high osc. * * Arguments : none * ********************************************************************************************************* */ __s32 standby_clk_core2hosc(void) { CmuReg_SysClkDiv_tmp.dwval = CmuReg->SysClkDiv.dwval; CmuReg_SysClkDiv_tmp.bits.CpuClkSrc = AC327_CLKSRC_HOSC; /*26M OSC */ CmuReg->SysClkDiv.dwval = CmuReg_SysClkDiv_tmp.dwval; return 0; } /* ********************************************************************************************************* * standby_clk_core2pll * * Description: switch core clock to core pll. * * Arguments : none * * Returns : 0; ********************************************************************************************************* */ __s32 standby_clk_core2pll(void) { CmuReg_SysClkDiv_tmp.dwval = CmuReg->SysClkDiv.dwval; CmuReg_SysClkDiv_tmp.bits.CpuClkSrc = AC327_CLKSRC_PLL1; /*pll cpu */ CmuReg->SysClkDiv.dwval = CmuReg_SysClkDiv_tmp.dwval; return 0; } /* ********************************************************************************************************* * standby_clk_plldisable * * Description: disable dram pll. * * Arguments : none * * Returns : 0; ********************************************************************************************************* */ __s32 standby_clk_plldisable(void) { unsigned int tmp; #if 0 /*use old mode */ /*pll lock */ tmp = readl(&(CmuReg->PllLockCtl)); tmp |= ((0x10000000)); writel(tmp, &(CmuReg->Pll1Ctl)); #endif /*pll1 */ tmp = readl(&(CmuReg->Pll1Ctl)); tmp &= (~(0x80000000)); writel(tmp, &(CmuReg->Pll1Ctl)); /*pll6: for periph0 */ tmp = readl(&(CmuReg->Pll6Ctl)); tmp &= (~(0x80000000)); writel(tmp, &(CmuReg->Pll6Ctl)); #ifndef CONFIG_ARCH_SUN8IW11P1 /*pll9: periph 1 */ tmp = readl(&(CmuReg->Pll9Ctl)); tmp &= (~(0x80000000)); writel(tmp, &(CmuReg->Pll9Ctl)); /*pll 24M: */ tmp = readl(&(CmuReg->Pll24M)); tmp &= (~(0x80000000)); writel(tmp, &(CmuReg->Pll24M)); #else /* ohci 12M divided from 24M */ tmp = readl(&(CmuReg->UsbClk)); tmp = (tmp & (~(0x3 << 20))) | (0x1 << 20); tmp = (tmp & (~(0x3 << 22))) | (0x1 << 22); tmp = (tmp & (~(0x3 << 24))) | (0x1 << 24); writel(tmp, &(CmuReg->UsbClk)); /*pll9: periph 1 */ tmp = readl(&(CmuReg->Pll7Ctl)); tmp &= (~(0x80000000)); writel(tmp, &(CmuReg->Pll7Ctl)); /* pll mipi */ tmp = readl(&(CmuReg->PllMipi)); tmp &= (~(0x80000000)); writel(tmp, &(CmuReg->PllMipi)); #endif #if defined CONFIG_ARCH_SUN8IW10P1 || defined CONFIG_ARCH_SUN8IW11P1 /*pll2: for audio */ tmp = readl(&(CmuReg->Pll2Ctl)); tmp &= (~(0x80000000)); writel(tmp, &(CmuReg->Pll2Ctl)); /*pll3: for video */ tmp = readl(&(CmuReg->Pll3Ctl)); tmp &= (~(0x80000000)); writel(tmp, &(CmuReg->Pll3Ctl)); /*pll10: for de */ tmp = readl(&(CmuReg->Pll10Ctl)); tmp &= (~(0x80000000)); writel(tmp, &(CmuReg->Pll10Ctl)); #else /*pll4: for ve */ tmp = readl(&(CmuReg->Pll4Ctl)); tmp &= (~(0x80000000)); writel(tmp, &(CmuReg->Pll4Ctl)); /*pll5: for ddr */ tmp = readl(&(CmuReg->Pll5Ctl)); tmp &= (~(0x80000000)); writel(tmp, &(CmuReg->Pll5Ctl)); #endif return 0; } /* ********************************************************************************************************* * standby_clk_pllenable * * Description: enable dram pll. * * Arguments : none * * Returns : 0; ********************************************************************************************************* */ __s32 standby_clk_pllenable(void) { unsigned int tmp; #ifndef CONFIG_ARCH_SUN8IW11P1 /*pll 24M: */ tmp = readl(&(CmuReg->Pll24M)); tmp |= ((0x80000000)); writel(tmp, &(CmuReg->Pll24M)); #endif /*pll1 */ tmp = readl(&(CmuReg->Pll1Ctl)); tmp |= ((0x80000000)); writel(tmp, &(CmuReg->Pll1Ctl)); /*pll6: for periph0 */ tmp = readl(&(CmuReg->Pll6Ctl)); tmp |= ((0x80000000)); writel(tmp, &(CmuReg->Pll6Ctl)); #ifndef CONFIG_ARCH_SUN8IW11P1 /*pll9: periph 1 */ tmp = readl(&(CmuReg->Pll9Ctl)); tmp |= ((0x80000000)); writel(tmp, &(CmuReg->Pll9Ctl)); /*pll10: de */ tmp = readl(&(CmuReg->Pll10Ctl)); tmp |= ((0x80000000)); writel(tmp, &(CmuReg->Pll10Ctl)); #else /*pll9: periph 1 */ tmp = readl(&(CmuReg->Pll7Ctl)); tmp |= ((0x80000000)); writel(tmp, &(CmuReg->Pll7Ctl)); #endif #if 0 /*pll2: for audio */ tmp = readl(&(CmuReg->Pll2Ctl)); tmp |= ((0x80000000)); writel(tmp, &(CmuReg->Pll2Ctl)); /*pll3: for video */ tmp = readl(&(CmuReg->Pll3Ctl)); tmp |= ((0x80000000)); writel(tmp, &(CmuReg->Pll3Ctl)); /*pll4: for ve */ tmp = readl(&(CmuReg->Pll4Ctl)); tmp |= ((0x80000000)); writel(tmp, &(CmuReg->Pll4Ctl)); /*pll5: for ddr */ tmp = readl(&(CmuReg->Pll5Ctl)); tmp |= ((0x80000000)); writel(tmp, &(CmuReg->Pll5Ctl)); /*pll7: for isp */ tmp = readl(&(CmuReg->PllIspCtl)); tmp |= ((0x80000000)); writel(tmp, &(CmuReg->PllIspCtl)); #endif return 0; } #if 0 /* ********************************************************************************************************* * standby_clk_pll1enable * * Description: enable pll1. * * Arguments : none * ********************************************************************************************************* */ __s32 standby_clk_pll1enable(void) { CmuReg_Pll1Ctl_tmp.dwval = CmuReg->Pll1Ctl.dwval; CmuReg_Pll1Ctl_tmp.bits.PLLEn = 1; CmuReg->Pll1Ctl.dwval = CmuReg_Pll1Ctl_tmp.dwval; return 0; } #endif /* * standby_clk_set_keyfield * * Description: set keyfield for modify ldo enable bit. * * Arguments : none * * Returns : 0; */ void standby_clk_set_keyfield(void) { unsigned int tmp; /*keyfield set to: 0xa7 */ tmp = readl((void *)(0xf1c00000 + 0xf4)); tmp &= (~(0xff000000)); tmp |= ((0xa7000000)); writel(tmp, (0xf1c00000 + 0xf4)); } /* * standby_clk_unset_keyfield * * Description: unset keyfield for disable modify ldo enable bit. * * Arguments : none * * Returns : 0; */ void standby_clk_unset_keyfield(void) { unsigned int tmp; /*keyfield set to: 0 */ tmp = readl((0xf1c00000 + 0xf4)); tmp &= (~(0xff000000)); writel(tmp, (0xf1c00000 + 0xf4)); } /* ********************************************************************************************************* * standby_clk_hoscdisable * * Description: disable HOSC. * * Arguments : none * * Returns : 0; ********************************************************************************************************* */ __s32 standby_clk_hoscdisable(void) { unsigned int tmp; /*disable dcxo: band gap */ tmp = readl((0xf1c20328)); tmp &= (~(0x80000000)); writel(tmp, (0xf1c20328)); /*disable dcxo */ tmp = readl((0xf1c20324)); tmp &= (~(0x80020000)); writel(tmp, (0xf1c20324)); /*0xf1c00000 + 0xf4 (system_ctrl: pll ctrl reg1) */ /*bit2: hosc; */ /*bit1: ldo for analog; */ /*bit0: ldo for digital */ /*disable hosc */ tmp = readl((0xf1c00000 + 0xf4)); tmp &= (~(0x00000004)); writel(tmp, (0xf1c00000 + 0xf4)); return 0; } /* ********************************************************************************************************* * standby_clk_hoscenable * * Description: enable HOSC. * * Arguments : none * * Returns : 0; ********************************************************************************************************* */ __s32 standby_clk_hoscenable(void) { unsigned int tmp; /*0xf1c00000 + 0xf4 (system_ctrl: pll ctrl reg1) */ /*bit2: hosc; */ /*bit1: ldo for analog; */ /*bit0: ldo for digital */ /*enable hosc */ tmp = readl((0xf1c00000 + 0xf4)); tmp |= ((0x00000004)); writel(tmp, (0xf1c00000 + 0xf4)); /*enable dcxo */ tmp = readl((0xf1c20324)); tmp |= (0x80020000); writel(tmp, (0xf1c20324)); /*enable dcxo: band gap */ tmp = readl((0xf1c20328)); tmp |= (0x80000000); writel(tmp, (0xf1c20328)); return 0; } /* ********************************************************************************************************* * standby_clk_ldodisable * * Description: disable LDO. * * Arguments : none * * Returns : 0; ********************************************************************************************************* */ __s32 standby_clk_ldodisable(void) { unsigned int tmp; /*0xf1c00000 + 0xf4 (system_ctrl: pll ctrl reg1) */ /*bit2: hosc; */ /*bit1: ldo for analog; */ /*bit0: ldo for digital */ /*disable ldo */ tmp = readl((0xf1c00000 + 0xf4)); tmp &= (~(0x00000003)); writel(tmp, (0xf1c00000 + 0xf4)); return 0; } /* ********************************************************************************************************* * standby_clk_ldoenable * * Description: enable LDO. * * Arguments : none * * Returns : 0; ********************************************************************************************************* */ __s32 standby_clk_ldoenable(void) { unsigned int tmp; /*0xf1c00000 + 0xf4 (system_ctrl: pll ctrl reg1) */ /*bit2: hosc; */ /*bit1: ldo for analog; */ /*bit0: ldo for digital */ /*enable ldo */ tmp = readl((0xf1c00000 + 0xf4)); tmp |= ((0x00000003)); writel(tmp, (0xf1c00000 + 0xf4)); return 0; } /* ********************************************************************************************************* * standby_clk_setdiv * * Description: switch core clock to 32k low osc. * * Arguments : none * * Returns : 0; ********************************************************************************************************* */ __s32 standby_clk_setdiv(struct standby_clk_div_t *clk_div) { unsigned int tmp; if (!clk_div) { return -1; } /*ahb1 */ CmuReg_ahb1_tmp.dwval = CmuReg->Ahb1Div.dwval; CmuReg_ahb1_tmp.bits.Ahb1Div = clk_div->ahb_div; CmuReg_ahb1_tmp.bits.Ahb1PreDiv = clk_div->ahb_pre_div; CmuReg_ahb1_tmp.bits.Apb1Div = clk_div->apb_div; CmuReg->Ahb1Div.dwval = CmuReg_ahb1_tmp.dwval; /*axi */ CmuReg_SysClkDiv_tmp.dwval = CmuReg->SysClkDiv.dwval; CmuReg_SysClkDiv_tmp.bits.AXIClkDiv = clk_div->axi_div; CmuReg->SysClkDiv.dwval = CmuReg_SysClkDiv_tmp.dwval; /*apb2 */ CmuReg_apb2_tmp.dwval = CmuReg->Apb2Div.dwval; CmuReg_apb2_tmp.bits.DivM = clk_div->apb2_div; CmuReg_apb2_tmp.bits.DivN = clk_div->apb2_pre_div; CmuReg->Apb2Div.dwval = CmuReg_apb2_tmp.dwval; return 0; } /* ********************************************************************************************************* * standby_clk_getdiv * * Description: switch core clock to 32k low osc. * * Arguments : none * * Returns : 0; ********************************************************************************************************* */ __s32 standby_clk_getdiv(struct standby_clk_div_t *clk_div) { if (!clk_div) { return -1; } /*axi */ CmuReg_SysClkDiv_tmp.dwval = CmuReg->SysClkDiv.dwval; clk_div->axi_div = CmuReg_SysClkDiv_tmp.bits.AXIClkDiv; /*ahb1 */ CmuReg_ahb1_tmp.dwval = CmuReg->Ahb1Div.dwval; clk_div->ahb_div = CmuReg_ahb1_tmp.bits.Ahb1Div; clk_div->apb_div = CmuReg_ahb1_tmp.bits.Apb1Div; clk_div->ahb_pre_div = CmuReg_ahb1_tmp.bits.Ahb1PreDiv; /*apb2 */ CmuReg_apb2_tmp.dwval = CmuReg->Apb2Div.dwval; clk_div->apb2_div = CmuReg_apb2_tmp.bits.DivM; clk_div->apb2_pre_div = CmuReg_apb2_tmp.bits.DivN; return 0; } /* ********************************************************************************************************* * standby_clk_set_pll_factor * * Description: set pll factor, target cpu freq is 384M hz * * Arguments : none * * Returns : 0; ********************************************************************************************************* */ __s32 standby_clk_set_pll_factor(struct pll_factor_t *pll_factor) { __ccmu_pll1_reg0000_t pll1_ctrl; if (!pll_factor) { return -1; } pll1_ctrl.dwval = readl(&(CmuReg->Pll1Ctl)); pll1_ctrl.bits.FactorN = pll_factor->FactorN; pll1_ctrl.bits.FactorK = pll_factor->FactorK; pll1_ctrl.bits.FactorM = pll_factor->FactorM; pll1_ctrl.bits.FactorP = pll_factor->FactorP; writel(pll1_ctrl.dwval, &(CmuReg->Pll1Ctl)); /*busy_waiting(); */ return 0; } /* ********************************************************************************************************* * standby_clk_get_pll_factor * * Description: * * Arguments : none * * Returns : 0; ********************************************************************************************************* */ __s32 standby_clk_get_pll_factor(struct pll_factor_t *pll_factor) { __ccmu_pll1_reg0000_t pll1_ctrl; if (!pll_factor) { return -1; } pll1_ctrl.dwval = readl(&(CmuReg->Pll1Ctl)); pll_factor->FactorN = pll1_ctrl.bits.FactorN; pll_factor->FactorK = pll1_ctrl.bits.FactorK; pll_factor->FactorM = pll1_ctrl.bits.FactorM; pll_factor->FactorP = pll1_ctrl.bits.FactorP; /*busy_waiting(); */ return 0; } /* ********************************************************************************************************* * standby_clk_apb2losc * * Description: switch apb2 clock to 32k low osc. * * Arguments : none * * Returns : 0; ********************************************************************************************************* */ __s32 standby_clk_apb2losc(void) { unsigned int tmp; /*apb2 */ CmuReg_apb2_tmp.dwval = CmuReg->Apb2Div.dwval; CmuReg_apb2_tmp.bits.ClkSrc = APB2_CLKSRC_LOSC; CmuReg->Apb2Div.dwval = CmuReg_apb2_tmp.dwval; return 0; } /* ********************************************************************************************************* * standby_clk_apb2hosc * * Description: switch apb2 clock to 24M hosc. * * Arguments : none * * Returns : 0; ********************************************************************************************************* */ __s32 standby_clk_apb2hosc(void) { unsigned int tmp; /*apb2 */ CmuReg_apb2_tmp.dwval = CmuReg->Apb2Div.dwval; CmuReg_apb2_tmp.bits.ClkSrc = APB2_CLKSRC_HOSC; CmuReg->Apb2Div.dwval = CmuReg_apb2_tmp.dwval; return 0; } /* ********************************************************************************************************* * standby_clk_bus_src_backup * * Description: switch ahb2->? * ahb1->?. * * Arguments : none * * Returns : 0; ********************************************************************************************************* */ __s32 standby_clk_bus_src_backup(void) { /*backup bus src cfg */ /* backup ahb clk src */ CmuReg_ahb1_backup.dwval = CmuReg->Ahb1Div.dwval; /* backup apb clk src */ CmuReg_apb2_backup.dwval = CmuReg->Apb2Div.dwval; #ifdef CONFIG_ARCH_SUN8IW10P1 /* backup de/ee clk src */ CmuReg_de_backup = CmuReg->De0; CmuReg_ee_backup = CmuReg->Ee0; #endif return 0; } /* ********************************************************************************************************* * standby_clk_bus_src_set * * Description: switch ahb2->ahb1->axi. * * Arguments : none * * Returns : 0; ********************************************************************************************************* */ __s32 standby_clk_bus_src_set(void) { /* change ahb1 clock to axi */ CmuReg_ahb1_tmp.dwval = CmuReg->Ahb1Div.dwval; CmuReg_ahb1_tmp.bits.Ahb1ClkSrc = AHB1_CLKSRC_AXI; CmuReg->Ahb1Div.dwval = CmuReg_ahb1_tmp.dwval; /* printk("CmuReg_ahb1_backup, %x!\n", CmuReg_ahb1_backup); */ #ifdef CONFIG_ARCH_SUN8IW10P1 /* switch de clk to ahb */ CmuReg->De0 = 0x82000000; #endif return 0; } /* ********************************************************************************************************* * standby_clk_bus_src_restore * * Description: switch ahb2->? * ahb1->?. * * Arguments : none * * Returns : 0; ********************************************************************************************************* */ __s32 standby_clk_bus_src_restore(void) { /* restore ahb clk src */ CmuReg->Ahb1Div.dwval = CmuReg_ahb1_backup.dwval; /* restore apb clk src */ CmuReg->Apb2Div.dwval = CmuReg_apb2_backup.dwval; #ifdef CONFIG_ARCH_SUN8IW10P1 /* retore de/ee clk */ CmuReg->De0 = CmuReg_de_backup; CmuReg->Ee0 = CmuReg_ee_backup; #endif return 0; } /* ********************************************************************************************************* * standby_clk_dramgating * * Description: gating dram clock. * * Arguments : onoff dram clock gating on or off; * * Returns : 0; ********************************************************************************************************* */ void standby_clk_dramgating(int onoff) { unsigned int tmp; tmp = readl(&(CmuReg->Pll5Ctl)); if (onoff) { tmp |= (0x80000000); } else { tmp &= (~0x80000000); } writel(tmp, &(CmuReg->Pll5Ctl)); return; } __u32 standby_clk_get_cpu_freq(void) { __u32 FactorN = 1; __u32 FactorK = 1; __u32 FactorM = 1; __u32 FactorP = 1; __u32 reg_val = 0; __u32 cpu_freq = 0; CmuReg_SysClkDiv_tmp.dwval = CmuReg->SysClkDiv.dwval; /*get runtime freq: clk src + divider ratio */ /*src selection */ reg_val = CmuReg_SysClkDiv_tmp.bits.CpuClkSrc; if (0 == reg_val) { /*32khz osc */ cpu_freq = 32; } else if (1 == reg_val) { /*hosc, 24Mhz */ cpu_freq = 24000; /*unit is khz */ } else if (2 == reg_val || 3 == reg_val) { CmuReg_Pll1Ctl_tmp.dwval = CmuReg->Pll1Ctl.dwval; FactorN = CmuReg_Pll1Ctl_tmp.bits.FactorN + 1; FactorK = CmuReg_Pll1Ctl_tmp.bits.FactorK + 1; FactorM = CmuReg_Pll1Ctl_tmp.bits.FactorM + 1; FactorP = 1 << (CmuReg_Pll1Ctl_tmp.bits.FactorP); cpu_freq = raw_lib_udiv(24000 * FactorN * FactorK, FactorP * FactorM); } /*printk("cpu_freq = dec(%d). \n", cpu_freq); */ /*busy_waiting(); */ return cpu_freq; } #endif