📄 pm.c
字号:
/********************** BEGIN LICENSE BLOCK ************************************ * * JZ4740 mobile_tv Project V1.0.0 * INGENIC CONFIDENTIAL--NOT FOR DISTRIBUTION IN SOURCE CODE FORM * Copyright (c) Ingenic Semiconductor Co. Ltd 2005. All rights reserved. * * This file, and the files included with this file, is distributed and made * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * * http://www.ingenic.cn * ********************** END LICENSE BLOCK ************************************** * * Author: <dsqiu@ingenic.cn> <jgao@ingenic.cn> * * Create: 2008-06-26, by dsqiu * * Maintain: 2008-06-26, by jgao * * ******************************************************************************* */#include <bsp.h>#include <jz4740.h>#include <mipsregs.h>#include <os_api.h>//--------------------------------------------------------------------typedef struct __tag_pll_opt{ unsigned int cpuclock; // cpu clock int cdiv; // cpu spec cdiv int mdiv; // mem div}PLL_OPT,*PPLL_OPT;//--------------------------------------------------------------------int sdram_convert(unsigned int mclock,unsigned int *sdram_freq);static void pll_convert(PPLL_OPT pllopt,unsigned int *pll_cfcr,unsigned int *pll_plcr1);static int save_reg[5];void config_source_savepower(void){ int dwRegData; //Set AMPEN_N output low __gpio_port_as_output(2,27); __gpio_clear_pin(91); // Stop SADC REG_SADC_ENA &= ~0x7; // Suspend UHC, OSC and UDC in Sleep Mode. dwRegData = REG_CPM_SCR; dwRegData |= 1<<7; dwRegData &= ~((1<<6)| (1<<4)); REG_CPM_SCR = dwRegData; // Suspend Codec// REG_ICDC_CDCCR1 = 0x001b2302;// udelay(1000);// REG_ICDC_CDCCR1 = 0x001b2102; // Stop LCD REG_LCD_STATE |= LCD_STATE_QD; // Disable nand flash REG_EMC_NFCSR &= ~0xff;}void save_internal_regs(void){// save_reg[0] = REG_ICDC_CDCCR1; save_reg[0] = REG_SADC_ENA; save_reg[1] = REG_EMC_NFCSR; save_reg[2] = REG_LCD_STATE; save_reg[3] = REG_CPM_SCR;}void restore_internal_regs(void){// REG_ICDC_CDCCR1 = save_reg[0]; REG_SADC_ENA = save_reg[0]; REG_EMC_NFCSR = save_reg[1]; REG_LCD_STATE = save_reg[2]; REG_CPM_SCR = save_reg[3];}static int jz_pm_do_hibernate(void){ printf("Put CPU into hibernate mode.\n"); serial_waitfinish(); __rtc_clear_alarm_flag(); __rtc_clear_hib_stat_all(); // __rtc_set_scratch_pattern(0x12345678); __rtc_enable_alarm_wakeup(); __rtc_set_hrcr_val(0xfe0); __rtc_set_hwfcr_val((0xFFFF << 4)); __rtc_power_down(); while(1); return 0;}static int jz_pm_do_sleep(void){// unsigned long imr = REG_INTC_IMR; /* Preserve current time */ /* Mask all interrupts */// REG_INTC_IMSR = 0xffffffff; /* Just allow next interrupts to wakeup the system. * Note: modify this according to your system. */ save_internal_regs(); config_source_savepower(); /* Enter SLEEP mode */ REG_CPM_LCR &= ~CPM_LCR_LPM_MASK; REG_CPM_LCR |= CPM_LCR_LPM_SLEEP; //REG_CPM_LCR &= ~CPM_LCR_LPM_MASK; //REG_CPM_LCR |= CPM_LCR_LPM_IDLE; __asm__(".set\tmips3\n\t" "sync\n\t" "wait\n\t" "nop\n\t" ".set\tmips0"); restore_internal_regs(); /* Restore to IDLE mode */ REG_CPM_LCR &= ~CPM_LCR_LPM_MASK; REG_CPM_LCR |= CPM_LCR_LPM_IDLE; /* Restore interrupts */// REG_INTC_IMR = imr; /* Restore current time */ return 0;}static int jz_pm_do_pllconvert(PPLL_OPT pllopt){ unsigned int cfcr, pllout,sdram_freq; unsigned int pll_cfcr,pll_plcr1; unsigned int t; unsigned int dmcr; #if 0 int div_preq[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; if(pllin < 25000000 || pllin > 420000000) { printf("pll should > 25000000 and < 420000000 ! \n"); return -1; }#endif pll_convert(pllopt,&pll_cfcr,&pll_plcr1); dmcr = sdram_convert(pllopt->cpuclock / pllopt->mdiv,&sdram_freq); unsigned int olddmcr = REG_EMC_DMCR; olddmcr &= 0xffff0000; olddmcr |= dmcr; t = read_c0_status(); write_c0_status(t & (~1));#if (DM==1) dm_pre_convert();#endif REG_CPM_CPCCR &= ~CPM_CPCCR_CE; REG_CPM_CPCCR = pll_cfcr; REG_EMC_RTCOR = sdram_freq; REG_EMC_RTCNT = 0; REG_CPM_CPCCR |= CPM_CPCCR_CE; //udelay(1000); //udelay(1000); //REG_EMC_DMCR = olddmcr | EMC_DMCR_RFSH | EMC_DMCR_MRSET; write_c0_status(t);#if (DM==1) dm_all_convert();#endif pllout = (__cpm_get_pllm() + 2)* EXTAL_CLK / (__cpm_get_plln() + 2); printf("pll out new: %dMHZ 0x%08x 0x%08x \n",pllout/1000000,pll_cfcr,REG_CPM_CPCCR); return 0;}static void pll_bypass(void){ unsigned int freq; /* sdram convert */ sdram_convert(12000000,&freq); REG_EMC_RTCOR = freq; REG_EMC_RTCNT = freq; REG_CPM_CPPCR |= CPM_CPPCR_PLLBP; REG_CPM_CPCCR = ((REG_CPM_CPCCR & (~0xffff)) | CPM_CPCCR_CE); REG_CPM_CPCCR &= ~CPM_CPCCR_CE;}int sdram_convert(unsigned int mclock,unsigned int *sdram_freq){ register unsigned int ns, dmcr = 0,tmp; printf("mclock = %d\n",mclock); ns = 1000000000 / mclock; printf("ns = %d\n",ns); tmp = SDRAM_TRAS/ns; if (tmp < 4) tmp = 4; if (tmp > 11) tmp = 11; dmcr |= ((tmp-4) << EMC_DMCR_TRAS_BIT); tmp = SDRAM_RCD/ns; if (tmp > 3) tmp = 3; dmcr |= (tmp << EMC_DMCR_RCD_BIT); tmp = SDRAM_TPC/ns; if (tmp > 7) tmp = 7; dmcr |= (tmp << EMC_DMCR_TPC_BIT); tmp = SDRAM_TRWL/ns; if (tmp > 3) tmp = 3; dmcr |= (tmp << EMC_DMCR_TRWL_BIT); tmp = (SDRAM_TRAS + SDRAM_TPC)/ns; if (tmp > 14) tmp = 14; dmcr |= (((tmp + 1) >> 1) << EMC_DMCR_TRC_BIT); /* Set refresh registers */ tmp = SDRAM_TREF/ns; tmp = tmp/64 + 1; if (tmp > 0xff) tmp = 0xff; *sdram_freq = tmp; //REG_EMC_RTCOR = tmp; //REG_EMC_RTCNT = tmp; return dmcr;}int div_preq[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};static int find_cpudiv(int div){ int i; for(i = 0;i < sizeof(div_preq)/sizeof(div_preq[0]);i++) if(div == div_preq[i]) return i; return -1;}static void pll_convert(PPLL_OPT pllopt,unsigned int *pll_cfcr,unsigned int *pll_plcr1){ unsigned int cfcr, plcr1; printf("cpuspeed memspeed: (%dM :%dM)\n",pllopt->cpuclock / pllopt->cdiv / 1000 / 1000,pllopt->cpuclock / pllopt->mdiv / 1000 / 1000); int cdiv = find_cpudiv(pllopt->cdiv); #if (RELEASE==0) if(cdiv == -1) { printf("error: init pll cdiv!"); return; } #endif int mdiv = find_cpudiv(pllopt->mdiv); #if (RELEASE==0) if(mdiv == -1) { printf("error: init pll mdiv!"); return; } #endif cfcr = REG_CPM_CPCCR; cfcr &= ~(0xffff); cfcr |= CPM_CPCCR_CLKOEN | (cdiv << CPM_CPCCR_CDIV_BIT) | (mdiv << CPM_CPCCR_HDIV_BIT) | (mdiv << CPM_CPCCR_PDIV_BIT) | (mdiv << CPM_CPCCR_MDIV_BIT) ;// |(2 << CPM_CPCCR_LDIV_BIT); /* init PLL */ *pll_cfcr= cfcr;}static void set_pll(unsigned int div,unsigned int pll){ u32 prog_entry = ((u32)set_pll / 32 - 1) * 32 ; u32 prog_size = 1024; u32 i; for( i = (prog_entry);i < prog_entry + prog_size; i += 32) __asm__ __volatile__( "cache 0x1c, 0x00(%0)\n\t" : : "r" (i)); REG_CPM_CPCCR = div;// REG_CPM_CPCCR |= CPM_CPCCR_CE; REG_CPM_CPPCR = pll; while (!(REG_CPM_CPPCR & CPM_CPPCR_PLLS));}/* convert pll while program is running */int jz_pm_pllconvert(PPLL_OPT pllin){ return jz_pm_do_pllconvert(pllin);}/* Put CPU to IDLE mode */void jz_pm_idle(void){ __asm__( ".set\tmips3\n\t" "sync\n\t" "wait\n\t" "nop\n\t" "nop\n\t" ".set\tmips0" ); //cpu_wait();}// cpu speed = cpu clock / cdiv// mem speed = cpu clock / mdiv// cpu clock cdiv mdiv static PLL_OPT opt_pll[3] = { {CFG_CPU_SPEED, 4, 4}, {CFG_CPU_SPEED, 2, 4}, {CFG_CPU_SPEED, 1, 3} };static int curLevel = 0;void pm_init(){#if (DM==1) printf("Driver Manager \r\n"); jz_dm_init();#endif}/* level: 0,1,2,3,-1; -1 is GetLevel;*/int jz_pm_control(int level){ printf("+jz_pm_control\r\n"); if(level != -1) { if(curLevel != level) { curLevel = level; if(level<0 || level >3) return -1; if(level==3) { return jz_pm_sleep(); } else { return jz_pm_pllconvert(&opt_pll[level]);//[level].cpuclock,opt_pll[level].div); } } }else return curLevel; return 0;}//--------------------------------------------------------------------typedef struct __tag_wake_type__{ void (*WakeUp)(); void (*PreWakeUp)(); unsigned int id; }WakeUpType;#define MAX_WakeUp_SOURCE 5static WakeUpType WakeUpsource[MAX_WakeUp_SOURCE] = {0};static unsigned char wcount = 0; void PM_AddWakeUp(int id,void* preWakeUp,void* WakeUp){ if(wcount < MAX_WakeUp_SOURCE) { WakeUpsource[wcount].id = id; WakeUpsource[wcount].PreWakeUp = preWakeUp; WakeUpsource[wcount].WakeUp = WakeUp; wcount++; }}static void PM_SetWakeUp(){ int i; for(i = 0;i < wcount;i++) { if(WakeUpsource[i].PreWakeUp) { printf("%s->%x\n",__FUNCTION__,WakeUpsource[i].id); WakeUpsource[i].PreWakeUp(); } }}static void PM_WakeUp(){ int i; for(i = 0;i < wcount;i++) { if(WakeUpsource[i].WakeUp) { printf("%s->%x\n",__FUNCTION__,WakeUpsource[i].id); WakeUpsource[i].WakeUp(); } }}//--------------------------------------------------------------------/* Put CPU to SLEEP mode */int jz_pm_sleep(void){ PM_SetWakeUp(); jz_pm_do_sleep(); PM_WakeUp(); return 1;}//--------------------------------------------------------------------typedef struct __tag_power_type__{ void (*pPowerDown)(); void (*pPowerUp)(); unsigned int id; }PowerType;#define MAX_Power_SOURCE 10static PowerType PowerSource[MAX_Power_SOURCE] = {0};static unsigned char w_powercount = 0;void PM_AddPowerCtrl(int id,void* ppowerdown,void* ppowerup){ if(w_powercount < MAX_Power_SOURCE) { PowerSource[w_powercount].id = id; PowerSource[w_powercount].pPowerDown = ppowerdown; PowerSource[w_powercount].pPowerUp = ppowerup; w_powercount++; }}static void PM_PowerDown(){ int i; for(i = 0;i < w_powercount;i++) { if(PowerSource[i].pPowerDown) { printf("%s->%x\n",__FUNCTION__,PowerSource[i].id); PowerSource[i].pPowerDown(); } }}static void PM_PowerUp(){ int i; for(i = 0;i < w_powercount;i++) { if(PowerSource[i].pPowerUp) { printf("%s->%x\n",__FUNCTION__,PowerSource[i].id); PowerSource[i].pPowerUp(); } }}/* Put CPU to HIBERNATE mode */int jz_pm_hibernate(void){ PM_PowerDown(); return jz_pm_do_hibernate();}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -