11881cdb1SYouMin Chen // SPDX-License-Identifier: GPL-2.0 25eeb396bSKever Yang /* 31881cdb1SYouMin Chen * (C) Copyright 2018 Rockchip Electronics Co., Ltd. 45eeb396bSKever Yang */ 55eeb396bSKever Yang 65eeb396bSKever Yang #include <common.h> 71881cdb1SYouMin Chen #include <debug_uart.h> 85eeb396bSKever Yang #include <dm.h> 95eeb396bSKever Yang #include <ram.h> 105eeb396bSKever Yang #include <syscon.h> 111881cdb1SYouMin Chen #include <asm/io.h> 125eeb396bSKever Yang #include <asm/arch/clock.h> 131881cdb1SYouMin Chen #include <asm/arch/cru_px30.h> 145eeb396bSKever Yang #include <asm/arch/grf_px30.h> 151881cdb1SYouMin Chen #include <asm/arch/hardware.h> 165eeb396bSKever Yang #include <asm/arch/sdram_common.h> 171881cdb1SYouMin Chen #include <asm/arch/sdram_px30.h> 181881cdb1SYouMin Chen 191881cdb1SYouMin Chen /* 201881cdb1SYouMin Chen * Because px30 sram size is small, so need define CONFIG_TPL_TINY_FRAMEWORK 211881cdb1SYouMin Chen * to reduce TPL size when build TPL firmware. 221881cdb1SYouMin Chen */ 231881cdb1SYouMin Chen #ifdef CONFIG_TPL_BUILD 241881cdb1SYouMin Chen #ifndef CONFIG_TPL_TINY_FRAMEWORK 251881cdb1SYouMin Chen #error please defined CONFIG_TPL_TINY_FRAMEWORK for px30 !!! 261881cdb1SYouMin Chen #endif 271881cdb1SYouMin Chen #endif 285eeb396bSKever Yang 29cf41a383STang Yun ping #ifdef CONFIG_TPL_BUILD 30cf41a383STang Yun ping 315eeb396bSKever Yang DECLARE_GLOBAL_DATA_PTR; 325eeb396bSKever Yang struct dram_info { 331881cdb1SYouMin Chen struct px30_ddr_pctl_regs *pctl; 341881cdb1SYouMin Chen struct px30_ddr_phy_regs *phy; 351881cdb1SYouMin Chen struct px30_cru *cru; 361881cdb1SYouMin Chen struct px30_msch_regs *msch; 371881cdb1SYouMin Chen struct px30_ddr_grf_regs *ddr_grf; 381881cdb1SYouMin Chen struct px30_grf *grf; 395eeb396bSKever Yang struct ram_info info; 405eeb396bSKever Yang struct px30_pmugrf *pmugrf; 415eeb396bSKever Yang }; 425eeb396bSKever Yang 431881cdb1SYouMin Chen #define PMUGRF_BASE_ADDR 0xFF010000 441881cdb1SYouMin Chen #define CRU_BASE_ADDR 0xFF2B0000 451881cdb1SYouMin Chen #define GRF_BASE_ADDR 0xFF140000 461881cdb1SYouMin Chen #define DDRC_BASE_ADDR 0xFF600000 471881cdb1SYouMin Chen #define DDR_PHY_BASE_ADDR 0xFF2A0000 481881cdb1SYouMin Chen #define SERVER_MSCH0_BASE_ADDR 0xFF530000 491881cdb1SYouMin Chen #define DDR_GRF_BASE_ADDR 0xff630000 501881cdb1SYouMin Chen 511881cdb1SYouMin Chen struct dram_info dram_info; 521881cdb1SYouMin Chen 531881cdb1SYouMin Chen struct px30_sdram_params sdram_configs[] = { 541881cdb1SYouMin Chen #include "sdram-px30-lpddr3-detect-333.inc" 551881cdb1SYouMin Chen }; 561881cdb1SYouMin Chen 571881cdb1SYouMin Chen struct px30_ddr_skew skew = { 581881cdb1SYouMin Chen #include "sdram-px30-ddr_skew.inc" 591881cdb1SYouMin Chen }; 601881cdb1SYouMin Chen 611881cdb1SYouMin Chen static void rkclk_ddr_reset(struct dram_info *dram, 621881cdb1SYouMin Chen u32 ctl_srstn, u32 ctl_psrstn, 631881cdb1SYouMin Chen u32 phy_srstn, u32 phy_psrstn) 641881cdb1SYouMin Chen { 651881cdb1SYouMin Chen writel(upctl2_srstn_req(ctl_srstn) | upctl2_psrstn_req(ctl_psrstn) | 661881cdb1SYouMin Chen upctl2_asrstn_req(ctl_srstn), 671881cdb1SYouMin Chen &dram->cru->softrst_con[1]); 681881cdb1SYouMin Chen writel(ddrphy_srstn_req(phy_srstn) | ddrphy_psrstn_req(phy_psrstn), 691881cdb1SYouMin Chen &dram->cru->softrst_con[2]); 701881cdb1SYouMin Chen } 711881cdb1SYouMin Chen 721881cdb1SYouMin Chen static void rkclk_set_dpll(struct dram_info *dram, unsigned int mhz) 731881cdb1SYouMin Chen { 741881cdb1SYouMin Chen unsigned int refdiv, postdiv1, postdiv2, fbdiv; 751881cdb1SYouMin Chen int delay = 1000; 761881cdb1SYouMin Chen 771881cdb1SYouMin Chen refdiv = 1; 781881cdb1SYouMin Chen if (mhz <= 300) { 791881cdb1SYouMin Chen postdiv1 = 4; 801881cdb1SYouMin Chen postdiv2 = 2; 811881cdb1SYouMin Chen } else if (mhz <= 400) { 821881cdb1SYouMin Chen postdiv1 = 6; 831881cdb1SYouMin Chen postdiv2 = 1; 841881cdb1SYouMin Chen } else if (mhz <= 600) { 851881cdb1SYouMin Chen postdiv1 = 4; 861881cdb1SYouMin Chen postdiv2 = 1; 871881cdb1SYouMin Chen } else if (mhz <= 800) { 881881cdb1SYouMin Chen postdiv1 = 3; 891881cdb1SYouMin Chen postdiv2 = 1; 901881cdb1SYouMin Chen } else if (mhz <= 1600) { 911881cdb1SYouMin Chen postdiv1 = 2; 921881cdb1SYouMin Chen postdiv2 = 1; 931881cdb1SYouMin Chen } else { 941881cdb1SYouMin Chen postdiv1 = 1; 951881cdb1SYouMin Chen postdiv2 = 1; 961881cdb1SYouMin Chen } 971881cdb1SYouMin Chen fbdiv = (mhz * refdiv * postdiv1 * postdiv2) / 24; 981881cdb1SYouMin Chen 991881cdb1SYouMin Chen writel(DPLL_MODE(CLOCK_FROM_XIN_OSC), &dram->cru->mode); 1001881cdb1SYouMin Chen 1011881cdb1SYouMin Chen writel(POSTDIV1(postdiv1) | FBDIV(fbdiv), &dram->cru->pll[1].con0); 1021881cdb1SYouMin Chen writel(DSMPD(1) | POSTDIV2(postdiv2) | REFDIV(refdiv), 1031881cdb1SYouMin Chen &dram->cru->pll[1].con1); 1041881cdb1SYouMin Chen 1051881cdb1SYouMin Chen while (delay > 0) { 1061881cdb1SYouMin Chen udelay(1); 1071881cdb1SYouMin Chen if (LOCK(readl(&dram->cru->pll[1].con1))) 1081881cdb1SYouMin Chen break; 1091881cdb1SYouMin Chen delay--; 1101881cdb1SYouMin Chen } 1111881cdb1SYouMin Chen 1121881cdb1SYouMin Chen writel(DPLL_MODE(CLOCK_FROM_PLL), &dram->cru->mode); 1131881cdb1SYouMin Chen } 1141881cdb1SYouMin Chen 1151881cdb1SYouMin Chen static void rkclk_configure_ddr(struct dram_info *dram, 1161881cdb1SYouMin Chen struct px30_sdram_params *sdram_params) 1171881cdb1SYouMin Chen { 1181881cdb1SYouMin Chen /* for inno ddr phy need 2*freq */ 1191881cdb1SYouMin Chen rkclk_set_dpll(dram, sdram_params->ddr_freq * 2); 1201881cdb1SYouMin Chen } 1211881cdb1SYouMin Chen 1221881cdb1SYouMin Chen static void phy_soft_reset(struct dram_info *dram) 1231881cdb1SYouMin Chen { 1241881cdb1SYouMin Chen void __iomem *phy_base = dram->phy; 1251881cdb1SYouMin Chen 1261881cdb1SYouMin Chen clrbits_le32(PHY_REG(phy_base, 0), 0x3 << 2); 1271881cdb1SYouMin Chen udelay(1); 1281881cdb1SYouMin Chen setbits_le32(PHY_REG(phy_base, 0), ANALOG_DERESET); 1291881cdb1SYouMin Chen udelay(5); 1301881cdb1SYouMin Chen setbits_le32(PHY_REG(phy_base, 0), DIGITAL_DERESET); 1311881cdb1SYouMin Chen udelay(1); 1321881cdb1SYouMin Chen } 1331881cdb1SYouMin Chen 1341881cdb1SYouMin Chen static int pctl_cfg(struct dram_info *dram, 1351881cdb1SYouMin Chen struct px30_sdram_params *sdram_params) 1361881cdb1SYouMin Chen { 1371881cdb1SYouMin Chen u32 i; 1381881cdb1SYouMin Chen void __iomem *pctl_base = dram->pctl; 1391881cdb1SYouMin Chen 1401881cdb1SYouMin Chen for (i = 0; sdram_params->pctl_regs.pctl[i][0] != 0xFFFFFFFF; i++) { 1411881cdb1SYouMin Chen writel(sdram_params->pctl_regs.pctl[i][1], 1421881cdb1SYouMin Chen pctl_base + sdram_params->pctl_regs.pctl[i][0]); 1431881cdb1SYouMin Chen } 1441881cdb1SYouMin Chen clrsetbits_le32(pctl_base + DDR_PCTL2_PWRTMG, 1451881cdb1SYouMin Chen (0xff << 16) | 0x1f, 1461881cdb1SYouMin Chen ((SR_IDLE & 0xff) << 16) | (PD_IDLE & 0x1f)); 1471881cdb1SYouMin Chen 1481881cdb1SYouMin Chen clrsetbits_le32(pctl_base + DDR_PCTL2_HWLPCTL, 1491881cdb1SYouMin Chen 0xfff << 16, 1501881cdb1SYouMin Chen 5 << 16); 1511881cdb1SYouMin Chen /* disable zqcs */ 1521881cdb1SYouMin Chen setbits_le32(pctl_base + DDR_PCTL2_ZQCTL0, 1u << 31); 1531881cdb1SYouMin Chen 1541881cdb1SYouMin Chen return 0; 1551881cdb1SYouMin Chen } 1561881cdb1SYouMin Chen 1571881cdb1SYouMin Chen /* return ddrconfig value 1581881cdb1SYouMin Chen * (-1), find ddrconfig fail 1591881cdb1SYouMin Chen * other, the ddrconfig value 1601881cdb1SYouMin Chen * only support cs0_row >= cs1_row 1611881cdb1SYouMin Chen */ 1621881cdb1SYouMin Chen static unsigned int calculate_ddrconfig(struct px30_sdram_params *sdram_params) 1631881cdb1SYouMin Chen { 1641881cdb1SYouMin Chen u32 bw, die_bw, col, bank; 1651881cdb1SYouMin Chen u32 i, tmp; 1661881cdb1SYouMin Chen u32 ddrconf = -1; 1671881cdb1SYouMin Chen 1681881cdb1SYouMin Chen bw = sdram_params->ch.bw; 1691881cdb1SYouMin Chen die_bw = sdram_params->ch.dbw; 1701881cdb1SYouMin Chen col = sdram_params->ch.col; 1711881cdb1SYouMin Chen bank = sdram_params->ch.bk; 1721881cdb1SYouMin Chen 1731881cdb1SYouMin Chen if (sdram_params->dramtype == DDR4) { 1741881cdb1SYouMin Chen if (die_bw == 0) 1751881cdb1SYouMin Chen ddrconf = 7 + bw; 1761881cdb1SYouMin Chen else 1771881cdb1SYouMin Chen ddrconf = 12 - bw; 1781881cdb1SYouMin Chen ddrconf = d4_rbc_2_d3_rbc[ddrconf - 7]; 1791881cdb1SYouMin Chen } else { 1801881cdb1SYouMin Chen tmp = ((bank - 2) << 3) | (col + bw - 10); 1811881cdb1SYouMin Chen for (i = 0; i < 7; i++) 1821881cdb1SYouMin Chen if ((ddr_cfg_2_rbc[i] & 0xf) == tmp) { 1831881cdb1SYouMin Chen ddrconf = i; 1841881cdb1SYouMin Chen break; 1851881cdb1SYouMin Chen } 1861881cdb1SYouMin Chen if (i > 6) 1871881cdb1SYouMin Chen printascii("calculate ddrconfig error\n"); 1881881cdb1SYouMin Chen } 1891881cdb1SYouMin Chen 1901881cdb1SYouMin Chen return ddrconf; 1911881cdb1SYouMin Chen } 1921881cdb1SYouMin Chen 1931881cdb1SYouMin Chen /* n: Unit bytes */ 1941881cdb1SYouMin Chen static void copy_to_reg(u32 *dest, u32 *src, u32 n) 1951881cdb1SYouMin Chen { 1961881cdb1SYouMin Chen int i; 1971881cdb1SYouMin Chen 1981881cdb1SYouMin Chen for (i = 0; i < n / sizeof(u32); i++) { 1991881cdb1SYouMin Chen writel(*src, dest); 2001881cdb1SYouMin Chen src++; 2011881cdb1SYouMin Chen dest++; 2021881cdb1SYouMin Chen } 2031881cdb1SYouMin Chen } 2041881cdb1SYouMin Chen 2051881cdb1SYouMin Chen /* 2061881cdb1SYouMin Chen * calculate controller dram address map, and setting to register. 2071881cdb1SYouMin Chen * argument sdram_params->ch.ddrconf must be right value before 2081881cdb1SYouMin Chen * call this function. 2091881cdb1SYouMin Chen */ 2101881cdb1SYouMin Chen static void set_ctl_address_map(struct dram_info *dram, 2111881cdb1SYouMin Chen struct px30_sdram_params *sdram_params) 2121881cdb1SYouMin Chen { 2131881cdb1SYouMin Chen void __iomem *pctl_base = dram->pctl; 2141881cdb1SYouMin Chen u32 cs_pst, bg, max_row, ddrconf; 2151881cdb1SYouMin Chen u32 i; 2161881cdb1SYouMin Chen 2171881cdb1SYouMin Chen if (sdram_params->dramtype == DDR4) 2181881cdb1SYouMin Chen /* 2191881cdb1SYouMin Chen * DDR4 8bit dram BG = 2(4bank groups), 2201881cdb1SYouMin Chen * 16bit dram BG = 1 (2 bank groups) 2211881cdb1SYouMin Chen */ 2221881cdb1SYouMin Chen bg = (sdram_params->ch.dbw == 0) ? 2 : 1; 2231881cdb1SYouMin Chen else 2241881cdb1SYouMin Chen bg = 0; 2251881cdb1SYouMin Chen 2261881cdb1SYouMin Chen cs_pst = sdram_params->ch.bw + sdram_params->ch.col + 2271881cdb1SYouMin Chen bg + sdram_params->ch.bk + sdram_params->ch.cs0_row; 2281881cdb1SYouMin Chen if (cs_pst >= 32 || sdram_params->ch.rank == 1) 2291881cdb1SYouMin Chen writel(0x1f, pctl_base + DDR_PCTL2_ADDRMAP0); 2301881cdb1SYouMin Chen else 2311881cdb1SYouMin Chen writel(cs_pst - 8, pctl_base + DDR_PCTL2_ADDRMAP0); 2321881cdb1SYouMin Chen 2331881cdb1SYouMin Chen ddrconf = sdram_params->ch.ddrconfig; 2341881cdb1SYouMin Chen if (sdram_params->dramtype == DDR4) { 2351881cdb1SYouMin Chen for (i = 0; i < ARRAY_SIZE(d4_rbc_2_d3_rbc); i++) { 2361881cdb1SYouMin Chen if (d4_rbc_2_d3_rbc[i] == ddrconf) { 2371881cdb1SYouMin Chen ddrconf = 7 + i; 2381881cdb1SYouMin Chen break; 2391881cdb1SYouMin Chen } 2401881cdb1SYouMin Chen } 2411881cdb1SYouMin Chen } 2421881cdb1SYouMin Chen 2431881cdb1SYouMin Chen copy_to_reg((u32 *)(pctl_base + DDR_PCTL2_ADDRMAP1), 2441881cdb1SYouMin Chen &addrmap[ddrconf][0], 8 * 4); 2451881cdb1SYouMin Chen max_row = cs_pst - 1 - 8 - (addrmap[ddrconf][5] & 0xf); 2461881cdb1SYouMin Chen 2471881cdb1SYouMin Chen if (max_row < 12) 2481881cdb1SYouMin Chen printascii("set addrmap fail\n"); 2491881cdb1SYouMin Chen /* need to disable row ahead of rank by set to 0xf */ 2501881cdb1SYouMin Chen for (i = 17; i > max_row; i--) 2511881cdb1SYouMin Chen clrsetbits_le32(pctl_base + DDR_PCTL2_ADDRMAP6 + 2521881cdb1SYouMin Chen ((i - 12) * 8 / 32) * 4, 2531881cdb1SYouMin Chen 0xf << ((i - 12) * 8 % 32), 2541881cdb1SYouMin Chen 0xf << ((i - 12) * 8 % 32)); 2551881cdb1SYouMin Chen 2561881cdb1SYouMin Chen if ((sdram_params->dramtype == LPDDR3 || 2571881cdb1SYouMin Chen sdram_params->dramtype == LPDDR2) && 2581881cdb1SYouMin Chen sdram_params->ch.row_3_4) 2591881cdb1SYouMin Chen setbits_le32(pctl_base + DDR_PCTL2_ADDRMAP6, 1 << 31); 2601881cdb1SYouMin Chen if (sdram_params->dramtype == DDR4 && sdram_params->ch.bw != 0x2) 2611881cdb1SYouMin Chen setbits_le32(pctl_base + DDR_PCTL2_PCCFG, 1 << 8); 2621881cdb1SYouMin Chen } 2631881cdb1SYouMin Chen 2641881cdb1SYouMin Chen static void phy_dll_bypass_set(struct dram_info *dram, u32 freq) 2651881cdb1SYouMin Chen { 2661881cdb1SYouMin Chen void __iomem *phy_base = dram->phy; 2671881cdb1SYouMin Chen u32 tmp; 2681881cdb1SYouMin Chen u32 i, j; 2691881cdb1SYouMin Chen 2701881cdb1SYouMin Chen setbits_le32(PHY_REG(phy_base, 0x13), 1 << 4); 2711881cdb1SYouMin Chen clrbits_le32(PHY_REG(phy_base, 0x14), 1 << 3); 2721881cdb1SYouMin Chen for (i = 0; i < 4; i++) { 2731881cdb1SYouMin Chen j = 0x26 + i * 0x10; 2741881cdb1SYouMin Chen setbits_le32(PHY_REG(phy_base, j), 1 << 4); 2751881cdb1SYouMin Chen clrbits_le32(PHY_REG(phy_base, j + 0x1), 1 << 3); 2761881cdb1SYouMin Chen } 2771881cdb1SYouMin Chen 2781881cdb1SYouMin Chen if (freq <= (400 * MHz)) 2791881cdb1SYouMin Chen /* DLL bypass */ 2801881cdb1SYouMin Chen setbits_le32(PHY_REG(phy_base, 0xa4), 0x1f); 2811881cdb1SYouMin Chen else 2821881cdb1SYouMin Chen clrbits_le32(PHY_REG(phy_base, 0xa4), 0x1f); 2831881cdb1SYouMin Chen 2841881cdb1SYouMin Chen if (freq <= (801 * MHz)) 2851881cdb1SYouMin Chen tmp = 2; 2861881cdb1SYouMin Chen else 2871881cdb1SYouMin Chen tmp = 1; 2881881cdb1SYouMin Chen 2891881cdb1SYouMin Chen for (i = 0; i < 4; i++) { 2901881cdb1SYouMin Chen j = 0x28 + i * 0x10; 2911881cdb1SYouMin Chen writel(tmp, PHY_REG(phy_base, j)); 2921881cdb1SYouMin Chen } 2931881cdb1SYouMin Chen } 2941881cdb1SYouMin Chen 2951881cdb1SYouMin Chen static void set_ds_odt(struct dram_info *dram, 2961881cdb1SYouMin Chen struct px30_sdram_params *sdram_params) 2971881cdb1SYouMin Chen { 2981881cdb1SYouMin Chen void __iomem *phy_base = dram->phy; 2991881cdb1SYouMin Chen u32 cmd_drv, clk_drv, dqs_drv, dqs_odt; 3001881cdb1SYouMin Chen u32 i, j; 3011881cdb1SYouMin Chen 3021881cdb1SYouMin Chen if (sdram_params->dramtype == DDR3) { 3031881cdb1SYouMin Chen cmd_drv = PHY_DDR3_RON_RTT_34ohm; 3041881cdb1SYouMin Chen clk_drv = PHY_DDR3_RON_RTT_45ohm; 3051881cdb1SYouMin Chen dqs_drv = PHY_DDR3_RON_RTT_34ohm; 3061881cdb1SYouMin Chen dqs_odt = PHY_DDR3_RON_RTT_225ohm; 3071881cdb1SYouMin Chen } else { 3081881cdb1SYouMin Chen cmd_drv = PHY_DDR4_LPDDR3_RON_RTT_34ohm; 3091881cdb1SYouMin Chen clk_drv = PHY_DDR4_LPDDR3_RON_RTT_43ohm; 3101881cdb1SYouMin Chen dqs_drv = PHY_DDR4_LPDDR3_RON_RTT_34ohm; 3111881cdb1SYouMin Chen if (sdram_params->dramtype == LPDDR2) 3121881cdb1SYouMin Chen dqs_odt = PHY_DDR4_LPDDR3_RON_RTT_DISABLE; 3131881cdb1SYouMin Chen else 3141881cdb1SYouMin Chen dqs_odt = PHY_DDR4_LPDDR3_RON_RTT_240ohm; 3151881cdb1SYouMin Chen } 3161881cdb1SYouMin Chen /* DS */ 3171881cdb1SYouMin Chen writel(cmd_drv, PHY_REG(phy_base, 0x11)); 3181881cdb1SYouMin Chen clrsetbits_le32(PHY_REG(phy_base, 0x12), 0x1f << 3, cmd_drv << 3); 3191881cdb1SYouMin Chen writel(clk_drv, PHY_REG(phy_base, 0x16)); 3201881cdb1SYouMin Chen writel(clk_drv, PHY_REG(phy_base, 0x18)); 3211881cdb1SYouMin Chen 3221881cdb1SYouMin Chen for (i = 0; i < 4; i++) { 3231881cdb1SYouMin Chen j = 0x20 + i * 0x10; 3241881cdb1SYouMin Chen writel(dqs_drv, PHY_REG(phy_base, j)); 3251881cdb1SYouMin Chen writel(dqs_drv, PHY_REG(phy_base, j + 0xf)); 3261881cdb1SYouMin Chen /* ODT */ 3271881cdb1SYouMin Chen writel(dqs_odt, PHY_REG(phy_base, j + 0x1)); 3281881cdb1SYouMin Chen writel(dqs_odt, PHY_REG(phy_base, j + 0xe)); 3291881cdb1SYouMin Chen } 3301881cdb1SYouMin Chen } 3311881cdb1SYouMin Chen 3321881cdb1SYouMin Chen static void phy_cfg(struct dram_info *dram, 3331881cdb1SYouMin Chen struct px30_sdram_params *sdram_params) 3341881cdb1SYouMin Chen { 3351881cdb1SYouMin Chen void __iomem *phy_base = dram->phy; 3361881cdb1SYouMin Chen u32 i; 3371881cdb1SYouMin Chen 3381881cdb1SYouMin Chen phy_dll_bypass_set(dram, sdram_params->ddr_freq); 3391881cdb1SYouMin Chen for (i = 0; sdram_params->phy_regs.phy[i][0] != 0xFFFFFFFF; i++) { 3401881cdb1SYouMin Chen writel(sdram_params->phy_regs.phy[i][1], 3411881cdb1SYouMin Chen phy_base + sdram_params->phy_regs.phy[i][0]); 3421881cdb1SYouMin Chen } 3431881cdb1SYouMin Chen if (sdram_params->ch.bw == 2) { 3441881cdb1SYouMin Chen clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 0xf << 4); 3451881cdb1SYouMin Chen } else if (sdram_params->ch.bw == 1) { 3461881cdb1SYouMin Chen clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 3 << 4); 3471881cdb1SYouMin Chen /* disable DQS2,DQS3 tx dll for saving power */ 3481881cdb1SYouMin Chen clrbits_le32(PHY_REG(phy_base, 0x46), 1 << 3); 3491881cdb1SYouMin Chen clrbits_le32(PHY_REG(phy_base, 0x56), 1 << 3); 3501881cdb1SYouMin Chen } else { 3511881cdb1SYouMin Chen clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 1 << 4); 3521881cdb1SYouMin Chen /* disable DQS2,DQS3 tx dll for saving power */ 3531881cdb1SYouMin Chen clrbits_le32(PHY_REG(phy_base, 0x36), 1 << 3); 3541881cdb1SYouMin Chen clrbits_le32(PHY_REG(phy_base, 0x46), 1 << 3); 3551881cdb1SYouMin Chen clrbits_le32(PHY_REG(phy_base, 0x56), 1 << 3); 3561881cdb1SYouMin Chen } 3571881cdb1SYouMin Chen set_ds_odt(dram, sdram_params); 3581881cdb1SYouMin Chen 3591881cdb1SYouMin Chen /* deskew */ 3601881cdb1SYouMin Chen setbits_le32(PHY_REG(phy_base, 2), 8); 3611881cdb1SYouMin Chen copy_to_reg(PHY_REG(phy_base, 0xb0), 3621881cdb1SYouMin Chen &sdram_params->skew->a0_a1_skew[0], 15 * 4); 3631881cdb1SYouMin Chen copy_to_reg(PHY_REG(phy_base, 0x70), 3641881cdb1SYouMin Chen &sdram_params->skew->cs0_dm0_skew[0], 44 * 4); 3651881cdb1SYouMin Chen copy_to_reg(PHY_REG(phy_base, 0xc0), 36628d6bb02SYouMin Chen &sdram_params->skew->cs1_dm0_skew[0], 44 * 4); 3671881cdb1SYouMin Chen } 3681881cdb1SYouMin Chen 3691881cdb1SYouMin Chen static int update_refresh_reg(struct dram_info *dram) 3701881cdb1SYouMin Chen { 3711881cdb1SYouMin Chen void __iomem *pctl_base = dram->pctl; 3721881cdb1SYouMin Chen u32 ret; 3731881cdb1SYouMin Chen 3741881cdb1SYouMin Chen ret = readl(pctl_base + DDR_PCTL2_RFSHCTL3) ^ (1 << 1); 3751881cdb1SYouMin Chen writel(ret, pctl_base + DDR_PCTL2_RFSHCTL3); 3761881cdb1SYouMin Chen 3771881cdb1SYouMin Chen return 0; 3781881cdb1SYouMin Chen } 3791881cdb1SYouMin Chen 3801881cdb1SYouMin Chen /* 3811881cdb1SYouMin Chen * rank = 1: cs0 3821881cdb1SYouMin Chen * rank = 2: cs1 3831881cdb1SYouMin Chen */ 3841881cdb1SYouMin Chen int read_mr(struct dram_info *dram, u32 rank, u32 mr_num) 3851881cdb1SYouMin Chen { 3861881cdb1SYouMin Chen void __iomem *pctl_base = dram->pctl; 3871881cdb1SYouMin Chen void __iomem *ddr_grf_base = dram->ddr_grf; 3881881cdb1SYouMin Chen 3891881cdb1SYouMin Chen writel((rank << 4) | (1 << 0), pctl_base + DDR_PCTL2_MRCTRL0); 3901881cdb1SYouMin Chen writel((mr_num << 8), pctl_base + DDR_PCTL2_MRCTRL1); 3911881cdb1SYouMin Chen setbits_le32(pctl_base + DDR_PCTL2_MRCTRL0, 1u << 31); 3921881cdb1SYouMin Chen while (readl(pctl_base + DDR_PCTL2_MRCTRL0) & (1u << 31)) 3931881cdb1SYouMin Chen continue; 3941881cdb1SYouMin Chen while (readl(pctl_base + DDR_PCTL2_MRSTAT) & MR_WR_BUSY) 3951881cdb1SYouMin Chen continue; 3961881cdb1SYouMin Chen 3971881cdb1SYouMin Chen return (readl(ddr_grf_base + DDR_GRF_STATUS(0)) & 0xff); 3981881cdb1SYouMin Chen } 3991881cdb1SYouMin Chen 4001881cdb1SYouMin Chen u32 disable_zqcs_arefresh(struct dram_info *dram) 4011881cdb1SYouMin Chen { 4021881cdb1SYouMin Chen void __iomem *pctl_base = dram->pctl; 4031881cdb1SYouMin Chen u32 dis_auto_zq = 0; 4041881cdb1SYouMin Chen 4051881cdb1SYouMin Chen /* disable zqcs */ 4061881cdb1SYouMin Chen if (!(readl(pctl_base + DDR_PCTL2_ZQCTL0) & 4071881cdb1SYouMin Chen (1ul << 31))) { 4081881cdb1SYouMin Chen dis_auto_zq = 1; 4091881cdb1SYouMin Chen setbits_le32(pctl_base + DDR_PCTL2_ZQCTL0, 1 << 31); 4101881cdb1SYouMin Chen } 4111881cdb1SYouMin Chen 4121881cdb1SYouMin Chen /* disable auto refresh */ 4131881cdb1SYouMin Chen setbits_le32(pctl_base + DDR_PCTL2_RFSHCTL3, 1); 4141881cdb1SYouMin Chen 4151881cdb1SYouMin Chen update_refresh_reg(dram); 4161881cdb1SYouMin Chen 4171881cdb1SYouMin Chen return dis_auto_zq; 4181881cdb1SYouMin Chen } 4191881cdb1SYouMin Chen 4201881cdb1SYouMin Chen void restore_zqcs_arefresh(struct dram_info *dram, u32 dis_auto_zq) 4211881cdb1SYouMin Chen { 4221881cdb1SYouMin Chen void __iomem *pctl_base = dram->pctl; 4231881cdb1SYouMin Chen 4241881cdb1SYouMin Chen /* restore zqcs */ 4251881cdb1SYouMin Chen if (dis_auto_zq) 4261881cdb1SYouMin Chen clrbits_le32(pctl_base + DDR_PCTL2_ZQCTL0, 1 << 31); 4271881cdb1SYouMin Chen 4281881cdb1SYouMin Chen /* restore auto refresh */ 4291881cdb1SYouMin Chen clrbits_le32(pctl_base + DDR_PCTL2_RFSHCTL3, 1); 4301881cdb1SYouMin Chen 4311881cdb1SYouMin Chen update_refresh_reg(dram); 4321881cdb1SYouMin Chen } 4331881cdb1SYouMin Chen 4341881cdb1SYouMin Chen #define MIN(a, b) (((a) > (b)) ? (b) : (a)) 4351881cdb1SYouMin Chen #define MAX(a, b) (((a) > (b)) ? (a) : (b)) 4361881cdb1SYouMin Chen static u32 check_rd_gate(struct dram_info *dram) 4371881cdb1SYouMin Chen { 4381881cdb1SYouMin Chen void __iomem *phy_base = dram->phy; 4391881cdb1SYouMin Chen 4401881cdb1SYouMin Chen u32 max_val = 0; 4411881cdb1SYouMin Chen u32 min_val = 0xff; 4421881cdb1SYouMin Chen u32 gate[4]; 4431881cdb1SYouMin Chen u32 i, bw; 4441881cdb1SYouMin Chen 4451881cdb1SYouMin Chen bw = (readl(PHY_REG(phy_base, 0x0)) >> 4) & 0xf; 4461881cdb1SYouMin Chen switch (bw) { 4471881cdb1SYouMin Chen case 0x1: 4481881cdb1SYouMin Chen bw = 1; 4491881cdb1SYouMin Chen break; 4501881cdb1SYouMin Chen case 0x3: 4511881cdb1SYouMin Chen bw = 2; 4521881cdb1SYouMin Chen break; 4531881cdb1SYouMin Chen case 0xf: 4541881cdb1SYouMin Chen default: 4551881cdb1SYouMin Chen bw = 4; 4561881cdb1SYouMin Chen break; 4571881cdb1SYouMin Chen } 4581881cdb1SYouMin Chen 4591881cdb1SYouMin Chen for (i = 0; i < bw; i++) { 4601881cdb1SYouMin Chen gate[i] = readl(PHY_REG(phy_base, 0xfb + i)); 4611881cdb1SYouMin Chen max_val = MAX(max_val, gate[i]); 4621881cdb1SYouMin Chen min_val = MIN(min_val, gate[i]); 4631881cdb1SYouMin Chen } 4641881cdb1SYouMin Chen 4651881cdb1SYouMin Chen if (max_val > 0x80 || min_val < 0x20) 4661881cdb1SYouMin Chen return -1; 4671881cdb1SYouMin Chen else 4681881cdb1SYouMin Chen return 0; 4691881cdb1SYouMin Chen } 4701881cdb1SYouMin Chen 4711881cdb1SYouMin Chen static int data_training(struct dram_info *dram, u32 cs, u32 dramtype) 4721881cdb1SYouMin Chen { 4731881cdb1SYouMin Chen void __iomem *phy_base = dram->phy; 4741881cdb1SYouMin Chen u32 ret; 4751881cdb1SYouMin Chen u32 dis_auto_zq = 0; 4761881cdb1SYouMin Chen u32 odt_val; 4771881cdb1SYouMin Chen u32 i, j; 4781881cdb1SYouMin Chen 4791881cdb1SYouMin Chen odt_val = readl(PHY_REG(phy_base, 0x2e)); 4801881cdb1SYouMin Chen 4811881cdb1SYouMin Chen for (i = 0; i < 4; i++) { 4821881cdb1SYouMin Chen j = 0x20 + i * 0x10; 4831881cdb1SYouMin Chen writel(PHY_DDR3_RON_RTT_225ohm, PHY_REG(phy_base, j + 0x1)); 4841881cdb1SYouMin Chen writel(0, PHY_REG(phy_base, j + 0xe)); 4851881cdb1SYouMin Chen } 4861881cdb1SYouMin Chen 4871881cdb1SYouMin Chen dis_auto_zq = disable_zqcs_arefresh(dram); 4881881cdb1SYouMin Chen 4891881cdb1SYouMin Chen if (dramtype == DDR4) { 4901881cdb1SYouMin Chen clrsetbits_le32(PHY_REG(phy_base, 0x29), 0x3, 0); 4911881cdb1SYouMin Chen clrsetbits_le32(PHY_REG(phy_base, 0x39), 0x3, 0); 4921881cdb1SYouMin Chen clrsetbits_le32(PHY_REG(phy_base, 0x49), 0x3, 0); 4931881cdb1SYouMin Chen clrsetbits_le32(PHY_REG(phy_base, 0x59), 0x3, 0); 4941881cdb1SYouMin Chen } 4951881cdb1SYouMin Chen /* choose training cs */ 4961881cdb1SYouMin Chen clrsetbits_le32(PHY_REG(phy_base, 2), 0x33, (0x20 >> cs)); 4971881cdb1SYouMin Chen /* enable gate training */ 4981881cdb1SYouMin Chen clrsetbits_le32(PHY_REG(phy_base, 2), 0x33, (0x20 >> cs) | 1); 4991881cdb1SYouMin Chen udelay(50); 5001881cdb1SYouMin Chen ret = readl(PHY_REG(phy_base, 0xff)); 5011881cdb1SYouMin Chen /* disable gate training */ 5021881cdb1SYouMin Chen clrsetbits_le32(PHY_REG(phy_base, 2), 0x33, (0x20 >> cs) | 0); 5031881cdb1SYouMin Chen clrbits_le32(PHY_REG(phy_base, 2), 0x30); 5041881cdb1SYouMin Chen restore_zqcs_arefresh(dram, dis_auto_zq); 5051881cdb1SYouMin Chen 5061881cdb1SYouMin Chen if (dramtype == DDR4) { 5071881cdb1SYouMin Chen clrsetbits_le32(PHY_REG(phy_base, 0x29), 0x3, 0x2); 5081881cdb1SYouMin Chen clrsetbits_le32(PHY_REG(phy_base, 0x39), 0x3, 0x2); 5091881cdb1SYouMin Chen clrsetbits_le32(PHY_REG(phy_base, 0x49), 0x3, 0x2); 5101881cdb1SYouMin Chen clrsetbits_le32(PHY_REG(phy_base, 0x59), 0x3, 0x2); 5111881cdb1SYouMin Chen } 5121881cdb1SYouMin Chen 5131881cdb1SYouMin Chen if (ret & 0x10) { 5141881cdb1SYouMin Chen ret = -1; 5151881cdb1SYouMin Chen } else { 5161881cdb1SYouMin Chen ret = (ret & 0xf) ^ (readl(PHY_REG(phy_base, 0)) >> 4); 5171881cdb1SYouMin Chen ret = (ret == 0) ? 0 : -1; 5181881cdb1SYouMin Chen } 5191881cdb1SYouMin Chen 5201881cdb1SYouMin Chen for (i = 0; i < 4; i++) { 5211881cdb1SYouMin Chen j = 0x20 + i * 0x10; 5221881cdb1SYouMin Chen writel(odt_val, PHY_REG(phy_base, j + 0x1)); 5231881cdb1SYouMin Chen writel(odt_val, PHY_REG(phy_base, j + 0xe)); 5241881cdb1SYouMin Chen } 5251881cdb1SYouMin Chen 5261881cdb1SYouMin Chen return ret; 5271881cdb1SYouMin Chen } 5281881cdb1SYouMin Chen 5291881cdb1SYouMin Chen /* rank = 1: cs0 5301881cdb1SYouMin Chen * rank = 2: cs1 5311881cdb1SYouMin Chen * rank = 3: cs0 & cs1 5321881cdb1SYouMin Chen * note: be careful of keep mr original val 5331881cdb1SYouMin Chen */ 5341881cdb1SYouMin Chen static int write_mr(struct dram_info *dram, u32 rank, u32 mr_num, u32 arg, 5351881cdb1SYouMin Chen u32 dramtype) 5361881cdb1SYouMin Chen { 5371881cdb1SYouMin Chen void __iomem *pctl_base = dram->pctl; 5381881cdb1SYouMin Chen 5391881cdb1SYouMin Chen while (readl(pctl_base + DDR_PCTL2_MRSTAT) & MR_WR_BUSY) 5401881cdb1SYouMin Chen continue; 5411881cdb1SYouMin Chen if (dramtype == DDR3 || dramtype == DDR4) { 5421881cdb1SYouMin Chen writel((mr_num << 12) | (rank << 4) | (0 << 0), 5431881cdb1SYouMin Chen pctl_base + DDR_PCTL2_MRCTRL0); 5441881cdb1SYouMin Chen writel(arg, pctl_base + DDR_PCTL2_MRCTRL1); 5451881cdb1SYouMin Chen } else { 5461881cdb1SYouMin Chen writel((rank << 4) | (0 << 0), 5471881cdb1SYouMin Chen pctl_base + DDR_PCTL2_MRCTRL0); 5481881cdb1SYouMin Chen writel((mr_num << 8) | (arg & 0xff), 5491881cdb1SYouMin Chen pctl_base + DDR_PCTL2_MRCTRL1); 5501881cdb1SYouMin Chen } 5511881cdb1SYouMin Chen 5521881cdb1SYouMin Chen setbits_le32(pctl_base + DDR_PCTL2_MRCTRL0, 1u << 31); 5531881cdb1SYouMin Chen while (readl(pctl_base + DDR_PCTL2_MRCTRL0) & (1u << 31)) 5541881cdb1SYouMin Chen continue; 5551881cdb1SYouMin Chen while (readl(pctl_base + DDR_PCTL2_MRSTAT) & MR_WR_BUSY) 5561881cdb1SYouMin Chen continue; 5571881cdb1SYouMin Chen 5581881cdb1SYouMin Chen return 0; 5591881cdb1SYouMin Chen } 5601881cdb1SYouMin Chen 5611881cdb1SYouMin Chen /* 5621881cdb1SYouMin Chen * rank : 1:cs0, 2:cs1, 3:cs0&cs1 5631881cdb1SYouMin Chen * vrefrate: 4500: 45%, 5641881cdb1SYouMin Chen */ 5651881cdb1SYouMin Chen static int write_vrefdq(struct dram_info *dram, u32 rank, u32 vrefrate, 5661881cdb1SYouMin Chen u32 dramtype) 5671881cdb1SYouMin Chen { 5681881cdb1SYouMin Chen void __iomem *pctl_base = dram->pctl; 5691881cdb1SYouMin Chen u32 tccd_l, value; 5701881cdb1SYouMin Chen u32 dis_auto_zq = 0; 5711881cdb1SYouMin Chen 5721881cdb1SYouMin Chen if (dramtype != DDR4 || vrefrate < 4500 || 5731881cdb1SYouMin Chen vrefrate > 9200) 5741881cdb1SYouMin Chen return (-1); 5751881cdb1SYouMin Chen 5761881cdb1SYouMin Chen tccd_l = (readl(pctl_base + DDR_PCTL2_DRAMTMG4) >> 16) & 0xf; 5771881cdb1SYouMin Chen tccd_l = (tccd_l - 4) << 10; 5781881cdb1SYouMin Chen 5791881cdb1SYouMin Chen if (vrefrate > 7500) { 5801881cdb1SYouMin Chen /* range 1 */ 5811881cdb1SYouMin Chen value = ((vrefrate - 6000) / 65) | tccd_l; 5821881cdb1SYouMin Chen } else { 5831881cdb1SYouMin Chen /* range 2 */ 5841881cdb1SYouMin Chen value = ((vrefrate - 4500) / 65) | tccd_l | (1 << 6); 5851881cdb1SYouMin Chen } 5861881cdb1SYouMin Chen 5871881cdb1SYouMin Chen dis_auto_zq = disable_zqcs_arefresh(dram); 5881881cdb1SYouMin Chen 5891881cdb1SYouMin Chen /* enable vrefdq calibratin */ 5901881cdb1SYouMin Chen write_mr(dram, rank, 6, value | (1 << 7), dramtype); 5911881cdb1SYouMin Chen udelay(1);/* tvrefdqe */ 5921881cdb1SYouMin Chen /* write vrefdq value */ 5931881cdb1SYouMin Chen write_mr(dram, rank, 6, value | (1 << 7), dramtype); 5941881cdb1SYouMin Chen udelay(1);/* tvref_time */ 5951881cdb1SYouMin Chen write_mr(dram, rank, 6, value | (0 << 7), dramtype); 5961881cdb1SYouMin Chen udelay(1);/* tvrefdqx */ 5971881cdb1SYouMin Chen 5981881cdb1SYouMin Chen restore_zqcs_arefresh(dram, dis_auto_zq); 5991881cdb1SYouMin Chen 6001881cdb1SYouMin Chen return 0; 6011881cdb1SYouMin Chen } 6021881cdb1SYouMin Chen 6031881cdb1SYouMin Chen /* 6041881cdb1SYouMin Chen * cs: 0:cs0 6051881cdb1SYouMin Chen * 1:cs1 6061881cdb1SYouMin Chen * else cs0+cs1 6071881cdb1SYouMin Chen * note: it didn't consider about row_3_4 6081881cdb1SYouMin Chen */ 6091881cdb1SYouMin Chen u64 get_cs_cap(struct px30_sdram_params *sdram_params, u32 cs) 6101881cdb1SYouMin Chen { 6111881cdb1SYouMin Chen u32 bg; 6121881cdb1SYouMin Chen u64 cap[2]; 6131881cdb1SYouMin Chen 6141881cdb1SYouMin Chen if (sdram_params->dramtype == DDR4) 6151881cdb1SYouMin Chen /* DDR4 8bit dram BG = 2(4bank groups), 6161881cdb1SYouMin Chen * 16bit dram BG = 1 (2 bank groups) 6171881cdb1SYouMin Chen */ 6181881cdb1SYouMin Chen bg = (sdram_params->ch.dbw == 0) ? 2 : 1; 6191881cdb1SYouMin Chen else 6201881cdb1SYouMin Chen bg = 0; 6211881cdb1SYouMin Chen cap[0] = 1llu << (sdram_params->ch.bw + sdram_params->ch.col + 6221881cdb1SYouMin Chen bg + sdram_params->ch.bk + sdram_params->ch.cs0_row); 6231881cdb1SYouMin Chen 6241881cdb1SYouMin Chen if (sdram_params->ch.rank == 2) 6251881cdb1SYouMin Chen cap[1] = 1llu << (sdram_params->ch.bw + sdram_params->ch.col + 6261881cdb1SYouMin Chen bg + sdram_params->ch.bk + sdram_params->ch.cs1_row); 6271881cdb1SYouMin Chen else 6281881cdb1SYouMin Chen cap[1] = 0; 6291881cdb1SYouMin Chen 6301881cdb1SYouMin Chen if (cs == 0) 6311881cdb1SYouMin Chen return cap[0]; 6321881cdb1SYouMin Chen else if (cs == 1) 6331881cdb1SYouMin Chen return cap[1]; 6341881cdb1SYouMin Chen else 6351881cdb1SYouMin Chen return (cap[0] + cap[1]); 6361881cdb1SYouMin Chen } 6371881cdb1SYouMin Chen 6381881cdb1SYouMin Chen static void set_ddrconfig(struct dram_info *dram, u32 ddrconfig) 6391881cdb1SYouMin Chen { 6401881cdb1SYouMin Chen writel(ddrconfig | (ddrconfig << 8), &dram->msch->deviceconf); 6411881cdb1SYouMin Chen rk_clrsetreg(&dram->grf->soc_noc_con[1], 0x3 << 14, 0 << 14); 6421881cdb1SYouMin Chen } 6431881cdb1SYouMin Chen 6441881cdb1SYouMin Chen static void dram_all_config(struct dram_info *dram, 6451881cdb1SYouMin Chen struct px30_sdram_params *sdram_params) 6461881cdb1SYouMin Chen { 6471881cdb1SYouMin Chen u32 sys_reg = 0; 6481881cdb1SYouMin Chen u32 sys_reg3 = 0; 6491881cdb1SYouMin Chen u64 cs_cap[2]; 6501881cdb1SYouMin Chen 6511881cdb1SYouMin Chen set_ddrconfig(dram, sdram_params->ch.ddrconfig); 6521881cdb1SYouMin Chen 6531881cdb1SYouMin Chen sys_reg |= SYS_REG_ENC_DDRTYPE(sdram_params->dramtype); 6541881cdb1SYouMin Chen sys_reg |= SYS_REG_ENC_ROW_3_4(sdram_params->ch.row_3_4); 6551881cdb1SYouMin Chen sys_reg |= SYS_REG_ENC_RANK(sdram_params->ch.rank); 6561881cdb1SYouMin Chen sys_reg |= SYS_REG_ENC_COL(sdram_params->ch.col); 6571881cdb1SYouMin Chen sys_reg |= SYS_REG_ENC_BK(sdram_params->ch.bk); 6581881cdb1SYouMin Chen sys_reg |= SYS_REG_ENC_BW(sdram_params->ch.bw); 6591881cdb1SYouMin Chen sys_reg |= SYS_REG_ENC_DBW(sdram_params->ch.dbw); 6601881cdb1SYouMin Chen 6611881cdb1SYouMin Chen SYS_REG_ENC_CS0_ROW_(sdram_params->ch.cs0_row, sys_reg, sys_reg3); 6621881cdb1SYouMin Chen if (sdram_params->ch.cs1_row) 6631881cdb1SYouMin Chen SYS_REG_ENC_CS1_ROW_(sdram_params->ch.cs1_row, sys_reg, 6641881cdb1SYouMin Chen sys_reg3); 6651881cdb1SYouMin Chen sys_reg3 |= SYS_REG_ENC_CS1_COL(sdram_params->ch.col); 6661881cdb1SYouMin Chen sys_reg3 |= SYS_REG_ENC_VERSION(DDR_SYS_REG_VERSION); 6671881cdb1SYouMin Chen 6681881cdb1SYouMin Chen writel(sys_reg, &dram->pmugrf->os_reg[2]); 6691881cdb1SYouMin Chen writel(sys_reg3, &dram->pmugrf->os_reg[3]); 6701881cdb1SYouMin Chen 6711881cdb1SYouMin Chen cs_cap[0] = get_cs_cap(sdram_params, 0); 6721881cdb1SYouMin Chen cs_cap[1] = get_cs_cap(sdram_params, 1); 6731881cdb1SYouMin Chen writel(((((cs_cap[1] >> 20) / 64) & 0xff) << 8) | 6741881cdb1SYouMin Chen (((cs_cap[0] >> 20) / 64) & 0xff), 6751881cdb1SYouMin Chen &dram->msch->devicesize); 6761881cdb1SYouMin Chen 6771881cdb1SYouMin Chen writel(sdram_params->ch.noc_timings.ddrtiminga0.d32, 6781881cdb1SYouMin Chen &dram->msch->ddrtiminga0); 6791881cdb1SYouMin Chen writel(sdram_params->ch.noc_timings.ddrtimingb0.d32, 6801881cdb1SYouMin Chen &dram->msch->ddrtimingb0); 6811881cdb1SYouMin Chen writel(sdram_params->ch.noc_timings.ddrtimingc0.d32, 6821881cdb1SYouMin Chen &dram->msch->ddrtimingc0); 6831881cdb1SYouMin Chen writel(sdram_params->ch.noc_timings.devtodev0.d32, 6841881cdb1SYouMin Chen &dram->msch->devtodev0); 6851881cdb1SYouMin Chen writel(sdram_params->ch.noc_timings.ddrmode.d32, &dram->msch->ddrmode); 6861881cdb1SYouMin Chen writel(sdram_params->ch.noc_timings.ddr4timing.d32, 6871881cdb1SYouMin Chen &dram->msch->ddr4timing); 6881881cdb1SYouMin Chen writel(sdram_params->ch.noc_timings.agingx0, &dram->msch->agingx0); 6891881cdb1SYouMin Chen writel(sdram_params->ch.noc_timings.agingx0, &dram->msch->aging0); 6901881cdb1SYouMin Chen writel(sdram_params->ch.noc_timings.agingx0, &dram->msch->aging1); 6911881cdb1SYouMin Chen writel(sdram_params->ch.noc_timings.agingx0, &dram->msch->aging2); 6921881cdb1SYouMin Chen writel(sdram_params->ch.noc_timings.agingx0, &dram->msch->aging3); 6931881cdb1SYouMin Chen } 6941881cdb1SYouMin Chen 6951881cdb1SYouMin Chen static void enable_low_power(struct dram_info *dram, 6961881cdb1SYouMin Chen struct px30_sdram_params *sdram_params) 6971881cdb1SYouMin Chen { 6981881cdb1SYouMin Chen void __iomem *pctl_base = dram->pctl; 699a82a427dSYouMin Chen void __iomem *phy_base = dram->phy; 7001881cdb1SYouMin Chen void __iomem *ddr_grf_base = dram->ddr_grf; 7011881cdb1SYouMin Chen u32 grf_lp_con; 7021881cdb1SYouMin Chen 7031881cdb1SYouMin Chen /* 7041881cdb1SYouMin Chen * bit0: grf_upctl_axi_cg_en = 1 enable upctl2 axi clk auto gating 7051881cdb1SYouMin Chen * bit1: grf_upctl_apb_cg_en = 1 ungated axi,core clk for apb access 7061881cdb1SYouMin Chen * bit2: grf_upctl_core_cg_en = 1 enable upctl2 core clk auto gating 7071881cdb1SYouMin Chen * bit3: grf_selfref_type2_en = 0 disable core clk gating when type2 sr 7081881cdb1SYouMin Chen * bit4: grf_upctl_syscreq_cg_en = 1 7091881cdb1SYouMin Chen * ungating coreclk when c_sysreq assert 7101881cdb1SYouMin Chen * bit8-11: grf_auto_sr_dly = 6 7111881cdb1SYouMin Chen */ 7121881cdb1SYouMin Chen writel(0x1f1f0617, &dram->ddr_grf->ddr_grf_con[1]); 7131881cdb1SYouMin Chen 7141881cdb1SYouMin Chen if (sdram_params->dramtype == DDR4) 7151881cdb1SYouMin Chen grf_lp_con = (0x7 << 16) | (1 << 1); 7161881cdb1SYouMin Chen else if (sdram_params->dramtype == DDR3) 7171881cdb1SYouMin Chen grf_lp_con = (0x7 << 16) | (1 << 0); 7181881cdb1SYouMin Chen else 7191881cdb1SYouMin Chen grf_lp_con = (0x7 << 16) | (1 << 2); 7201881cdb1SYouMin Chen 7211881cdb1SYouMin Chen /* en lpckdis_en */ 7221881cdb1SYouMin Chen grf_lp_con = grf_lp_con | (0x1 << (9 + 16)) | (0x1 << 9); 7231881cdb1SYouMin Chen writel(grf_lp_con, ddr_grf_base + DDR_GRF_LP_CON); 7241881cdb1SYouMin Chen 725a82a427dSYouMin Chen /* off digit module clock when enter power down */ 726a82a427dSYouMin Chen setbits_le32(PHY_REG(phy_base, 7), 1 << 7); 727a82a427dSYouMin Chen 7281881cdb1SYouMin Chen /* enable sr, pd */ 7291881cdb1SYouMin Chen if (PD_IDLE == 0) 7301881cdb1SYouMin Chen clrbits_le32(pctl_base + DDR_PCTL2_PWRCTL, (1 << 1)); 7311881cdb1SYouMin Chen else 7321881cdb1SYouMin Chen setbits_le32(pctl_base + DDR_PCTL2_PWRCTL, (1 << 1)); 7331881cdb1SYouMin Chen if (SR_IDLE == 0) 7341881cdb1SYouMin Chen clrbits_le32(pctl_base + DDR_PCTL2_PWRCTL, 1); 7351881cdb1SYouMin Chen else 7361881cdb1SYouMin Chen setbits_le32(pctl_base + DDR_PCTL2_PWRCTL, 1); 7371881cdb1SYouMin Chen setbits_le32(pctl_base + DDR_PCTL2_PWRCTL, (1 << 3)); 7381881cdb1SYouMin Chen } 7391881cdb1SYouMin Chen 740504e252fSYouMin Chen static void print_ddr_info(struct px30_sdram_params *sdram_params) 7411881cdb1SYouMin Chen { 742504e252fSYouMin Chen u64 cap; 743504e252fSYouMin Chen u32 bg; 744504e252fSYouMin Chen u32 split; 7451881cdb1SYouMin Chen 746504e252fSYouMin Chen split = readl(DDR_GRF_BASE_ADDR + DDR_GRF_SPLIT_CON); 747504e252fSYouMin Chen bg = (sdram_params->ch.dbw == 0) ? 2 : 1; 748504e252fSYouMin Chen switch (sdram_params->dramtype) { 749504e252fSYouMin Chen case LPDDR3: 750504e252fSYouMin Chen printascii("LPDDR3\n"); 751504e252fSYouMin Chen break; 752504e252fSYouMin Chen case DDR3: 753504e252fSYouMin Chen printascii("DDR3\n"); 754504e252fSYouMin Chen break; 755504e252fSYouMin Chen case DDR4: 756504e252fSYouMin Chen printascii("DDR4\n"); 757504e252fSYouMin Chen break; 758504e252fSYouMin Chen case LPDDR2: 759504e252fSYouMin Chen printascii("LPDDR2\n"); 760504e252fSYouMin Chen break; 761504e252fSYouMin Chen default: 762504e252fSYouMin Chen printascii("Unknown Device\n"); 763504e252fSYouMin Chen break; 764504e252fSYouMin Chen } 7651881cdb1SYouMin Chen 766504e252fSYouMin Chen printdec(sdram_params->ddr_freq); 767504e252fSYouMin Chen printascii("MHz\n"); 768504e252fSYouMin Chen printascii("BW="); 769504e252fSYouMin Chen printdec(8 << sdram_params->ch.bw); 770504e252fSYouMin Chen printascii(" Col="); 771504e252fSYouMin Chen printdec(sdram_params->ch.col); 772504e252fSYouMin Chen printascii(" Bk="); 773504e252fSYouMin Chen printdec(0x1 << sdram_params->ch.bk); 774504e252fSYouMin Chen if (sdram_params->dramtype == DDR4) { 775504e252fSYouMin Chen printascii(" BG="); 776504e252fSYouMin Chen printdec(1 << bg); 777504e252fSYouMin Chen } 778504e252fSYouMin Chen printascii(" CS0 Row="); 779504e252fSYouMin Chen printdec(sdram_params->ch.cs0_row); 780504e252fSYouMin Chen if (sdram_params->ch.cs0_high16bit_row != 781504e252fSYouMin Chen sdram_params->ch.cs0_row) { 782504e252fSYouMin Chen printascii("/"); 783504e252fSYouMin Chen printdec(sdram_params->ch.cs0_high16bit_row); 784504e252fSYouMin Chen } 785504e252fSYouMin Chen if (sdram_params->ch.rank > 1) { 786504e252fSYouMin Chen printascii(" CS1 Row="); 787504e252fSYouMin Chen printdec(sdram_params->ch.cs1_row); 788504e252fSYouMin Chen if (sdram_params->ch.cs1_high16bit_row != 789504e252fSYouMin Chen sdram_params->ch.cs1_row) { 790504e252fSYouMin Chen printascii("/"); 791504e252fSYouMin Chen printdec(sdram_params->ch.cs1_high16bit_row); 792504e252fSYouMin Chen } 793504e252fSYouMin Chen } 794504e252fSYouMin Chen printascii(" CS="); 795504e252fSYouMin Chen printdec(sdram_params->ch.rank); 796504e252fSYouMin Chen printascii(" Die BW="); 797504e252fSYouMin Chen printdec(8 << sdram_params->ch.dbw); 798504e252fSYouMin Chen 799504e252fSYouMin Chen cap = get_cs_cap(sdram_params, 3); 800504e252fSYouMin Chen if (sdram_params->ch.row_3_4) 801504e252fSYouMin Chen cap = cap * 3 / 4; 802504e252fSYouMin Chen else if (!(split & (1 << SPLIT_BYPASS_OFFSET))) 803504e252fSYouMin Chen cap = cap / 2 + ((split & 0xff) << 24) / 2; 804504e252fSYouMin Chen 805504e252fSYouMin Chen printascii(" Size="); 806504e252fSYouMin Chen printdec(cap >> 20); 807504e252fSYouMin Chen printascii("MB\n"); 8081881cdb1SYouMin Chen } 8091881cdb1SYouMin Chen 8101881cdb1SYouMin Chen /* 8111881cdb1SYouMin Chen * pre_init: 0: pre init for dram cap detect 8121881cdb1SYouMin Chen * 1: detect correct cap(except cs1 row)info, than reinit 8131881cdb1SYouMin Chen * 2: after reinit, we detect cs1_row, if cs1_row not equal 8141881cdb1SYouMin Chen * to cs0_row and cs is in middle on ddrconf map, we need 8151881cdb1SYouMin Chen * to reinit dram, than set the correct ddrconf. 8161881cdb1SYouMin Chen */ 8171881cdb1SYouMin Chen static int sdram_init_(struct dram_info *dram, 8181881cdb1SYouMin Chen struct px30_sdram_params *sdram_params, u32 pre_init) 8191881cdb1SYouMin Chen { 8201881cdb1SYouMin Chen void __iomem *pctl_base = dram->pctl; 8211881cdb1SYouMin Chen 8221881cdb1SYouMin Chen rkclk_ddr_reset(dram, 1, 1, 1, 1); 8231881cdb1SYouMin Chen udelay(10); 8241881cdb1SYouMin Chen /* 8251881cdb1SYouMin Chen * dereset ddr phy psrstn to config pll, 8261881cdb1SYouMin Chen * if using phy pll psrstn must be dereset 8271881cdb1SYouMin Chen * before config pll 8281881cdb1SYouMin Chen */ 8291881cdb1SYouMin Chen rkclk_ddr_reset(dram, 1, 1, 1, 0); 8301881cdb1SYouMin Chen rkclk_configure_ddr(dram, sdram_params); 8311881cdb1SYouMin Chen 8321881cdb1SYouMin Chen /* release phy srst to provide clk to ctrl */ 8331881cdb1SYouMin Chen rkclk_ddr_reset(dram, 1, 1, 0, 0); 8341881cdb1SYouMin Chen udelay(10); 8351881cdb1SYouMin Chen phy_soft_reset(dram); 8361881cdb1SYouMin Chen /* release ctrl presetn, and config ctl registers */ 8371881cdb1SYouMin Chen rkclk_ddr_reset(dram, 1, 0, 0, 0); 8381881cdb1SYouMin Chen pctl_cfg(dram, sdram_params); 8391881cdb1SYouMin Chen sdram_params->ch.ddrconfig = calculate_ddrconfig(sdram_params); 8401881cdb1SYouMin Chen set_ctl_address_map(dram, sdram_params); 8411881cdb1SYouMin Chen phy_cfg(dram, sdram_params); 8421881cdb1SYouMin Chen 8431881cdb1SYouMin Chen /* enable dfi_init_start to init phy after ctl srstn deassert */ 8441881cdb1SYouMin Chen setbits_le32(pctl_base + DDR_PCTL2_DFIMISC, (1 << 5) | (1 << 4)); 8451881cdb1SYouMin Chen 8461881cdb1SYouMin Chen rkclk_ddr_reset(dram, 0, 0, 0, 0); 8471881cdb1SYouMin Chen /* wait for dfi_init_done and dram init complete */ 8481881cdb1SYouMin Chen while ((readl(pctl_base + DDR_PCTL2_STAT) & 0x7) == 0) 8491881cdb1SYouMin Chen continue; 8501881cdb1SYouMin Chen 8511881cdb1SYouMin Chen if (sdram_params->dramtype == LPDDR3) 8521881cdb1SYouMin Chen write_mr(dram, 3, 11, 3, LPDDR3); 8531881cdb1SYouMin Chen 8541881cdb1SYouMin Chen /* do ddr gate training */ 8551881cdb1SYouMin Chen redo_cs0_training: 8561881cdb1SYouMin Chen if (data_training(dram, 0, sdram_params->dramtype) != 0) { 8571881cdb1SYouMin Chen if (pre_init != 0) 8581881cdb1SYouMin Chen printascii("DTT cs0 error\n"); 8591881cdb1SYouMin Chen return -1; 8601881cdb1SYouMin Chen } 8611881cdb1SYouMin Chen if (check_rd_gate(dram)) { 8621881cdb1SYouMin Chen printascii("re training cs0"); 8631881cdb1SYouMin Chen goto redo_cs0_training; 8641881cdb1SYouMin Chen } 8651881cdb1SYouMin Chen 8661881cdb1SYouMin Chen if (sdram_params->dramtype == LPDDR3) { 8671881cdb1SYouMin Chen if ((read_mr(dram, 1, 8) & 0x3) != 0x3) 8681881cdb1SYouMin Chen return -1; 8691881cdb1SYouMin Chen } else if (sdram_params->dramtype == LPDDR2) { 8701881cdb1SYouMin Chen if ((read_mr(dram, 1, 8) & 0x3) != 0x0) 8711881cdb1SYouMin Chen return -1; 8721881cdb1SYouMin Chen } 8731881cdb1SYouMin Chen /* for px30: when 2cs, both 2 cs should be training */ 8741881cdb1SYouMin Chen if (pre_init != 0 && sdram_params->ch.rank == 2) { 8751881cdb1SYouMin Chen redo_cs1_training: 8761881cdb1SYouMin Chen if (data_training(dram, 1, sdram_params->dramtype) != 0) { 8771881cdb1SYouMin Chen printascii("DTT cs1 error\n"); 8781881cdb1SYouMin Chen return -1; 8791881cdb1SYouMin Chen } 8801881cdb1SYouMin Chen if (check_rd_gate(dram)) { 8811881cdb1SYouMin Chen printascii("re training cs1"); 8821881cdb1SYouMin Chen goto redo_cs1_training; 8831881cdb1SYouMin Chen } 8841881cdb1SYouMin Chen } 8851881cdb1SYouMin Chen 8861881cdb1SYouMin Chen if (sdram_params->dramtype == DDR4) 8871881cdb1SYouMin Chen write_vrefdq(dram, 0x3, 5670, sdram_params->dramtype); 8881881cdb1SYouMin Chen 8891881cdb1SYouMin Chen dram_all_config(dram, sdram_params); 8901881cdb1SYouMin Chen enable_low_power(dram, sdram_params); 8911881cdb1SYouMin Chen 8921881cdb1SYouMin Chen return 0; 8931881cdb1SYouMin Chen } 8941881cdb1SYouMin Chen 8951881cdb1SYouMin Chen static u64 dram_detect_cap(struct dram_info *dram, 8961881cdb1SYouMin Chen struct px30_sdram_params *sdram_params, 8971881cdb1SYouMin Chen unsigned char channel) 8981881cdb1SYouMin Chen { 8991881cdb1SYouMin Chen void __iomem *pctl_base = dram->pctl; 9001881cdb1SYouMin Chen void __iomem *phy_base = dram->phy; 9011881cdb1SYouMin Chen 9021881cdb1SYouMin Chen /* 9031881cdb1SYouMin Chen * for ddr3: ddrconf = 3 9041881cdb1SYouMin Chen * for ddr4: ddrconf = 12 9051881cdb1SYouMin Chen * for lpddr3: ddrconf = 3 9061881cdb1SYouMin Chen * default bw = 1 9071881cdb1SYouMin Chen */ 9081881cdb1SYouMin Chen u32 bk, bktmp; 9091881cdb1SYouMin Chen u32 col, coltmp; 9101881cdb1SYouMin Chen u32 row, rowtmp, row_3_4; 9111881cdb1SYouMin Chen void __iomem *test_addr, *test_addr1; 9121881cdb1SYouMin Chen u32 dbw; 9131881cdb1SYouMin Chen u32 cs; 9141881cdb1SYouMin Chen u32 bw = 1; 9151881cdb1SYouMin Chen u64 cap = 0; 9161881cdb1SYouMin Chen u32 dram_type = sdram_params->dramtype; 9171881cdb1SYouMin Chen u32 pwrctl; 9181881cdb1SYouMin Chen 9191881cdb1SYouMin Chen if (dram_type != DDR4) { 9201881cdb1SYouMin Chen /* detect col and bk for ddr3/lpddr3 */ 9211881cdb1SYouMin Chen coltmp = 12; 9221881cdb1SYouMin Chen bktmp = 3; 923*f588f59eSYouMin Chen if (dram_type == LPDDR2) 924*f588f59eSYouMin Chen rowtmp = 15; 925*f588f59eSYouMin Chen else 9261881cdb1SYouMin Chen rowtmp = 16; 9271881cdb1SYouMin Chen 9281881cdb1SYouMin Chen for (col = coltmp; col >= 9; col -= 1) { 9291881cdb1SYouMin Chen writel(0, CONFIG_SYS_SDRAM_BASE); 9301881cdb1SYouMin Chen test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE + 9311881cdb1SYouMin Chen (1ul << (col + bw - 1ul))); 9321881cdb1SYouMin Chen writel(PATTERN, test_addr); 9331881cdb1SYouMin Chen if ((readl(test_addr) == PATTERN) && 9341881cdb1SYouMin Chen (readl(CONFIG_SYS_SDRAM_BASE) == 0)) 9351881cdb1SYouMin Chen break; 9361881cdb1SYouMin Chen } 9371881cdb1SYouMin Chen if (col == 8) { 9381881cdb1SYouMin Chen printascii("col error\n"); 9391881cdb1SYouMin Chen goto cap_err; 9401881cdb1SYouMin Chen } 9411881cdb1SYouMin Chen 9421881cdb1SYouMin Chen test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE + 9431881cdb1SYouMin Chen (1ul << (coltmp + bktmp + bw - 1ul))); 9441881cdb1SYouMin Chen writel(0, CONFIG_SYS_SDRAM_BASE); 9451881cdb1SYouMin Chen writel(PATTERN, test_addr); 9461881cdb1SYouMin Chen if ((readl(test_addr) == PATTERN) && 9471881cdb1SYouMin Chen (readl(CONFIG_SYS_SDRAM_BASE) == 0)) 9481881cdb1SYouMin Chen bk = 3; 9491881cdb1SYouMin Chen else 9501881cdb1SYouMin Chen bk = 2; 9511881cdb1SYouMin Chen if (dram_type == DDR3) 9521881cdb1SYouMin Chen dbw = 1; 9531881cdb1SYouMin Chen else 9541881cdb1SYouMin Chen dbw = 2; 9551881cdb1SYouMin Chen } else { 9561881cdb1SYouMin Chen /* detect bg for ddr4 */ 9571881cdb1SYouMin Chen coltmp = 10; 9581881cdb1SYouMin Chen bktmp = 4; 9591881cdb1SYouMin Chen rowtmp = 17; 9601881cdb1SYouMin Chen 9611881cdb1SYouMin Chen col = 10; 9621881cdb1SYouMin Chen bk = 2; 9631881cdb1SYouMin Chen test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE + 9641881cdb1SYouMin Chen (1ul << (coltmp + bw + 1ul))); 9651881cdb1SYouMin Chen writel(0, CONFIG_SYS_SDRAM_BASE); 9661881cdb1SYouMin Chen writel(PATTERN, test_addr); 9671881cdb1SYouMin Chen if ((readl(test_addr) == PATTERN) && 9681881cdb1SYouMin Chen (readl(CONFIG_SYS_SDRAM_BASE) == 0)) 9691881cdb1SYouMin Chen dbw = 0; 9701881cdb1SYouMin Chen else 9711881cdb1SYouMin Chen dbw = 1; 9721881cdb1SYouMin Chen } 9731881cdb1SYouMin Chen /* detect row */ 9741881cdb1SYouMin Chen for (row = rowtmp; row > 12; row--) { 9751881cdb1SYouMin Chen writel(0, CONFIG_SYS_SDRAM_BASE); 9761881cdb1SYouMin Chen test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE + 9771881cdb1SYouMin Chen (1ul << (row + bktmp + coltmp + bw - 1ul))); 9781881cdb1SYouMin Chen writel(PATTERN, test_addr); 9791881cdb1SYouMin Chen if ((readl(test_addr) == PATTERN) && 9801881cdb1SYouMin Chen (readl(CONFIG_SYS_SDRAM_BASE) == 0)) 9811881cdb1SYouMin Chen break; 9821881cdb1SYouMin Chen } 9831881cdb1SYouMin Chen if (row == 12) { 9841881cdb1SYouMin Chen printascii("row error"); 9851881cdb1SYouMin Chen goto cap_err; 9861881cdb1SYouMin Chen } 9871881cdb1SYouMin Chen /* detect row_3_4 */ 9881881cdb1SYouMin Chen test_addr = CONFIG_SYS_SDRAM_BASE; 9891881cdb1SYouMin Chen test_addr1 = (void __iomem *)(CONFIG_SYS_SDRAM_BASE + 9901881cdb1SYouMin Chen (0x3ul << (row + bktmp + coltmp + bw - 1ul - 1ul))); 9911881cdb1SYouMin Chen 9921881cdb1SYouMin Chen writel(0, test_addr); 9931881cdb1SYouMin Chen writel(PATTERN, test_addr1); 9941881cdb1SYouMin Chen if ((readl(test_addr) == 0) && 9951881cdb1SYouMin Chen (readl(test_addr1) == PATTERN)) 9961881cdb1SYouMin Chen row_3_4 = 0; 9971881cdb1SYouMin Chen else 9981881cdb1SYouMin Chen row_3_4 = 1; 9991881cdb1SYouMin Chen 10001881cdb1SYouMin Chen /* disable auto low-power */ 10011881cdb1SYouMin Chen pwrctl = readl(pctl_base + DDR_PCTL2_PWRCTL); 10021881cdb1SYouMin Chen writel(0, pctl_base + DDR_PCTL2_PWRCTL); 10031881cdb1SYouMin Chen 10041881cdb1SYouMin Chen /* bw and cs detect using phy read gate training */ 10051881cdb1SYouMin Chen if (data_training(dram, 1, dram_type) == 0) 10061881cdb1SYouMin Chen cs = 1; 10071881cdb1SYouMin Chen else 10081881cdb1SYouMin Chen cs = 0; 10091881cdb1SYouMin Chen 10101881cdb1SYouMin Chen clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 0xf << 4); 10111881cdb1SYouMin Chen setbits_le32(PHY_REG(phy_base, 0x46), 1 << 3); 10121881cdb1SYouMin Chen setbits_le32(PHY_REG(phy_base, 0x56), 1 << 3); 10131881cdb1SYouMin Chen 10141881cdb1SYouMin Chen phy_soft_reset(dram); 10151881cdb1SYouMin Chen 10161881cdb1SYouMin Chen if (data_training(dram, 0, dram_type) == 0) 10171881cdb1SYouMin Chen bw = 2; 10181881cdb1SYouMin Chen else 10191881cdb1SYouMin Chen bw = 1; 10201881cdb1SYouMin Chen 10211881cdb1SYouMin Chen /* restore auto low-power */ 10221881cdb1SYouMin Chen writel(pwrctl, pctl_base + DDR_PCTL2_PWRCTL); 10231881cdb1SYouMin Chen 10241881cdb1SYouMin Chen sdram_params->ch.rank = cs + 1; 10251881cdb1SYouMin Chen sdram_params->ch.col = col; 10261881cdb1SYouMin Chen sdram_params->ch.bk = bk; 10271881cdb1SYouMin Chen sdram_params->ch.dbw = dbw; 10281881cdb1SYouMin Chen sdram_params->ch.bw = bw; 10291881cdb1SYouMin Chen sdram_params->ch.cs0_row = row; 10301881cdb1SYouMin Chen sdram_params->ch.cs0_high16bit_row = row; 10311881cdb1SYouMin Chen if (cs) { 10321881cdb1SYouMin Chen sdram_params->ch.cs1_row = row; 10331881cdb1SYouMin Chen sdram_params->ch.cs1_high16bit_row = row; 10341881cdb1SYouMin Chen } else { 10351881cdb1SYouMin Chen sdram_params->ch.cs1_row = 0; 10361881cdb1SYouMin Chen sdram_params->ch.cs1_high16bit_row = 0; 10371881cdb1SYouMin Chen } 10381881cdb1SYouMin Chen sdram_params->ch.row_3_4 = row_3_4; 10391881cdb1SYouMin Chen 10401881cdb1SYouMin Chen if (dram_type == DDR4) 10411881cdb1SYouMin Chen cap = 1llu << (cs + row + bk + col + ((dbw == 0) ? 2 : 1) + bw); 10421881cdb1SYouMin Chen else 10431881cdb1SYouMin Chen cap = 1llu << (cs + row + bk + col + bw); 10441881cdb1SYouMin Chen 10451881cdb1SYouMin Chen return cap; 10461881cdb1SYouMin Chen 10471881cdb1SYouMin Chen cap_err: 10481881cdb1SYouMin Chen return 0; 10491881cdb1SYouMin Chen } 10501881cdb1SYouMin Chen 10511881cdb1SYouMin Chen static u32 remodify_sdram_params(struct px30_sdram_params *sdram_params) 10521881cdb1SYouMin Chen { 10531881cdb1SYouMin Chen u32 tmp = 0, tmp_adr = 0, i; 10541881cdb1SYouMin Chen 10551881cdb1SYouMin Chen for (i = 0; sdram_params->pctl_regs.pctl[i][0] != 0xFFFFFFFF; i++) { 10561881cdb1SYouMin Chen if (sdram_params->pctl_regs.pctl[i][0] == 0) { 10571881cdb1SYouMin Chen tmp = sdram_params->pctl_regs.pctl[i][1];/* MSTR */ 10581881cdb1SYouMin Chen tmp_adr = i; 10591881cdb1SYouMin Chen } 10601881cdb1SYouMin Chen } 10611881cdb1SYouMin Chen 10621881cdb1SYouMin Chen tmp &= ~((3ul << 30) | (3ul << 24) | (3ul << 12)); 10631881cdb1SYouMin Chen 10641881cdb1SYouMin Chen switch (sdram_params->ch.dbw) { 10651881cdb1SYouMin Chen case 2: 10661881cdb1SYouMin Chen tmp |= (3ul << 30); 10671881cdb1SYouMin Chen break; 10681881cdb1SYouMin Chen case 1: 10691881cdb1SYouMin Chen tmp |= (2ul << 30); 10701881cdb1SYouMin Chen break; 10711881cdb1SYouMin Chen case 0: 10721881cdb1SYouMin Chen default: 10731881cdb1SYouMin Chen tmp |= (1ul << 30); 10741881cdb1SYouMin Chen break; 10751881cdb1SYouMin Chen } 10761881cdb1SYouMin Chen 1077175c2742SYouMin Chen /* 1078175c2742SYouMin Chen * If DDR3 or DDR4 MSTR.active_ranks=1, 1079175c2742SYouMin Chen * it will gate memory clock when enter power down. 1080175c2742SYouMin Chen * Force set active_ranks to 3 to workaround it. 1081175c2742SYouMin Chen */ 1082175c2742SYouMin Chen if (sdram_params->ch.rank == 2 || sdram_params->dramtype == DDR3 || 1083175c2742SYouMin Chen sdram_params->dramtype == DDR4) 10841881cdb1SYouMin Chen tmp |= 3 << 24; 10851881cdb1SYouMin Chen else 10861881cdb1SYouMin Chen tmp |= 1 << 24; 10871881cdb1SYouMin Chen 10881881cdb1SYouMin Chen tmp |= (2 - sdram_params->ch.bw) << 12; 10891881cdb1SYouMin Chen 10901881cdb1SYouMin Chen sdram_params->pctl_regs.pctl[tmp_adr][1] = tmp; 10911881cdb1SYouMin Chen 10921881cdb1SYouMin Chen return 0; 10931881cdb1SYouMin Chen } 10941881cdb1SYouMin Chen 10951881cdb1SYouMin Chen int dram_detect_high_row(struct dram_info *dram, 10961881cdb1SYouMin Chen struct px30_sdram_params *sdram_params, 10971881cdb1SYouMin Chen unsigned char channel) 10981881cdb1SYouMin Chen { 10991881cdb1SYouMin Chen sdram_params->ch.cs0_high16bit_row = sdram_params->ch.cs0_row; 11001881cdb1SYouMin Chen sdram_params->ch.cs1_high16bit_row = sdram_params->ch.cs1_row; 11011881cdb1SYouMin Chen 11021881cdb1SYouMin Chen return 0; 11031881cdb1SYouMin Chen } 11041881cdb1SYouMin Chen 11051881cdb1SYouMin Chen static int dram_detect_cs1_row(struct px30_sdram_params *sdram_params, 11061881cdb1SYouMin Chen unsigned char channel) 11071881cdb1SYouMin Chen { 11081881cdb1SYouMin Chen u32 ret = 0; 11091881cdb1SYouMin Chen void __iomem *test_addr; 11101881cdb1SYouMin Chen u32 row, bktmp, coltmp, bw; 11111881cdb1SYouMin Chen u64 cs0_cap; 11121881cdb1SYouMin Chen u32 byte_mask; 11131881cdb1SYouMin Chen 11141881cdb1SYouMin Chen if (sdram_params->ch.rank == 2) { 11151881cdb1SYouMin Chen cs0_cap = get_cs_cap(sdram_params, 0); 11161881cdb1SYouMin Chen 11171881cdb1SYouMin Chen if (sdram_params->dramtype == DDR4) { 11181881cdb1SYouMin Chen if (sdram_params->ch.dbw == 0) 11191881cdb1SYouMin Chen bktmp = sdram_params->ch.bk + 2; 11201881cdb1SYouMin Chen else 11211881cdb1SYouMin Chen bktmp = sdram_params->ch.bk + 1; 11221881cdb1SYouMin Chen } else { 11231881cdb1SYouMin Chen bktmp = sdram_params->ch.bk; 11241881cdb1SYouMin Chen } 11251881cdb1SYouMin Chen bw = sdram_params->ch.bw; 11261881cdb1SYouMin Chen coltmp = sdram_params->ch.col; 11271881cdb1SYouMin Chen 11281881cdb1SYouMin Chen /* 11291881cdb1SYouMin Chen * because px30 support axi split,min bandwidth 11301881cdb1SYouMin Chen * is 8bit. if cs0 is 32bit, cs1 may 32bit or 16bit 11311881cdb1SYouMin Chen * so we check low 16bit data when detect cs1 row. 11321881cdb1SYouMin Chen * if cs0 is 16bit/8bit, we check low 8bit data. 11331881cdb1SYouMin Chen */ 11341881cdb1SYouMin Chen if (bw == 2) 11351881cdb1SYouMin Chen byte_mask = 0xFFFF; 11361881cdb1SYouMin Chen else 11371881cdb1SYouMin Chen byte_mask = 0xFF; 11381881cdb1SYouMin Chen 11391881cdb1SYouMin Chen /* detect cs1 row */ 11401881cdb1SYouMin Chen for (row = sdram_params->ch.cs0_row; row > 12; row--) { 11411881cdb1SYouMin Chen test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE + 11421881cdb1SYouMin Chen cs0_cap + 11431881cdb1SYouMin Chen (1ul << (row + bktmp + coltmp + bw - 1ul))); 11441881cdb1SYouMin Chen writel(0, CONFIG_SYS_SDRAM_BASE + cs0_cap); 11451881cdb1SYouMin Chen writel(PATTERN, test_addr); 11461881cdb1SYouMin Chen 11471881cdb1SYouMin Chen if (((readl(test_addr) & byte_mask) == 11481881cdb1SYouMin Chen (PATTERN & byte_mask)) && 11491881cdb1SYouMin Chen ((readl(CONFIG_SYS_SDRAM_BASE + cs0_cap) & 11501881cdb1SYouMin Chen byte_mask) == 0)) { 11511881cdb1SYouMin Chen ret = row; 11521881cdb1SYouMin Chen break; 11531881cdb1SYouMin Chen } 11541881cdb1SYouMin Chen } 11551881cdb1SYouMin Chen } 11561881cdb1SYouMin Chen 11571881cdb1SYouMin Chen return ret; 11581881cdb1SYouMin Chen } 11591881cdb1SYouMin Chen 11601881cdb1SYouMin Chen /* return: 0 = success, other = fail */ 11611881cdb1SYouMin Chen static int sdram_init_detect(struct dram_info *dram, 11621881cdb1SYouMin Chen struct px30_sdram_params *sdram_params) 11631881cdb1SYouMin Chen { 11641881cdb1SYouMin Chen u32 ret; 11651881cdb1SYouMin Chen u32 sys_reg = 0; 11661881cdb1SYouMin Chen u32 sys_reg3 = 0; 11671881cdb1SYouMin Chen 11681881cdb1SYouMin Chen if (sdram_init_(dram, sdram_params, 0) != 0) 11691881cdb1SYouMin Chen return -1; 11701881cdb1SYouMin Chen 11711881cdb1SYouMin Chen if (dram_detect_cap(dram, sdram_params, 0) == 0) 11721881cdb1SYouMin Chen return -1; 11731881cdb1SYouMin Chen 11741881cdb1SYouMin Chen /* modify bw, cs related timing */ 11751881cdb1SYouMin Chen remodify_sdram_params(sdram_params); 11761881cdb1SYouMin Chen /* reinit sdram by real dram cap */ 11771881cdb1SYouMin Chen ret = sdram_init_(dram, sdram_params, 1); 11781881cdb1SYouMin Chen if (ret != 0) 11791881cdb1SYouMin Chen goto out; 11801881cdb1SYouMin Chen 11811881cdb1SYouMin Chen /* redetect cs1 row */ 11821881cdb1SYouMin Chen sdram_params->ch.cs1_row = 11831881cdb1SYouMin Chen dram_detect_cs1_row(sdram_params, 0); 11841881cdb1SYouMin Chen if (sdram_params->ch.cs1_row) { 11851881cdb1SYouMin Chen sys_reg = readl(&dram->pmugrf->os_reg[2]); 11861881cdb1SYouMin Chen sys_reg3 = readl(&dram->pmugrf->os_reg[3]); 11871881cdb1SYouMin Chen SYS_REG_ENC_CS1_ROW_(sdram_params->ch.cs1_row, 11881881cdb1SYouMin Chen sys_reg, sys_reg3); 11891881cdb1SYouMin Chen writel(sys_reg, &dram->pmugrf->os_reg[2]); 11901881cdb1SYouMin Chen writel(sys_reg3, &dram->pmugrf->os_reg[3]); 11911881cdb1SYouMin Chen } 11921881cdb1SYouMin Chen 11931881cdb1SYouMin Chen ret = dram_detect_high_row(dram, sdram_params, 0); 11941881cdb1SYouMin Chen 11951881cdb1SYouMin Chen out: 11961881cdb1SYouMin Chen return ret; 11971881cdb1SYouMin Chen } 11981881cdb1SYouMin Chen 11991881cdb1SYouMin Chen struct px30_sdram_params 12001881cdb1SYouMin Chen *get_default_sdram_config(void) 12011881cdb1SYouMin Chen { 12021881cdb1SYouMin Chen sdram_configs[0].skew = &skew; 12031881cdb1SYouMin Chen 12041881cdb1SYouMin Chen return &sdram_configs[0]; 12051881cdb1SYouMin Chen } 12061881cdb1SYouMin Chen 12071881cdb1SYouMin Chen /* return: 0 = success, other = fail */ 12081881cdb1SYouMin Chen int sdram_init(void) 12091881cdb1SYouMin Chen { 12101881cdb1SYouMin Chen struct px30_sdram_params *sdram_params; 12111881cdb1SYouMin Chen int ret = 0; 12121881cdb1SYouMin Chen 12131881cdb1SYouMin Chen dram_info.phy = (void *)DDR_PHY_BASE_ADDR; 12141881cdb1SYouMin Chen dram_info.pctl = (void *)DDRC_BASE_ADDR; 12151881cdb1SYouMin Chen dram_info.grf = (void *)GRF_BASE_ADDR; 12161881cdb1SYouMin Chen dram_info.cru = (void *)CRU_BASE_ADDR; 12171881cdb1SYouMin Chen dram_info.msch = (void *)SERVER_MSCH0_BASE_ADDR; 12181881cdb1SYouMin Chen dram_info.ddr_grf = (void *)DDR_GRF_BASE_ADDR; 12191881cdb1SYouMin Chen dram_info.pmugrf = (void *)PMUGRF_BASE_ADDR; 12201881cdb1SYouMin Chen 12211881cdb1SYouMin Chen sdram_params = get_default_sdram_config(); 12221881cdb1SYouMin Chen ret = sdram_init_detect(&dram_info, sdram_params); 12231881cdb1SYouMin Chen 12241881cdb1SYouMin Chen if (ret) 12251881cdb1SYouMin Chen goto error; 12261881cdb1SYouMin Chen 1227504e252fSYouMin Chen print_ddr_info(sdram_params); 1228504e252fSYouMin Chen 12291881cdb1SYouMin Chen printascii("out\n"); 12301881cdb1SYouMin Chen return ret; 12311881cdb1SYouMin Chen error: 12321881cdb1SYouMin Chen return (-1); 12331881cdb1SYouMin Chen } 12341881cdb1SYouMin Chen #endif /* CONFIG_TPL_BUILD */ 1235