summaryrefslogtreecommitdiff
path: root/drivers/platform/sprd/dmc_freq_28nm.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/platform/sprd/dmc_freq_28nm.c')
-rw-r--r--drivers/platform/sprd/dmc_freq_28nm.c657
1 files changed, 657 insertions, 0 deletions
diff --git a/drivers/platform/sprd/dmc_freq_28nm.c b/drivers/platform/sprd/dmc_freq_28nm.c
new file mode 100644
index 00000000..3b26dc24
--- /dev/null
+++ b/drivers/platform/sprd/dmc_freq_28nm.c
@@ -0,0 +1,657 @@
+
+#ifdef CONFIG_ARCH_SCX30G
+#include <linux/init.h>
+#include <linux/suspend.h>
+#include <linux/kobject.h>
+#include <linux/fs.h>
+#include <linux/io.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/io.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/wakelock.h>
+#include <linux/module.h>
+#include <linux/kthread.h>
+#include <soc/sprd/common.h>
+#include <soc/sprd/hardware.h>
+#include <soc/sprd/sci.h>
+#include <linux/earlysuspend.h>
+#include <soc/sprd/sci_glb_regs.h>
+#include <linux/random.h>
+#include <asm/hardware/cache-l2x0.h>
+#include <asm/cacheflush.h>
+#include <asm/suspend.h>
+#include <linux/vmalloc.h>
+#include <linux/printk.h>
+#include <soc/sprd/__sc8830_dmc_dfs.h>
+#include "soc/sprd/chip_x30g/dram_phy_28nm.h"
+
+static volatile u32 mutex_flg = 0;
+
+/* other PLL clock srv, t-shark is used 384 for tdpll */
+#define PLAT_CLK 384
+
+#define DDR_TIMING_REG_VAL_ADDR (SPRD_IRAM0H_BASE + 0xc0c)
+#define DDR_TIMING_CALC_VAL_ADDR (SPRD_IRAM0H_BASE + 0xF80)
+//#define UMCTL_REG_BASE (0x30000000)
+//#define PUBL_REG_BASE (0x30010000)
+
+//SPRD_LPDDR2_BASE
+//SPRD_LPDDR2_PHY_BASE
+
+#define NINT(FREQ,REFIN) (FREQ/REFIN)
+#define KINT(FREQ,REFIN) ((FREQ-(FREQ/REFIN)*REFIN)*1048576/REFIN)
+
+#define REG32(x) (*((volatile u32 *)(x)))
+
+#ifdef CONFIG_SCX35_DMC_FREQ_AP
+static void emc_dfs_code_copy(u8 * dest);
+static int emc_dfs_call(unsigned long flag);
+void emc_dfs_main(unsigned long flag);
+#endif
+#ifdef EMC_FREQ_AUTO_TEST
+extern void __emc_freq_test(void);
+
+//static u32 get_sys_cnt(void)
+//{
+// return __raw_readl(SPRD_GPTIMER_BASE + 0x44);
+//}
+#endif
+static u32 dpll_clk_get(void)
+{
+ u32 clk = 0;
+ u32 nint, kint, refin, pnt = 0 ;
+ u32 reg, div_s, sdm_en, n;
+
+ reg = sci_glb_read(REG_AON_APB_DPLL_CFG1, -1);
+ kint = ((reg >> 12) & 0xFFFFF);
+ nint = (reg & 0x3F);
+ div_s = (reg >> 10) & 0x01;
+ sdm_en = (reg >> 6) & 0x01;
+
+ reg = sci_glb_read(REG_AON_APB_DPLL_CFG, -1);
+ n = reg & 0x3F;
+ if((reg & 0x03000000) == 0x00000000) {
+ refin = 2;
+ }
+ if((reg & 0x03000000) == 0x01000000) {
+ refin = 4;
+ }
+ if((reg & 0x03000000) == 0x02000000) {
+ refin = 13;
+ }
+ if((reg & 0x03000000) == 0x03000000) {
+ refin = 26;
+ }
+
+ if ((div_s != 0) && (sdm_en != 0)) {
+ if (((kint * refin ) & 0xFFFFF) >= 0x80000) {
+ pnt = 1;
+ }
+ else {
+ pnt = 0;
+ }
+ kint = ((kint * refin) >> 20) + pnt;
+ clk = nint * refin + kint;
+ }
+ else if ((div_s != 0) && (sdm_en == 0)) {
+ clk = nint * refin;
+ }
+ else/* if (div_s == 0) */ {
+ clk = refin * n;
+ }
+
+ return clk;
+}
+
+u32 emc_clk_get(void)
+{
+ u32 pll_clk;
+ u32 div;
+ u32 reg_val;
+ u32 sel;
+ u32 clk;
+ reg_val = sci_glb_read(REG_AON_CLK_EMC_CFG, -1);
+ sel = reg_val & 0x3;
+ div = (reg_val >> 8) & 0x3;
+ switch(sel) {
+ case 0:
+ pll_clk = 26;
+ break;
+ case 1:
+ pll_clk = 624;
+ break;
+ case 2:
+ pll_clk = 768;
+ break;
+ case 3:
+ pll_clk = dpll_clk_get();
+ break;
+ default:
+ break;
+ }
+
+ clk = (pll_clk / (div + 1)) >> 1;
+ return clk;
+}
+EXPORT_SYMBOL(emc_clk_get);
+
+static void dpll_clk_set(u32 clk)
+{
+ volatile u32 reg = 0;
+ u32 refin = 0;
+
+ if(dpll_clk_get() == clk) {
+ return;
+ }
+
+ /* get refin value */
+ refin = 26;
+
+ /* set kint, nint */
+ reg = sci_glb_read(REG_AON_APB_DPLL_CFG1, -1);
+ reg |= 1 << 10; /* set fractional divider */
+ reg &=~(0xfffff<<12 | 0x3f);
+ reg |= (KINT(clk, refin) & 0xfffff) << 12;
+ reg |= (NINT(clk, refin)) & 0x3f;
+
+ if (0 == (reg & 0xfffff000)) {
+ reg &= ~(1<<6); /* sdm_en disable */
+ } else {
+ reg |= 1<<6; /* sdm_en */
+ }
+
+ sci_glb_write(REG_AON_APB_DPLL_CFG1, reg, -1);
+
+ /* Set REFIN */
+ reg = sci_glb_read(REG_AON_APB_DPLL_CFG,-1);
+ reg &= ~(BITS_DPLL_REFIN(0x03));
+ if (refin == 26) {
+ reg |= BITS_DPLL_REFIN(0x03);
+ }
+ else if (refin == 13){
+ reg |= BITS_DPLL_REFIN(0x02);
+ }
+/*
+ else if (refin = 4){
+ reg |= BITS_DPLL_REFIN(0x02);
+ }
+ else if (refin = 2){
+ }
+*/
+ sci_glb_write(REG_AON_APB_DPLL_CFG, reg, -1);
+
+ udelay(100);
+}
+
+static u32 calc_tprd(u32 reg_addr, u32 new_clk, u32 cur_clk, u32 init_val)
+{
+ u32 tprd, reg;
+
+ reg = sci_glb_read(reg_addr ,-1);
+ tprd = (reg >> 8) & 0xFF;
+ tprd = tprd * cur_clk / new_clk;
+
+ reg = (init_val & (~0xFF00));
+ reg |= ((tprd & 0xFF) << 8 );
+
+ return reg;
+}
+
+static void emc_calc_phy_param(u32 new_clk)
+{
+ ddr_dfs_v2_t *init = (ddr_dfs_v2_t *)DDR_TIMING_REG_VAL_ADDR;
+ publ_calc_t *calc = (publ_calc_t *)DDR_TIMING_CALC_VAL_ADDR;
+ u32 cur_clk, i;
+ u32 cur_tprd, init_tprd;
+ u32 acd, r0wld, r1wld, wdqd, rdqsd, rdqsnd, r0dqsgd, r1dqsgd;
+
+ for (i = 0; i < 5; i++) {
+ if (init->ddr_clk == new_clk) {
+ break;
+ }
+ init++;
+ }
+ if (i == 5) {
+ return ;
+ }
+
+ cur_clk = emc_clk_get();
+ /* get register acmdlr.tprd [15:8]*/
+ calc->publ_acmdlr = calc_tprd((SPRD_LPDDR2_PHY_BASE +0x38),
+ new_clk, cur_clk, init->publ_acmdlr);
+ /* get register dx0mdlr.tprd [15:8]*/
+ calc->publ_dx0mdlr = calc_tprd((SPRD_LPDDR2_PHY_BASE +0x2C4),
+ new_clk, cur_clk, init->publ_dx0mdlr);
+ /* get register dx1mdlr.tprd [15:8]*/
+ calc->publ_dx1mdlr = calc_tprd((SPRD_LPDDR2_PHY_BASE +0x344),
+ new_clk, cur_clk, init->publ_dx1mdlr);
+ /* get register dx2mdlr.tprd [15:8]*/
+ calc->publ_dx2mdlr = calc_tprd((SPRD_LPDDR2_PHY_BASE +0x3C4),
+ new_clk, cur_clk, init->publ_dx2mdlr);
+ /* get register dx3mdlr.tprd [15:8]*/
+ calc->publ_dx3mdlr = calc_tprd((SPRD_LPDDR2_PHY_BASE +0x444),
+ new_clk, cur_clk, init->publ_dx3mdlr);
+
+ /* get alcdlr.acd [7:0] */
+ cur_tprd = (calc->publ_acmdlr >> 8 ) & 0xFF;
+ init_tprd = (init->publ_acmdlr >> 8) & 0xFF;
+ if (init_tprd == 0) {
+ printk("[emc_calc_phy_param] publ_acmdlr.init_tprd is 0x%d, error!\n\r", init_tprd);
+ return;
+ }
+ acd = (init->publ_aclcdlr & 0xFF) * cur_tprd / init_tprd;
+ calc->publ_aclcdlr = (init->publ_aclcdlr & (~0xFF)) | (acd & 0xFF);
+
+ /* DX0LCDLR0~3 */
+ cur_tprd = (calc->publ_dx0mdlr >> 8 ) & 0xFF;
+ init_tprd = (init->publ_dx0mdlr >> 8) & 0xFF;
+ if (init_tprd == 0) {
+ printk("[emc_calc_phy_param] publ_dx0mdlr.init_tprd is 0x%d, error!\n\r", init_tprd);
+ return;
+ }
+ r0wld = ((init->publ_dx0lcdlr0 & 0xFF) * cur_tprd / init_tprd) & 0xFF;
+ r1wld = (((init->publ_dx0lcdlr0 >> 8) & 0xFF) * cur_tprd / init_tprd) & 0xFF;
+ calc->publ_dx0lcdlr0 = (init->publ_dx0lcdlr0 & (~0xFFFF)) | (r1wld << 8) | r0wld;
+
+ wdqd = ((init->publ_dx0lcdlr1 & 0xFF) * cur_tprd / init_tprd) & 0xFF;
+ rdqsd = (((init->publ_dx0lcdlr1 >> 8) & 0xFF) * cur_tprd / init_tprd) & 0xFF;
+ rdqsnd = (((init->publ_dx0lcdlr1 >> 16) & 0xFF) * cur_tprd / init_tprd) & 0xFF;
+ calc->publ_dx0lcdlr1 = (rdqsnd << 16) | (rdqsd << 8) | wdqd;
+
+ r0dqsgd = ((init->publ_dx0lcdlr2 & 0xFF) * cur_tprd / init_tprd) & 0xFF;
+ r1dqsgd = (((init->publ_dx0lcdlr2 >> 8) & 0xFF) * cur_tprd / init_tprd) & 0xFF;
+ calc->publ_dx0lcdlr2 = (init->publ_dx0lcdlr2 & (~0xFFFF)) | (r1dqsgd << 8) | r0dqsgd;
+
+ /* DX1LCDLR0~3 */
+ cur_tprd = (calc->publ_dx1mdlr >> 8 ) & 0xFF;
+ init_tprd = (init->publ_dx1mdlr >> 8) & 0xFF;
+ if (init_tprd == 0) {
+ printk("[emc_calc_phy_param] publ_dx1mdlr.init_tprd is 0x%d, error!\n\r", init_tprd);
+ return;
+ }
+ r0wld = ((init->publ_dx1lcdlr0 & 0xFF) * cur_tprd / init_tprd) & 0xFF;
+ r1wld = (((init->publ_dx1lcdlr0 >> 8) & 0xFF) * cur_tprd / init_tprd) & 0xFF;
+ calc->publ_dx1lcdlr0 = (init->publ_dx1lcdlr0 & (~0xFFFF)) | (r1wld << 8) | r0wld;
+
+ wdqd = ((init->publ_dx1lcdlr1 & 0xFF) * cur_tprd / init_tprd) & 0xFF;
+ rdqsd = (((init->publ_dx1lcdlr1 >> 8) & 0xFF) * cur_tprd / init_tprd) & 0xFF;
+ rdqsnd = (((init->publ_dx1lcdlr1 >> 16) & 0xFF) * cur_tprd / init_tprd) & 0xFF;
+ calc->publ_dx1lcdlr1 = (rdqsnd << 16) | (rdqsd << 8) | wdqd;
+
+ r0dqsgd = ((init->publ_dx1lcdlr2 & 0xFF) * cur_tprd / init_tprd) & 0xFF;
+ r1dqsgd = (((init->publ_dx1lcdlr2 >> 8) & 0xFF) * cur_tprd / init_tprd) & 0xFF;
+ calc->publ_dx1lcdlr2 = (init->publ_dx1lcdlr2 & (~0xFFFF)) | (r1dqsgd << 8) | r0dqsgd;
+
+ /* DX2LCDLR0~3 */
+ cur_tprd = (calc->publ_dx2mdlr >> 8 ) & 0xFF;
+ init_tprd = (init->publ_dx2mdlr >> 8) & 0xFF;
+ if (init_tprd == 0) {
+ printk("[emc_calc_phy_param] publ_dx2mdlr.init_tprd is 0x%d, error!\n\r", init_tprd);
+ return;
+ }
+ r0wld = ((init->publ_dx2lcdlr0 & 0xFF) * cur_tprd / init_tprd) & 0xFF;
+ r1wld = (((init->publ_dx2lcdlr0 >> 8) & 0xFF) * cur_tprd / init_tprd) & 0xFF;
+ calc->publ_dx2lcdlr0 = (init->publ_dx2lcdlr0 & (~0xFFFF)) | (r1wld << 8) | r0wld;
+
+ wdqd = ((init->publ_dx2lcdlr1 & 0xFF) * cur_tprd / init_tprd) & 0xFF;
+ rdqsd = (((init->publ_dx2lcdlr1 >> 8) & 0xFF) * cur_tprd / init_tprd) & 0xFF;
+ rdqsnd = (((init->publ_dx2lcdlr1 >> 16) & 0xFF) * cur_tprd / init_tprd) & 0xFF;
+ calc->publ_dx2lcdlr1 = (rdqsnd << 16) | (rdqsd << 8) | wdqd;
+
+ r0dqsgd = ((init->publ_dx2lcdlr2 & 0xFF) * cur_tprd / init_tprd) & 0xFF;
+ r1dqsgd = (((init->publ_dx2lcdlr2 >> 8) & 0xFF) * cur_tprd / init_tprd) & 0xFF;
+ calc->publ_dx2lcdlr2 = (init->publ_dx2lcdlr2 & (~0xFFFF)) | (r1dqsgd << 8) | r0dqsgd;
+
+ /* DX3LCDLR0~3 */
+ cur_tprd = (calc->publ_dx3mdlr >> 8 ) & 0xFF;
+ init_tprd = (init->publ_dx3mdlr >> 8) & 0xFF;
+ if (init_tprd == 0) {
+ printk("[emc_calc_phy_param] publ_dx3mdlr.init_tprd is 0x%d, error!\n\r", init_tprd);
+ return;
+ }
+ r0wld = ((init->publ_dx3lcdlr0 & 0xFF) * cur_tprd / init_tprd) & 0xFF;
+ r1wld = (((init->publ_dx3lcdlr0 >> 8) & 0xFF) * cur_tprd / init_tprd) & 0xFF;
+ calc->publ_dx3lcdlr0 = (init->publ_dx3lcdlr0 & (~0xFFFF)) | (r1wld << 8) | r0wld;
+
+ wdqd = ((init->publ_dx3lcdlr1 & 0xFF) * cur_tprd / init_tprd) & 0xFF;
+ rdqsd = (((init->publ_dx3lcdlr1 >> 8) & 0xFF) * cur_tprd / init_tprd) & 0xFF;
+ rdqsnd = (((init->publ_dx3lcdlr1 >> 16) & 0xFF) * cur_tprd / init_tprd) & 0xFF;
+ calc->publ_dx3lcdlr1 = (rdqsnd << 16) | (rdqsd << 8) | wdqd;
+
+ r0dqsgd = ((init->publ_dx3lcdlr2 & 0xFF) * cur_tprd / init_tprd) & 0xFF;
+ r1dqsgd = (((init->publ_dx3lcdlr2 >> 8) & 0xFF) * cur_tprd / init_tprd) & 0xFF;
+ calc->publ_dx3lcdlr2 = (init->publ_dx3lcdlr2 & (~0xFFFF)) | (r1dqsgd << 8) | r0dqsgd;
+
+ /* write new_clk in struct */
+ calc->ddr_clk = new_clk;
+}
+
+static u32 __emc_clk_set(u32 clk)
+{
+ u32 flag = 0;
+
+ /* check timing params */
+ flag = (clk << EMC_CLK_FREQ_OFFSET);
+
+ emc_calc_phy_param(clk);
+
+#ifdef CONFIG_SCX35_DMC_FREQ_AP
+ flush_cache_all();
+ cpu_suspend(flag, emc_dfs_call);
+#endif
+ if(emc_clk_get() != clk) {
+ printk("[__emc_clk_set] error, set clk = %d, get clk = %d\n\r", clk, emc_clk_get());
+ }
+ return 0;
+}
+
+static u32 get_dpll_from_clk (u32 new_clk)
+{
+ u32 dpll = 0;
+
+ switch (new_clk){
+ case 200:
+ case 400:
+ dpll = 800;
+ break;
+ case 384:
+ /* this clock from tdpll */
+ break;
+ case 466:
+ dpll = 932;
+ break;
+ case 533:
+ dpll = 1066;
+ break;
+ default :
+ break;
+ }
+
+ return dpll;
+}
+/* How To look PLL Setting
+ reg name val bit
+ MPLL_CFG reFin [25:24]
+ MPLL_CFG N [5:0]
+
+ MPLL_CFG1 div_s [10]
+ MPLL_CFG1 sdm_en [6]
+ MPLL_CFG1 Nint [5:0]
+ MPLL_CFG1 Kint [31:12]
+ div_s = 1 sdm_en = 1 Fout = Fin * ( Nint + Kint/1048576)
+ div_s = 1 sdm_en = 0 Fout = Fin * Nint
+ div_s = 0 sdm_en = x Fout = Fin * N */
+/* reg[0x402D0024] :*/
+/* [9:8] : clk_emc_div(clk_div= clk_src/(div+1)) */
+/* [1:0] : clk_emc_sel (0:pub 26m, 1: CPLL, 2:TDPLL, 3:DPLL)*/
+static u32 check_need_plat_clk(u32 new_clk)
+{
+ u32 sel, cur_dpll, nd_dpll = 0;
+
+ if (PLAT_CLK == new_clk) {
+ return 0;
+ }
+
+ sel = sci_glb_read(REG_AON_CLK_EMC_CFG, -1);
+ sel &= 0x3;
+ /* if current not used dpll return 0 don't need platform clock */
+ if (sel != 0x03) {
+ return 0;
+ }
+
+ /* get dpll clock to check */
+ cur_dpll = dpll_clk_get();
+ nd_dpll = get_dpll_from_clk(new_clk);
+ if (nd_dpll == 0){
+ /* must be not go to this, if running, new_clk error! */
+ return 1;
+ }
+
+ if (cur_dpll == nd_dpll) {
+ return 0;
+ }
+
+ return 1;
+}
+
+u32 emc_clk_set(u32 new_clk, u32 sene)
+{
+ u32 old_clk, nd_dpll;
+#if defined (EMC_FREQ_AUTO_TEST) || defined (CONFIG_SCX35_DMC_FREQ_AP)
+ unsigned long irq_flags = 0;
+#endif
+
+/* used to get dfs hold times for debug */
+#if 0
+ u32 start_t1, end_t1;
+ static u32 max_u_time = 0;
+ u32 current_u_time;
+
+ start_t1 = get_sys_cnt();
+#endif
+
+ /* check new_clk */
+ if ((new_clk != 200) && (new_clk != 384) && (new_clk != 400)
+ && (new_clk != 466) && (new_clk != 533)) {
+ printk("[emc_clk_set] : new_clk[%d] error!\n\r", new_clk);
+ return 0;
+ }
+
+ /* make sure no other thread running this code */
+ if(mutex_flg >= 1) {
+ panic("now other thread set dmc clk\n");
+ goto out;
+ }
+ mutex_flg ++;
+
+ /* step 1: save irq and lock it */
+#if defined (EMC_FREQ_AUTO_TEST) || defined (CONFIG_SCX35_DMC_FREQ_AP)
+ local_irq_save(irq_flags);
+#endif
+
+ /* check current clock */
+ old_clk = emc_clk_get();
+ if(old_clk == new_clk) {
+ goto out;
+ }
+
+ /* step 2: check new clock need alter dpll( paltform clock ) or not */
+ if (check_need_plat_clk(new_clk)) {
+ __emc_clk_set(PLAT_CLK);
+
+ /* set dpll to need */
+ nd_dpll = get_dpll_from_clk(new_clk);
+ if (nd_dpll == 0){
+ /* must be not go to this, if running, new_clk error! */
+ goto out;
+ }
+ dpll_clk_set(nd_dpll);
+ }
+
+#ifdef CONFIG_SCX35_DMC_FREQ_AP
+ __emc_clk_set(new_clk);
+#endif
+
+out:
+#if defined (EMC_FREQ_AUTO_TEST) || defined(CONFIG_SCX35_DMC_FREQ_AP)
+ local_irq_restore(irq_flags);
+#endif
+ mutex_flg --;
+#if 0
+ end_t1 = get_sys_cnt();
+
+ current_u_time = (start_t1 - end_t1)/128;
+ if(max_u_time < current_u_time) {
+ max_u_time = current_u_time;
+ }
+ printk("emc dfs use current = %08u max %08u\n", current_u_time, max_u_time);
+#endif
+ return 0;
+}
+EXPORT_SYMBOL(emc_clk_set);
+
+#ifdef CONFIG_SCX35_DMC_FREQ_AP
+static int emc_dfs_call(unsigned long flag)
+{
+ cpu_switch_mm(init_mm.pgd, &init_mm);
+ ((int (*)(unsigned long))SPRD_IRAM0H_PHYS)(flag); //iram0h must be the first function of dfs
+ return 0;
+}
+static void emc_dfs_code_copy(u8 * dest)
+{
+ memcpy_toio((void *)dest, (void *)emc_dfs_main, 0xc00);
+}
+#endif
+
+
+static int __init emc_early_suspend_init(void)
+{
+#ifdef CONFIG_SCX35_DMC_FREQ_AP
+ int ret;
+ emc_dfs_code_copy((u8 *)SPRD_IRAM0H_BASE);
+ ret = ioremap_page_range(SPRD_IRAM0H_PHYS,
+ SPRD_IRAM0H_PHYS+SZ_4K, SPRD_IRAM0H_PHYS, PAGE_KERNEL_EXEC);
+ if (ret) {
+ printk("ioremap_page_range err %d\n", ret);
+ BUG();
+ }
+#endif
+
+#ifdef EMC_FREQ_AUTO_TEST
+ __emc_freq_test();
+#endif
+
+ return 0;
+}
+
+static void __exit emc_early_suspend_exit(void)
+{
+}
+
+#ifndef CONFIG_ARCH_SCX20
+module_init(emc_early_suspend_init);
+module_exit(emc_early_suspend_exit);
+#endif
+
+#endif
+
+#ifdef CONFIG_ARCH_SCX35L
+#include <linux/init.h>
+#include <linux/suspend.h>
+#include <linux/kobject.h>
+#include <linux/fs.h>
+#include <linux/io.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/io.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/wakelock.h>
+#include <linux/module.h>
+#include <linux/kthread.h>
+#include <soc/sprd/common.h>
+#include <soc/sprd/hardware.h>
+#include <soc/sprd/sci.h>
+#include <linux/earlysuspend.h>
+#include <soc/sprd/sci_glb_regs.h>
+
+#define DDR_TIMING_REG_VAL_ADDR (SPRD_IRAM0H_BASE + 0xc00)
+#define DDR_TIMING_CALC_VAL_ADDR (SPRD_IRAM0H_BASE + 0xF80)
+
+static u32 dpll_clk_get(void)
+{
+ u32 clk = 0;
+ u32 nint, kint, refin, pnt = 0 ;
+ u32 reg1, reg2, div_s, sdm_en, n;
+
+ reg1 = sci_glb_read(REG_AON_APB_DPLL_CFG1, -1);
+ reg2 = sci_glb_read(REG_AON_APB_DPLL_CFG2, -1);
+ kint = reg2 & 0xFFFFF;
+ nint = (reg2>>24) & 0x3F;
+ div_s = (reg1 >> 26) & 0x01;
+ sdm_en = (reg1 >> 24) & 0x01;
+ n = reg1 & 0x7ff;
+
+ switch((reg1>>18)&0x3)
+ {
+ case 0:
+ refin = 2;
+ break;
+ case 1:
+ refin = 4;
+ break;
+ case 2:
+ refin = 13;
+ break;
+ case 3:
+ refin = 26;
+ break;
+ }
+
+
+ if ((div_s != 0) && (sdm_en != 0)) {
+ if (((kint * refin ) & 0xFFFFF) >= 0x80000) {
+ pnt = 1;
+ }
+ else {
+ pnt = 0;
+ }
+ kint = ((kint * refin) >> 20) + pnt;
+ clk = nint * refin + kint;
+ }
+ else if ((div_s != 0) && (sdm_en == 0)) {
+ clk = nint * refin;
+ }
+ else/* if (div_s == 0) */ {
+ clk = refin * n;
+ }
+
+ return clk;
+}
+
+u32 emc_clk_get(void)
+{
+ u32 pll_clk;
+ u32 div;
+ u32 reg_val;
+ u32 sel;
+ u32 clk;
+ reg_val = sci_glb_read(REG_AON_CLK_EMC_CFG, -1);
+ sel = reg_val & 0x7;
+ div = (reg_val >> 8) & 0x7;
+ switch(sel) {
+ case 0:
+ pll_clk = 26;
+ break;
+ case 1:
+ pll_clk = 192;
+ break;
+ case 2:
+ pll_clk = 307;
+ break;
+ case 3:
+ pll_clk = 384;
+ break;
+ case 4:
+ pll_clk = 512;
+ break;
+ case 5:
+ pll_clk = 614;
+ break;
+ case 6:
+ pll_clk = 768;
+ break;
+ case 7:
+ pll_clk = dpll_clk_get();
+ break;
+ default:
+ break;
+ }
+
+ clk = (pll_clk / (div + 1)) >> 1;
+ return clk;
+}
+EXPORT_SYMBOL(emc_clk_get);
+#endif