RK3168 DDR:support DDR change frequency for RK3168

This commit is contained in:
cym 2013-03-07 10:56:17 +08:00
parent 59772d964b
commit ee23f025c5
5 changed files with 178 additions and 11 deletions

2
arch/arm/mach-rk30/clock_data-rk3066b.c Normal file → Executable file
View File

@ -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)
{

View File

@ -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();
n=temp[1024*i];
barrier();
}
#endif
#if defined(CONFIG_ARCH_RK3188)
for(i=0;i<8;i++) //32KB
{
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;

View File

@ -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)
{

41
arch/arm/plat-rk/ddr_freq.c Normal file → Executable file
View File

@ -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);

4
arch/arm/plat-rk/include/plat/ddr.h Normal file → Executable file
View File

@ -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