274 lines
6.1 KiB
C
274 lines
6.1 KiB
C
/*
|
|
* Copyright (c) 2021-2022 Amlogic, Inc. All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: MIT
|
|
*/
|
|
|
|
#include "FreeRTOS.h"
|
|
#include <common.h>
|
|
#include "register.h"
|
|
#include "p_register.h"
|
|
#include "uart.h"
|
|
#include <task.h>
|
|
#include "soc.h"
|
|
#include "timer_source.h"
|
|
#include "clk.h"
|
|
#include "clk_util.h"
|
|
#include "vad_suspend.h"
|
|
#include "power_domain.h"
|
|
#include "mailbox-api.h"
|
|
#include "suspend.h"
|
|
#include "uart.h"
|
|
#include "c_mmc_reg.h"
|
|
|
|
extern uint32_t get_reason_flag(void);
|
|
|
|
void set_time(uint32_t val)
|
|
{
|
|
#ifdef ARM_CPU
|
|
REG32(SYSCTRL_SEC_TIMERE) = 0x0;
|
|
#else
|
|
REG32(SYSCTRL_TIMERF) = val;
|
|
#endif
|
|
}
|
|
|
|
uint32_t get_time(void)
|
|
{
|
|
uint64_t timerE = 0;
|
|
|
|
#ifdef ARM_CPU
|
|
timerE = REG32(SYSCTRL_SEC_TIMERE);
|
|
#else
|
|
timerE = REG32(SYSCTRL_TIMERF);
|
|
#endif
|
|
return (timerE);
|
|
}
|
|
|
|
/*
|
|
* use_clk_src
|
|
* 0. osc_clk
|
|
* 1. sys_clk (rtc_pll) clk_div1
|
|
* 2. sys_clk (rtc_pll) clk_div2
|
|
* 3. rtc_clk
|
|
* Note:
|
|
* 1. If select sys_clk, tick clk of 1us/10us/100us/1ms/xtal3 are all same
|
|
* 2. If select rtc_clk, tick clk of 1us/10us/100us/1ms/xtal3 will actually
|
|
* be 1ms/10ms/100ms/1s/93.747us
|
|
*/
|
|
|
|
void alt_timebase(int use_clk_src)
|
|
{
|
|
uint32_t clk_div = 0;
|
|
|
|
if (use_clk_src == 0)
|
|
//select osc_clk
|
|
REG32(CLKCTRL_TIMEBASE_CTRL0) = 0x20018;
|
|
else if (use_clk_src == 1) {
|
|
//select sys_clk (rtc_pll) clk_div1
|
|
//if sys_clk is 11.171MHz
|
|
clk_div = 11;
|
|
REG32(CLKCTRL_TIMEBASE_CTRL0) = (clk_div << 19) | (0x2aa << 6);
|
|
} else if (use_clk_src == 2) {
|
|
//select sys_clk (rtc_pll) clk_div2 when sys_clk < 256MHz
|
|
//if sys_clk is 122.88MHz
|
|
clk_div = 123;
|
|
REG32(CLKCTRL_TIMEBASE_CTRL0) = (clk_div << 24) | (0x3ff << 6);
|
|
} else {
|
|
//select rtc clk
|
|
// 32k/32 = 1k
|
|
REG32(CLKCTRL_TIMEBASE_CTRL0) = 0x20020;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* This is function for axi clk setting:
|
|
* Includes axi_clk(AKA cpu_axi_clk/ACLK), axi_matrix, axi_sram
|
|
*
|
|
*/
|
|
void set_axi_div_clk(int sel, int div)
|
|
{
|
|
uint32_t control;
|
|
uint32_t dyn_pre_mux;
|
|
uint32_t dyn_div;
|
|
|
|
// fclk_div4 = 500MHz
|
|
dyn_pre_mux = sel;
|
|
dyn_div = div; /* divide by 1 */
|
|
|
|
control = REG32(CLKCTRL_AXI_CLK_CTRL0);
|
|
if (control & (1 << 15)) { //default is preb, need use prea
|
|
control =
|
|
(control & ~(0x3fff)) | ((1 << 13) | (dyn_pre_mux << 10) | (dyn_div << 0));
|
|
REG32(CLKCTRL_AXI_CLK_CTRL0) = control;
|
|
control = control & ~(1 << 15);
|
|
REG32(CLKCTRL_AXI_CLK_CTRL0) = control;
|
|
udelay(25);
|
|
} else {
|
|
//preb
|
|
control = (control & ~((0x3fff) << 16)) |
|
|
((1 << 29) | (dyn_pre_mux << 26) | (dyn_div << 16));
|
|
REG32(CLKCTRL_AXI_CLK_CTRL0) = control;
|
|
control = control | (1 << 15);
|
|
REG32(CLKCTRL_AXI_CLK_CTRL0) = control;
|
|
udelay(25);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* This is function for clk81 setting
|
|
*
|
|
*/
|
|
void set_sys_div_clk(int sel, int div)
|
|
{
|
|
uint32_t control;
|
|
uint32_t dyn_pre_mux;
|
|
uint32_t dyn_div;
|
|
|
|
printf("Set sys clock to 167Mhz\n");
|
|
|
|
// fclk_div4 = 500MHz
|
|
dyn_pre_mux = sel;
|
|
dyn_div = div; /* divide by 3 */
|
|
|
|
control = REG32(CLKCTRL_SYS_CLK_CTRL0);
|
|
|
|
if (control & (1 << 15)) { //default is preb, need use prea
|
|
control =
|
|
(control & ~(0x3fff)) | ((1 << 13) | (dyn_pre_mux << 10) | (dyn_div << 0));
|
|
REG32(CLKCTRL_SYS_CLK_CTRL0) = control;
|
|
control = control & ~(1 << 15);
|
|
REG32(CLKCTRL_SYS_CLK_CTRL0) = control;
|
|
udelay(25);
|
|
} else {
|
|
//preb
|
|
control = (control & ~((0x3fff) << 16)) |
|
|
((1 << 29) | (dyn_pre_mux << 26) | (dyn_div << 16));
|
|
REG32(CLKCTRL_SYS_CLK_CTRL0) = control;
|
|
control = control | (1 << 15);
|
|
REG32(CLKCTRL_SYS_CLK_CTRL0) = control;
|
|
udelay(25);
|
|
}
|
|
|
|
/* when bus switched from 24MHz to 166MHz,
|
|
* the clock tick used to generate OTP waveform
|
|
* needs 20us waiting time to switch to new clock tick
|
|
*/
|
|
udelay(25);
|
|
}
|
|
|
|
void disable_pll(int id)
|
|
{
|
|
switch (id) {
|
|
case PLL_SYS:
|
|
REG32(ANACTRL_SYSPLL_CTRL0) = (1 << 29);
|
|
break;
|
|
case PLL_GP0:
|
|
REG32(ANACTRL_GP0PLL_CTRL0) = (1 << 29);
|
|
break;
|
|
case PLL_GP1:
|
|
REG32(ANACTRL_GP1PLL_CTRL0) = (1 << 29);
|
|
break;
|
|
case PLL_FIX:
|
|
REG32(ANACTRL_FIXPLL_CTRL0) = (1 << 29);
|
|
break;
|
|
case PLL_HIFI:
|
|
REG32(ANACTRL_HIFIPLL_CTRL0) = (1 << 29);
|
|
break;
|
|
case PLL_RTC:
|
|
REG32(ANACTRL_RTCPLL_CTRL0) = (1 << 29);
|
|
break;
|
|
case PLL_DDR:
|
|
REG32(AM_DDR_PLL_CNTL0) = (1 << 29);
|
|
break;
|
|
default:
|
|
printf("Error: PLL is not in list\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void start_off_fsm_of_chip_core(void)
|
|
{
|
|
// start fsm to shut down chip_core
|
|
REG32(AO_PWRCTRL_SHUT_DN) = 1;
|
|
|
|
// Counter increases 1
|
|
REG32(AO_PWRCTRL_SW_COUNT) += 1;
|
|
}
|
|
|
|
static void init_ao_pwr_ctrl(void)
|
|
{
|
|
// pmic_sleep high valid
|
|
REG32(AO_PWRCTRL_MODE) |= (0<<1); // high valid
|
|
|
|
// SLEEP: delay between kick_off to core_iso_en = 1
|
|
REG32(AO_PWRCTRL_OFF_DLY0) = 10; // 10ms, unit: 1ms
|
|
|
|
// SLEEP: delay between core_iso_en = 1 to pmic_sleep = 1
|
|
REG32(AO_PWRCTRL_OFF_DLY1) = 1; // 1ms, unit: 1ms
|
|
|
|
// WAKEUP: delay between pmic_sleep = 0 to core_iso_en = 0
|
|
REG32(AO_PWRCTRL_ON_DLY) = 1;
|
|
|
|
#ifdef USE_GPIOAO_2_CTRL_PMIC
|
|
REG32(PADCTRL_PIN_MUX_REGAO) &= ~(0xf << 8);
|
|
REG32(PADCTRL_PIN_MUX_REGAO) |= (0x4 << 8);
|
|
#else
|
|
REG32(PADCTRL_PIN_MUX_REGAO) &= ~(0xf << 16);
|
|
REG32(PADCTRL_PIN_MUX_REGAO) |= (0x4 << 16);
|
|
#endif
|
|
}
|
|
|
|
int oscin_ctrl_reg;
|
|
void vCLK_resume(uint32_t st_f)
|
|
{
|
|
if (st_f) {
|
|
/* switch osc_clk back*/
|
|
REG32(CLKCTRL_SYSOSCIN_CTRL) = 1;
|
|
REG32(CLKCTRL_OSCIN_CTRL) = oscin_ctrl_reg | (1 << 31);
|
|
udelay(2000);
|
|
/* switching tick timer (using osc_clk) */
|
|
alt_timebase(0);
|
|
|
|
set_sys_div_clk(0, 0); // osc_clk
|
|
set_axi_div_clk(0, 0); // osc_clk
|
|
vUartChangeBaudrate_resume(921600);
|
|
udelay(1000);
|
|
disable_pll(PLL_RTC);
|
|
power_switch_to_wraper(PWR_ON);
|
|
/* open mem_pd of srama and sramb */
|
|
REG32(PWRCTRL_MEM_PD2) = 0x0;
|
|
}
|
|
|
|
// In a55 boot code
|
|
REG32(PWRCTRL_ACCESS_CTRL) = 0x0; // default access pwrctrl
|
|
}
|
|
|
|
void vCLK_suspend(uint32_t st_f)
|
|
{
|
|
printf("enter vCLK suspend\n");
|
|
|
|
if (st_f) {
|
|
/* poweroff wrapper */
|
|
power_switch_to_wraper(PWR_OFF);
|
|
udelay(2000);
|
|
|
|
// switch clock from sys_clk to osc_clk
|
|
REG32(AO_CLKCTRL_OSCIN_CTRL) |= (1<<0); // select osc_clk
|
|
// switch clock from osc_clk to rtc_clk
|
|
REG32(AO_CLKCTRL_OSCIN_CTRL) |= (1<<1); // select rtc_clk
|
|
|
|
/***start_ao_standby_flow ***/
|
|
// initial ao pwr_ctrl
|
|
init_ao_pwr_ctrl();
|
|
|
|
// start fsm to power off chip_core
|
|
start_off_fsm_of_chip_core();
|
|
|
|
printf("soc poweroff\n");
|
|
/* power off osc_clk */
|
|
REG32(CLKCTRL_SYSOSCIN_CTRL) = 0;
|
|
} else {
|
|
printf("run at 24MHz\n");
|
|
}
|
|
}
|