From ee23f025c5dd336025a80e636a1273ea7e86bac3 Mon Sep 17 00:00:00 2001 From: cym Date: Thu, 7 Mar 2013 10:56:17 +0800 Subject: [PATCH] RK3168 DDR:support DDR change frequency for RK3168 --- arch/arm/mach-rk30/clock_data-rk3066b.c | 2 +- arch/arm/mach-rk30/ddr.c | 140 ++++++++++++++++++++++-- arch/arm/mach-rk3188/clock_data.c | 2 +- arch/arm/plat-rk/ddr_freq.c | 41 +++++++ arch/arm/plat-rk/include/plat/ddr.h | 4 + 5 files changed, 178 insertions(+), 11 deletions(-) mode change 100644 => 100755 arch/arm/mach-rk30/clock_data-rk3066b.c mode change 100644 => 100755 arch/arm/plat-rk/ddr_freq.c mode change 100644 => 100755 arch/arm/plat-rk/include/plat/ddr.h diff --git a/arch/arm/mach-rk30/clock_data-rk3066b.c b/arch/arm/mach-rk30/clock_data-rk3066b.c old mode 100644 new mode 100755 index d7b6ce57e261..3c92e19df8ce --- a/arch/arm/mach-rk30/clock_data-rk3066b.c +++ b/arch/arm/mach-rk30/clock_data-rk3066b.c @@ -1119,7 +1119,7 @@ static int ddr_clk_set_rate(struct clk *c, unsigned long rate) static long ddr_clk_round_rate(struct clk *clk, unsigned long rate) { - return ddr_set_pll(rate / MHZ, 0) * MHZ; + return ddr_set_pll_rk3066b(rate / MHZ, 0) * MHZ; } static unsigned long ddr_clk_recalc_rate(struct clk *clk) { diff --git a/arch/arm/mach-rk30/ddr.c b/arch/arm/mach-rk30/ddr.c index 5284b006f118..4a24aa1612ec 100755 --- a/arch/arm/mach-rk30/ddr.c +++ b/arch/arm/mach-rk30/ddr.c @@ -1534,7 +1534,7 @@ NR NO NF Fout freq Step fin 1 2 46 - 91 550MHz - 1100MHz 12MHz 550MHz<= 1100MHz 1 1 46 - 91 1100MHz - 2200MHz 24MHz 1100MHz<= 2200MHz ******************************************/ -uint32_t __sramlocalfunc ddr_set_pll_rk3600b(uint32_t nMHz, uint32_t set) +uint32_t __sramlocalfunc ddr_set_pll_rk3066b(uint32_t nMHz, uint32_t set) { uint32_t ret = 0; int delay = 1000; @@ -3230,6 +3230,94 @@ void __sramlocalfunc ddr_selfrefresh_exit(void) } } +#if defined(CONFIG_ARCH_RK3066B) +static __sramdata uint32_t data8_dqstr[25][4]; +static __sramdata uint32_t min_ddr_freq,dqstr_flag=false; + +int ddr_get_datatraing_value_3168(bool end_flag,uint32_t dqstr_value,uint32_t min_freq) +{ + if(end_flag == true) + { + dqstr_flag = true; //complete learn data training value flag + min_ddr_freq = min_freq; + return 0; + } + + data8_dqstr[dqstr_value][0]=pPHY_Reg->DATX8[0].DXDQSTR; + data8_dqstr[dqstr_value][1]=pPHY_Reg->DATX8[0].DXDQSTR; + data8_dqstr[dqstr_value][2]=pPHY_Reg->DATX8[0].DXDQSTR; + data8_dqstr[dqstr_value][3]=pPHY_Reg->DATX8[0].DXDQSTR; + + ddr_print("training %luMhz[%d]:0x%x-0x%x-0x%x-0x%x\n", + clk_get_rate(clk_get(NULL, "ddr_pll"))/1000000,dqstr_value,data8_dqstr[dqstr_value][0],data8_dqstr[dqstr_value][1], + data8_dqstr[dqstr_value][2],data8_dqstr[dqstr_value][3]); + return 0; +} +EXPORT_SYMBOL(ddr_get_datatraing_value_3168); + +void __sramlocalfunc ddr_set_pll_enter_3168(uint32_t freq_slew) +{ + uint32_t value_1u,value_100n; + ddr_move_to_Config_state(); + + if(freq_slew == 1) + { + value_100n = ddr_reg.pctl.pctl_timing.togcnt100n; + value_1u = ddr_reg.pctl.pctl_timing.togcnt1u; + ddr_reg.pctl.pctl_timing.togcnt1u = pDDR_Reg->TOGCNT1U; + ddr_reg.pctl.pctl_timing.togcnt100n = pDDR_Reg->TOGCNT100N; + ddr_update_timing(); + ddr_update_mr(); + ddr_reg.pctl.pctl_timing.togcnt100n = value_100n; + ddr_reg.pctl.pctl_timing.togcnt1u = value_1u; + } + else + { + pDDR_Reg->TOGCNT100N = ddr_reg.pctl.pctl_timing.togcnt100n; + pDDR_Reg->TOGCNT1U = ddr_reg.pctl.pctl_timing.togcnt1u; + } + + pDDR_Reg->TZQCSI = 0; + ddr_move_to_Lowpower_state(); + + ddr_set_dll_bypass(0); //dll bypass + pCRU_Reg->CRU_CLKGATE_CON[0] = ((0x1<<2)<<16) | (1<<2); //disable DDR PHY clock + dsb(); +} + +void __sramlocalfunc ddr_set_pll_exit_3168(uint32 freq_slew,uint32_t dqstr_value) +{ + pCRU_Reg->CRU_CLKGATE_CON[0] = ((0x1<<2)<<16) | (0<<2); //enable DDR PHY clock + dsb(); + ddr_set_dll_bypass(ddr_freq); + ddr_reset_dll(); + + if(dqstr_flag==true) + { + pPHY_Reg->DATX8[0].DXDQSTR=data8_dqstr[dqstr_value][0]; + pPHY_Reg->DATX8[1].DXDQSTR=data8_dqstr[dqstr_value][1]; + pPHY_Reg->DATX8[2].DXDQSTR=data8_dqstr[dqstr_value][2]; + pPHY_Reg->DATX8[3].DXDQSTR=data8_dqstr[dqstr_value][3]; + } + + ddr_update_odt(); + ddr_move_to_Config_state(); + if(freq_slew == 1) + { + pDDR_Reg->TOGCNT100N = ddr_reg.pctl.pctl_timing.togcnt100n; + pDDR_Reg->TOGCNT1U = ddr_reg.pctl.pctl_timing.togcnt1u; + pDDR_Reg->TZQCSI = ddr_reg.pctl.pctl_timing.tzqcsi; + } + else + { + ddr_update_timing(); + ddr_update_mr(); + } + ddr_data_training(); + ddr_move_to_Access_state(); +} +#endif + uint32_t __sramfunc ddr_change_freq(uint32_t nMHz) { uint32_t ret; @@ -3241,6 +3329,15 @@ uint32_t __sramfunc ddr_change_freq(uint32_t nMHz) uint32_t regvalue = pCRU_Reg->CRU_PLL_CON[0][0]; uint32_t freq; +#if defined(CONFIG_ARCH_RK3066B) + uint32_t freq_slew=0,dqstr_value=0; + if(dqstr_flag==true) + { + dqstr_value=(nMHz-min_ddr_freq+1)/50; + freq_slew = (nMHz>ddr_freq)? 1 : 0; + } +#endif + // freq = (Fin/NR)*NF/OD if((pCRU_Reg->CRU_MODE_CON&3) == 1) // CPLL Normal mode freq = 24 *((pCRU_Reg->CRU_PLL_CON[0][1]&0xffff)+1) // NF = 2*(CLKF+1) @@ -3252,10 +3349,11 @@ uint32_t __sramfunc ddr_change_freq(uint32_t nMHz) loops_per_us = LPJ_100MHZ*freq / 1000000; #if defined(CONFIG_ARCH_RK3066B) || defined(CONFIG_ARCH_RK3188) - ret=ddr_set_pll_rk3600b(nMHz,0); + ret=ddr_set_pll_rk3066b(nMHz,0); #else ret=ddr_set_pll(nMHz,0); #endif + ddr_get_parameter(ret); /** 1. Make sure there is no host access */ @@ -3266,11 +3364,29 @@ uint32_t __sramfunc ddr_change_freq(uint32_t nMHz) flush_tlb_all(); isb(); DDR_SAVE_SP(save_sp); - for(i=0;i<16;i++) + +#if defined(CONFIG_ARCH_RK3066B) + for(i=0;i<4;i++) //16KB + { + n=temp[1024*i]; + barrier(); + } +#endif +#if defined(CONFIG_ARCH_RK3188) + for(i=0;i<8;i++) //32KB { - n=temp[1024*i]; - barrier(); + n=temp[1024*i]; + barrier(); + } +#endif +#if defined(CONFIG_ARCH_RK30XX) + for(i=0;i<16;i++) //64KB + { + n=temp[1024*i]; + barrier(); } +#endif + n= pDDR_Reg->SCFG.d32; n= pPHY_Reg->RIDR; n= pCRU_Reg->CRU_PLL_CON[0][0]; @@ -3285,27 +3401,33 @@ uint32_t __sramfunc ddr_change_freq(uint32_t nMHz) /** 2. ddr enter self-refresh mode or precharge power-down mode */ idle_port(); +#if defined(CONFIG_ARCH_RK3066B) + ddr_set_pll_enter_3168(freq_slew); +#else ddr_selfrefresh_enter(ret); +#endif /** 3. change frequence */ #if defined(CONFIG_ARCH_RK3066B) || defined(CONFIG_ARCH_RK3188) - ddr_set_pll_rk3600b(ret,1); + ddr_set_pll_rk3066b(ret,1); #else ddr_set_pll(ret,1); #endif ddr_freq = ret; /** 5. Issues a Mode Exit command */ +#if defined(CONFIG_ARCH_RK3066B) + ddr_set_pll_exit_3168(freq_slew,dqstr_value); +#else ddr_selfrefresh_exit(); +#endif deidle_port(); - dsb(); DDR_RESTORE_SP(save_sp); local_fiq_enable(); local_irq_restore(flags); return ret; } - EXPORT_SYMBOL(ddr_change_freq); void ddr_set_auto_self_refresh(bool en) @@ -3480,7 +3602,7 @@ int ddr_init(uint32_t dram_speed_bin, uint32_t freq) uint32_t die=1; uint32_t gsr,dqstr; - ddr_print("version 1.00 20130130 \n"); + ddr_print("version 1.00 20130307 \n"); mem_type = pPHY_Reg->DCR.b.DDRMD; ddr_speed_bin = dram_speed_bin; diff --git a/arch/arm/mach-rk3188/clock_data.c b/arch/arm/mach-rk3188/clock_data.c index d56fbb96ff76..eeac5f89e0ff 100755 --- a/arch/arm/mach-rk3188/clock_data.c +++ b/arch/arm/mach-rk3188/clock_data.c @@ -1138,7 +1138,7 @@ static int ddr_clk_set_rate(struct clk *c, unsigned long rate) static long ddr_clk_round_rate(struct clk *clk, unsigned long rate) { CLKDATA_DBG("%s do nothing for ddr round rate\n", __func__); - return ddr_set_pll(rate / MHZ, 0) * MHZ; + return ddr_set_pll_rk3066b(rate / MHZ, 0) * MHZ; } static unsigned long ddr_clk_recalc_rate(struct clk *clk) { diff --git a/arch/arm/plat-rk/ddr_freq.c b/arch/arm/plat-rk/ddr_freq.c old mode 100644 new mode 100755 index db187db437ca..8e2af89442f8 --- a/arch/arm/plat-rk/ddr_freq.c +++ b/arch/arm/plat-rk/ddr_freq.c @@ -332,6 +332,43 @@ static int ddr_scale_rate_for_dvfs(struct clk *clk, unsigned long rate, dvfs_set return !(clk_get_rate(clk) == rate); } +#if defined(CONFIG_ARCH_RK3066B) +static int ddrfreq_scanfreq_datatraing_3168(void) +{ + struct cpufreq_frequency_table *table; + uint32_t dqstr_freq,dqstr_value; + uint32_t min_freq,max_freq; + int i; + table = dvfs_get_freq_volt_table(clk_get(NULL, "ddr")); + if (!table) + { + pr_err("failed to get ddr freq volt table\n"); + } + for (i = 0; table && table[i].frequency != CPUFREQ_TABLE_END; i++) + { + if(i == 0) + min_freq = table[i].frequency / 1000; + + max_freq = table[i].frequency / 1000; + } + + //get data training value for RK3066B ddr_change_freq + for(dqstr_freq=min_freq; dqstr_freq<=max_freq; dqstr_freq=dqstr_freq+50) + { + if (clk_set_rate(ddr.clk, dqstr_freq*MHZ) != 0) + { + pr_err("failed to clk_set_rate ddr.clk %dhz\n",dqstr_freq*MHZ); + } + dqstr_value=(dqstr_freq-min_freq+1)/50; + + ddr_get_datatraing_value_3168(false,dqstr_value,min_freq); + } + ddr_get_datatraing_value_3168(true,0,min_freq); + dprintk(DEBUG_DDR,"get datatraing from %dMhz to %dMhz\n",min_freq,max_freq); + return 0; +} +#endif + static int ddrfreq_init(void) { int i, ret; @@ -427,6 +464,10 @@ static int ddrfreq_late_init(void) register_early_suspend(&ddr.early_suspend); #endif +#if defined(CONFIG_ARCH_RK3066B) + ddrfreq_scanfreq_datatraing_3168(); +#endif + ddr.task = kthread_create(ddrfreq_task, NULL, "ddrfreqd"); if (IS_ERR(ddr.task)) { ret = PTR_ERR(ddr.task); diff --git a/arch/arm/plat-rk/include/plat/ddr.h b/arch/arm/plat-rk/include/plat/ddr.h old mode 100644 new mode 100755 index 89a6ac283665..c8187cb7bf48 --- a/arch/arm/plat-rk/include/plat/ddr.h +++ b/arch/arm/plat-rk/include/plat/ddr.h @@ -151,5 +151,9 @@ uint32_t ddr_get_cap(void); int ddr_init(uint32_t dram_type, uint32_t freq); void ddr_set_auto_self_refresh(bool en); uint32_t __sramlocalfunc ddr_set_pll(uint32_t nMHz, uint32_t set); +uint32_t __sramlocalfunc ddr_set_pll_rk3066b(uint32_t nMHz, uint32_t set); +#if defined(CONFIG_ARCH_RK3066B) +int ddr_get_datatraing_value_3168(bool end_flag,uint32_t dqstr_value,uint32_t min_freq); +#endif #endif -- 2.34.1