mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 11:50:43 +09:00
RK3168 DDR:support DDR change frequency for RK3168
This commit is contained in:
2
arch/arm/mach-rk30/clock_data-rk3066b.c
Normal file → Executable file
2
arch/arm/mach-rk30/clock_data-rk3066b.c
Normal file → Executable 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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
41
arch/arm/plat-rk/ddr_freq.c
Normal file → Executable 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
4
arch/arm/plat-rk/include/plat/ddr.h
Normal file → Executable 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
|
||||
|
||||
Reference in New Issue
Block a user