mirror of https://github.com/OpenIPC/firmware.git
				
				
				
			
		
			
				
	
	
		
			318 lines
		
	
	
		
			8.4 KiB
		
	
	
	
		
			Diff
		
	
	
			
		
		
	
	
			318 lines
		
	
	
		
			8.4 KiB
		
	
	
	
		
			Diff
		
	
	
| diff -drupN a/tools/pm-sleep/pm_sleep.c b/tools/pm-sleep/pm_sleep.c
 | |
| --- a/tools/pm-sleep/pm_sleep.c	1970-01-01 03:00:00.000000000 +0300
 | |
| +++ b/tools/pm-sleep/pm_sleep.c	2022-06-09 05:02:37.000000000 +0300
 | |
| @@ -0,0 +1,313 @@
 | |
| +
 | |
| +
 | |
| +#include <cache.h>
 | |
| +
 | |
| +#include <common.h>
 | |
| +#include <cpm.h>
 | |
| +#include <ddr.h>
 | |
| +#include <smp_cp0.h>
 | |
| +#include <pm_sleep.h>
 | |
| +#include <i2c-gpio.h>
 | |
| +#include <gpio.h>
 | |
| +#include <uart.h>
 | |
| +#include <cpufreq.h>
 | |
| +#include <cpu.h>
 | |
| +
 | |
| +unsigned int *extern_func;
 | |
| +
 | |
| +struct sleep_param *p_slp_param;
 | |
| +extern void scale_cpu_freq(int status, unsigned int *cpccr);
 | |
| +
 | |
| +struct save_register
 | |
| +{
 | |
| +	unsigned int ddr_autosr;
 | |
| +	unsigned int ddr_dlp;
 | |
| +	unsigned int ddr_ctrl;
 | |
| +	unsigned int cpm_cpccr;
 | |
| +	unsigned int c0_config;
 | |
| +	unsigned int c0_status;
 | |
| +	unsigned int smp_cp0_ctrl;
 | |
| +
 | |
| +
 | |
| +	unsigned char pmu_pin_func;
 | |
| +	unsigned char pmu_register_val;
 | |
| +};
 | |
| +
 | |
| +static struct save_register g_save_register;
 | |
| +/* static void i2c_sleep_set_data(void) */
 | |
| +/* { */
 | |
| +/* 	struct i2c_gpio i2c; */
 | |
| +/* 	unsigned int ret; */
 | |
| +/* 	if(p_slp_param->pmu_addr != 0xff){ */
 | |
| +/* 		i2c.scl = p_slp_param->pmu_i2c_scl; */
 | |
| +/* 		i2c.sda = p_slp_param->pmu_i2c_sda; */
 | |
| +/* 		ret = i2c_read(&i2c, */
 | |
| +/* 			       p_slp_param->pmu_addr, p_slp_param->pmu_reg, 1, */
 | |
| +/* 			       &g_save_register.pmu_register_val, 1); */
 | |
| +/* 		if(ret != 0) */
 | |
| +/* 		{ */
 | |
| +/* 			p_slp_param->pmu_addr = -1; */
 | |
| +/* 		}else */
 | |
| +/* 			ret = i2c_write(&i2c, */
 | |
| +/* 				  p_slp_param->pmu_addr, p_slp_param->pmu_reg, 1, */
 | |
| +/* 				  &p_slp_param->pmu_register_val, 1); */
 | |
| +/* 		i2c_reinit(&i2c); */
 | |
| +/* 	} */
 | |
| +/* } */
 | |
| +/* static int i2c_restore_data(void) */
 | |
| +/* { */
 | |
| +/* 	struct i2c_gpio i2c; */
 | |
| +/* 	unsigned char val; */
 | |
| +/* 	int ret = 0; */
 | |
| +/* 	if(p_slp_param->pmu_addr != 0xff){ */
 | |
| +
 | |
| +/* 		i2c.scl = p_slp_param->pmu_i2c_scl; */
 | |
| +/* 		i2c.sda = p_slp_param->pmu_i2c_sda; */
 | |
| +/* 		ret = i2c_write(&i2c, */
 | |
| +/* 			  p_slp_param->pmu_addr, p_slp_param->pmu_reg, 1, */
 | |
| +/* 			  &g_save_register.pmu_register_val, 1); */
 | |
| +/* 		if(ret != 0) */
 | |
| +/* 			return -1; */
 | |
| +/* 		ret = i2c_read(&i2c, */
 | |
| +/* 			       p_slp_param->pmu_addr, p_slp_param->pmu_reg, 1, */
 | |
| +/* 			       &val, 1); */
 | |
| +/* 		if(ret != 0) */
 | |
| +/* 			return -1; */
 | |
| +/* 		if(val != g_save_register.pmu_register_val) */
 | |
| +/* 		{ */
 | |
| +/* 			return -1; */
 | |
| +/* 		} */
 | |
| +
 | |
| +/* 	} */
 | |
| +/* 	return 0; */
 | |
| +/* } */
 | |
| +
 | |
| +
 | |
| +void sleep_pm_exit();
 | |
| +void call_function(unsigned int pc, int arg);
 | |
| +int set_core_voltage(int vol_mv);
 | |
| +void core_sleep_enter(void)
 | |
| +{
 | |
| +	unsigned int val;
 | |
| +	struct save_register *p_save_register = &g_save_register;
 | |
| +
 | |
| +	serial_setid(p_slp_param->uart_id);
 | |
| +
 | |
| +	flush_cache_all();
 | |
| +	set_resume_pc((unsigned int)sleep_pm_exit);
 | |
| +
 | |
| +	if(p_slp_param->prev_sleep_pc != 0xffffffff) {
 | |
| +		/* serial_put_hex(p_slp_param->prev_sleep_pc); */
 | |
| +		call_function(p_slp_param->prev_sleep_pc, 0);
 | |
| +	}
 | |
| +
 | |
| +	p_save_register->c0_config = read_c0_config();
 | |
| +	p_save_register->c0_status = read_c0_status();
 | |
| +
 | |
| +	ddr_writel(0x0, DDRP_DTAR);
 | |
| +	p_save_register->ddr_autosr = ddr_readl(DDRC_AUTOSR_EN);
 | |
| +	ddr_writel(0,DDRC_AUTOSR_EN); // exit auto sel-refresh
 | |
| +	p_save_register->ddr_dlp = ddr_readl(DDRC_DLP);
 | |
| +	if(!(ddr_readl(DDRP_PIR) & DDRP_PIR_DLLBYP))
 | |
| +	{
 | |
| +		ddr_writel(0xf003 , DDRC_DLP);
 | |
| +		/* val = ddr_readl(DDRP_DSGCR); */
 | |
| +		/* val |= (1 << 4); */
 | |
| +		/* ddr_writel(val,DDRP_DSGCR); */
 | |
| +	}
 | |
| +        /**
 | |
| +	 *  DDR keep selrefresh,when it exit the sleep state.
 | |
| +	 */
 | |
| +	val = ddr_readl(DDRC_CTRL);
 | |
| +	p_save_register->ddr_ctrl = val;
 | |
| +	val &= ~(0x1f << 11);  // remove power down.
 | |
| +	val |= (1 << 17) | (1 << 5);   // enter to hold ddr state
 | |
| +	ddr_writel(val,DDRC_CTRL);
 | |
| +
 | |
| +	scale_cpu_freq(SCALE, &p_save_register->cpm_cpccr);
 | |
| +
 | |
| +	//  DDR CLK GATE OFF
 | |
| +	/* cpm_set_bit(31,CPM_CLKGR); */
 | |
| +
 | |
| +	p_save_register->smp_cp0_ctrl = __read_32bit_c0_register($12, 2); /* cache attr */
 | |
| +	__write_32bit_c0_register($12, 2, p_save_register->smp_cp0_ctrl | (1<<31));
 | |
| +
 | |
| +	/* i2c_sleep_set_data(); */
 | |
| +	if(p_slp_param->pmu_pin_func != 0xff)
 | |
| +	{
 | |
| +		p_save_register->pmu_pin_func = get_gpio_func(p_slp_param->pmu_pin);
 | |
| +		set_gpio_func(p_slp_param->pmu_pin,p_slp_param->pmu_pin_func);
 | |
| +	}else
 | |
| +		p_save_register->pmu_pin_func = 0xff;
 | |
| +
 | |
| +	if(p_slp_param->post_sleep_pc != 0xffffffff)
 | |
| +	{
 | |
| +		/* serial_put_hex(p_slp_param->post_sleep_pc); */
 | |
| +		call_function(p_slp_param->post_sleep_pc, 0);
 | |
| +	}
 | |
| +	write_c0_status(p_save_register->c0_status | 1 << 10);
 | |
| +	/* serial_put_hex(cpm_inl(CPM_OPCR)); */
 | |
| +	serial_putc('e');
 | |
| +	__asm__ volatile(".set push\n\t"
 | |
| +					 ".set mips32\n\t"
 | |
| +					 "sync \n\t"
 | |
| +					 "nop\n\t"
 | |
| +					 "wait\n\t"
 | |
| +					 "nop\n\t"
 | |
| +					 "nop\n\t"
 | |
| +					 "nop\n\t"
 | |
| +					 "jr %0\n\t"
 | |
| +					 ".set mips32 \n\t"
 | |
| +					 ".set pop\n\t"
 | |
| +					 :
 | |
| +					 :"r" ((unsigned int)sleep_pm_exit));
 | |
| +	while(1)
 | |
| +		serial_putc('E');
 | |
| +
 | |
| +}
 | |
| +
 | |
| +
 | |
| +void core_sleep_restore(void)
 | |
| +{
 | |
| +	int val = 0;
 | |
| +	int bypassmode = 0;
 | |
| +	struct save_register *p_save_register = &g_save_register;
 | |
| +
 | |
| +	serial_putc('O');
 | |
| +
 | |
| +	write_c0_config(p_save_register->c0_config);
 | |
| +	write_c0_status(p_save_register->c0_status);
 | |
| +
 | |
| +	/*
 | |
| +	 * For voice triger in sleep mode of pmu.
 | |
| +	 */
 | |
| +	/* if(i2c_restore_data() != 0) */
 | |
| +	/* { */
 | |
| +	/* 	serial_putc('E'); */
 | |
| +	/* 	serial_putc('v'); */
 | |
| +	/* 	__asm__ volatile(".set mips32\n\t" */
 | |
| +	/* 			 "wait\n\t" */
 | |
| +	/* 			 "nop\n\t" */
 | |
| +	/* 			 ".set mips32 \n\t"); */
 | |
| +	/* } */
 | |
| +
 | |
| +	if(p_slp_param->prev_resume_pc != 0xffffffff)
 | |
| +	{
 | |
| +		__jz_cache_init();
 | |
| +		/* serial_put_hex(p_slp_param->prev_resume_pc); */
 | |
| +		call_function(p_slp_param->prev_resume_pc, p_save_register->cpm_cpccr);
 | |
| +	}
 | |
| +
 | |
| +	if(p_slp_param->pmu_pin != 0xff)
 | |
| +	{
 | |
| +		set_gpio_func(p_slp_param->pmu_pin,p_save_register->pmu_pin_func);
 | |
| +	}
 | |
| +
 | |
| +	scale_cpu_freq(RESTORE, &p_save_register->cpm_cpccr);
 | |
| +
 | |
| +	//  DDR CLK GATE ON
 | |
| +	/* cpm_clear_bit(31,CPM_CLKGR); */
 | |
| +
 | |
| +	bypassmode = ddr_readl(DDRP_PIR) & DDRP_PIR_DLLBYP;
 | |
| +	if(!bypassmode) {
 | |
| +		/**
 | |
| +		 * reset dll of ddr.
 | |
| +		 * WARNING: 2015-01-08
 | |
| +		 * 	DDR CLK GATE(CPM_DRCG 0xB00000D0), BIT6 must set to 1 (or 0x40).
 | |
| +		 * 	If clear BIT6, chip memory will not stable, gpu hang occur.
 | |
| +		 */
 | |
| +		/* { */
 | |
| +		/* 	val = ddr_readl(DDRP_DSGCR); */
 | |
| +		/* 	val &= ~(1 << 4); */
 | |
| +		/* 	ddr_writel(val,DDRP_DSGCR); */
 | |
| +		/* } */
 | |
| +#define CPM_DRCG (0xB00000D0)
 | |
| +
 | |
| +		*(volatile unsigned int *)CPM_DRCG |= (1<<1);
 | |
| +		TCSM_DELAY(0x1ff);
 | |
| +		*(volatile unsigned int *)CPM_DRCG &= ~(1<<1);
 | |
| +		TCSM_DELAY(0x1ff);
 | |
| +		/*
 | |
| +		 * for disabled ddr enter power down.
 | |
| +		 */
 | |
| +		*(volatile unsigned int *)0xb301102c &= ~(1 << 4);
 | |
| +		TCSM_DELAY(0xf);
 | |
| +
 | |
| +		/*
 | |
| +		 * reset dll of ddr too.
 | |
| +		 */
 | |
| +		*(volatile unsigned int *)CPM_DRCG |= (1<<1);
 | |
| +		TCSM_DELAY(0x1ff);
 | |
| +		*(volatile unsigned int *)CPM_DRCG &= ~(1<<1);
 | |
| +		TCSM_DELAY(0x1ff);
 | |
| +
 | |
| +		val = DDRP_PIR_INIT | DDRP_PIR_ITMSRST  | DDRP_PIR_DLLSRST | DDRP_PIR_DLLLOCK;// | DDRP_PIR_ZCAL  ;
 | |
| +		ddr_writel(val, DDRP_PIR);
 | |
| +		val = DDRP_PGSR_IDONE | DDRP_PGSR_DLDONE | DDRP_PGSR_DIDONE;// | DDRP_PGSR_ZCDONE;
 | |
| +		while ((ddr_readl(DDRP_PGSR) & val) != val) {
 | |
| +			if(ddr_readl(DDRP_PGSR) & (DDRP_PGSR_DTERR | DDRP_PGSR_DTIERR)) {
 | |
| +				serial_putc('e');
 | |
| +				break;
 | |
| +			}
 | |
| +			serial_put_hex(ddr_readl(DDRP_ZQXCR0(0)));
 | |
| +			serial_put_hex(ddr_readl(DDRP_ZQXSR0(0)));
 | |
| +			serial_put_hex(ddr_readl(DDRP_PGSR));
 | |
| +			serial_putc('\r');
 | |
| +			serial_putc('\n');
 | |
| +		}
 | |
| +	}
 | |
| +
 | |
| +	/* exit the ddr selrefresh */
 | |
| +	val = ddr_readl(DDRC_CTRL);
 | |
| +	val |= 1 << 1;
 | |
| +	val &= ~((1<< 17) | (1 << 5));    // exit to hold ddr state
 | |
| +	ddr_writel(val,DDRC_CTRL);
 | |
| +	/* ddr trainning. */
 | |
| +	if(!bypassmode){
 | |
| +		val = DDRP_PIR_INIT | DDRP_PIR_QSTRN;
 | |
| +	}else
 | |
| +		val = DDRP_PIR_INIT | DDRP_PIR_QSTRN | DDRP_PIR_DLLBYP;
 | |
| +	ddr_writel(val, DDRP_PIR);
 | |
| +	val = (DDRP_PGSR_IDONE | DDRP_PGSR_DLDONE | DDRP_PGSR_DIDONE | DDRP_PGSR_DTDONE);
 | |
| +	while ((ddr_readl(DDRP_PGSR) & val) != val) {
 | |
| +		if(ddr_readl(DDRP_PGSR) & (DDRP_PGSR_DTERR | DDRP_PGSR_DTIERR)) {
 | |
| +			serial_putc('e');
 | |
| +			break;
 | |
| +		}
 | |
| +		serial_put_hex(ddr_readl(DDRP_PGSR));
 | |
| +		serial_putc('\r');
 | |
| +		serial_putc('\n');
 | |
| +	}
 | |
| +
 | |
| +	if(!bypassmode)
 | |
| +	{
 | |
| +		*(volatile unsigned int *)0xb301102c |= (1 << 4);
 | |
| +		TCSM_DELAY(0xf);
 | |
| +	}
 | |
| +
 | |
| +	/* serial_putc('d'); */
 | |
| +	/* serial_put_hex(*(unsigned int *)p_slp_param->post_resume_pc); */
 | |
| +
 | |
| +	if(!p_save_register->ddr_dlp && !bypassmode)
 | |
| +	{
 | |
| +		ddr_writel(0x0 , DDRC_DLP);
 | |
| +	}
 | |
| +	if(p_save_register->ddr_autosr) {
 | |
| +		ddr_writel(1,DDRC_AUTOSR_EN);   // enter auto sel-refresh
 | |
| +	}
 | |
| +	ddr_writel(p_save_register->ddr_ctrl, DDRC_CTRL);
 | |
| +
 | |
| +	l2cache_enable();
 | |
| +//	dump_ddr_param();
 | |
| +	__jz_cache_init();
 | |
| +
 | |
| +	/* serial_put_hex(*(unsigned int *)p_slp_param->post_resume_pc); */
 | |
| +	__write_32bit_c0_register($12, 2,p_save_register->smp_cp0_ctrl);
 | |
| +	if(p_slp_param->post_resume_pc != 0xfffffff)
 | |
| +	{
 | |
| +		call_function(p_slp_param->post_resume_pc, 0);
 | |
| +	}
 | |
| +
 | |
| +	while(1)
 | |
| +		serial_putc('s');
 | |
| +}
 |