oleavr-rgl-a500-mini-linux-.../drivers/soc/allwinner/pm/standby/standby_clock.c
Ole André Vadla Ravnås 169c65d57e Initial commit
2022-05-07 01:01:45 +02:00

819 lines
20 KiB
C

/*
* 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