OSHW-DEIMOS/SOFTWARE/A64-TERES/linux-a64/drivers/soc/allwinner/pm/standby/main.c
Dimitar Gamishev f9b0e7a283 linux
2017-10-13 14:07:04 +03:00

213 lines
4.9 KiB
C

/*
* standby driver for allwinnertech
*
* Copyright (C) 2015 allwinnertech Ltd.
* Author: Ming Li <liming@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 "main.h"
static struct aw_pm_info pm_info;
static extended_standby_t extended_standby_para_info;
static struct pll_factor_t orig_pll;
static struct pll_factor_t local_pll;
static struct standby_clk_div_t clk_div;
static struct standby_clk_div_t tmp_clk_div;
static int dram_enter_selfresh(extended_standby_t *para);
static int dram_exit_selfresh(void);
static int cpu_enter_lowfreq(void);
static int cpu_freq_resume(void);
static int bus_enter_lowfreq(extended_standby_t *para);
static int bus_freq_resume(extended_standby_t *para);
static void query_wakeup_source(struct aw_pm_info *arg);
int standby_main(struct aw_pm_info *arg)
{
save_mem_status(STANDBY_START | 0X01);
/* copy standby parameter from dram */
standby_memcpy(&pm_info, arg, sizeof(pm_info));
/* copy extended standby info */
if(0 != pm_info.standby_para.pextended_standby) {
standby_memcpy(&extended_standby_para_info, (void *)(pm_info.standby_para.pextended_standby), sizeof(extended_standby_para_info));
}
mem_clk_init(1);
/* init uart for print */
if(unlikely(pm_info.standby_para.debug_mask&PM_STANDBY_PRINT_STANDBY)){
serial_init_manager();
}
save_mem_status(STANDBY_START | 0X02);
/* enable dram enter into self-refresh */
dram_enter_selfresh(&extended_standby_para_info);
save_mem_status(STANDBY_START | 0X03);
/* cpu reduce frequency */
cpu_enter_lowfreq();
save_mem_status(STANDBY_START | 0X04);
/* power domain suspend */
#ifdef CONFIG_AW_AXP
standby_twi_init(pm_info.pmu_arg.twi_port);
if (SUPER_STANDBY_FLAG == extended_standby_para_info.id)
power_enter_super(&pm_info, &extended_standby_para_info);
dm_suspend(&pm_info, &extended_standby_para_info);
#endif
printk("test printk...\n");
save_mem_status(STANDBY_START | 0X05);
/* bus reduce frequency */
bus_enter_lowfreq(&extended_standby_para_info);
/* cpu enter sleep, wait wakeup by interrupt */
asm("WFI");
/* bus freq resume */
bus_freq_resume(&extended_standby_para_info);
save_mem_status(RESUME0_START | 0X01);
/* cpu freq resume */
cpu_freq_resume();
save_mem_status(RESUME0_START | 0X02);
/* power domain resume */
#ifdef CONFIG_AW_AXP
dm_resume(&extended_standby_para_info);
standby_twi_exit();
#endif
save_mem_status(RESUME0_START | 0X03);
/* dram out self-refresh */
dram_exit_selfresh();
save_mem_status(RESUME0_START | 0X04);
if(unlikely(pm_info.standby_para.debug_mask&PM_STANDBY_PRINT_STANDBY)){
serial_exit_manager();
}
return 0;
}
static int dram_enter_selfresh(extended_standby_t *para)
{
s32 ret = -1;
return ret;
}
static int dram_exit_selfresh(void)
{
s32 ret = -1;
return ret;
}
static int cpu_enter_lowfreq(void)
{
standby_clk_init();
/* backup cpu freq */
standby_clk_get_pll_factor(&orig_pll);
/* backup bus src */
standby_clk_bus_src_backup();
/*lower freq from 1008M to 408M*/
local_pll.FactorN = 16;
local_pll.FactorK = 0;
local_pll.FactorM = 0;
local_pll.FactorP = 0;
standby_clk_set_pll_factor(&local_pll);
delay_ms(10);
/* switch cpu clock to HOSC, and disable pll */
standby_clk_core2hosc();
delay_us(1);
return 0;
}
static int cpu_freq_resume(void)
{
/* switch cpu clock to core pll */
standby_clk_core2pll();
change_runtime_env();
delay_ms(10);
/*restore freq from 384 to 1008M*/
standby_clk_set_pll_factor(&orig_pll);
change_runtime_env();
delay_ms(5);
return 0;
}
static int bus_enter_lowfreq(extended_standby_t *para)
{
/* change ahb src to axi? losc?*/
standby_clk_bus_src_set();
standby_clk_getdiv(&clk_div);
/* set clock division cpu:axi:ahb:apb = 2:2:2:1 */
tmp_clk_div.axi_div = 0;
tmp_clk_div.ahb_div = 0;
tmp_clk_div.ahb_pre_div = 0;
tmp_clk_div.apb_div = 0;
tmp_clk_div.apb_pre_div = 0;
standby_clk_setdiv(&tmp_clk_div);
/* swtich apb2 to losc */
standby_clk_apb2losc();
change_runtime_env();
//delay_ms(1);
standby_clk_plldisable();
/* switch cpu to 32k */
standby_clk_core2losc();
if(1 == para->soc_dram_state.selfresh_flag){
// disable HOSC, and disable LDO
standby_clk_hoscdisable();
standby_clk_ldodisable();
}
return 0;
}
static int bus_freq_resume(extended_standby_t *para)
{
if(1 == para->soc_dram_state.selfresh_flag){
/* enable LDO, enable HOSC */
standby_clk_ldoenable();
/* delay 1ms for power be stable */
//3ms
standby_delay_cycle(1);
standby_clk_hoscenable();
//3ms
standby_delay_cycle(1);
}
/* switch clock to hosc */
standby_clk_core2hosc();
/* swtich apb2 to hosc */
standby_clk_apb2hosc();
/* restore clock division */
standby_clk_setdiv(&clk_div);
/* enable pll */
standby_clk_pllenable();
delay_ms(10);
standby_clk_bus_src_restore();
return 0;
}