1*1881cdb1SYouMin Chen // SPDX-License-Identifier: GPL-2.0 25eeb396bSKever Yang /* 3*1881cdb1SYouMin Chen * (C) Copyright 2018 Rockchip Electronics Co., Ltd. 45eeb396bSKever Yang */ 55eeb396bSKever Yang 65eeb396bSKever Yang #include <common.h> 7*1881cdb1SYouMin Chen #include <debug_uart.h> 85eeb396bSKever Yang #include <dm.h> 95eeb396bSKever Yang #include <ram.h> 105eeb396bSKever Yang #include <syscon.h> 11*1881cdb1SYouMin Chen #include <asm/io.h> 125eeb396bSKever Yang #include <asm/arch/clock.h> 13*1881cdb1SYouMin Chen #include <asm/arch/cru_px30.h> 145eeb396bSKever Yang #include <asm/arch/grf_px30.h> 15*1881cdb1SYouMin Chen #include <asm/arch/hardware.h> 165eeb396bSKever Yang #include <asm/arch/sdram_common.h> 17*1881cdb1SYouMin Chen #include <asm/arch/sdram_px30.h> 18*1881cdb1SYouMin Chen 19*1881cdb1SYouMin Chen /* 20*1881cdb1SYouMin Chen * Because px30 sram size is small, so need define CONFIG_TPL_TINY_FRAMEWORK 21*1881cdb1SYouMin Chen * to reduce TPL size when build TPL firmware. 22*1881cdb1SYouMin Chen */ 23*1881cdb1SYouMin Chen #ifdef CONFIG_TPL_BUILD 24*1881cdb1SYouMin Chen #ifndef CONFIG_TPL_TINY_FRAMEWORK 25*1881cdb1SYouMin Chen #error please defined CONFIG_TPL_TINY_FRAMEWORK for px30 !!! 26*1881cdb1SYouMin Chen #endif 27*1881cdb1SYouMin Chen #endif 285eeb396bSKever Yang 295eeb396bSKever Yang DECLARE_GLOBAL_DATA_PTR; 305eeb396bSKever Yang struct dram_info { 31*1881cdb1SYouMin Chen #ifdef CONFIG_TPL_BUILD 32*1881cdb1SYouMin Chen struct px30_ddr_pctl_regs *pctl; 33*1881cdb1SYouMin Chen struct px30_ddr_phy_regs *phy; 34*1881cdb1SYouMin Chen struct px30_cru *cru; 35*1881cdb1SYouMin Chen struct px30_msch_regs *msch; 36*1881cdb1SYouMin Chen struct px30_ddr_grf_regs *ddr_grf; 37*1881cdb1SYouMin Chen struct px30_grf *grf; 38*1881cdb1SYouMin Chen #endif 395eeb396bSKever Yang struct ram_info info; 405eeb396bSKever Yang struct px30_pmugrf *pmugrf; 415eeb396bSKever Yang }; 425eeb396bSKever Yang 43*1881cdb1SYouMin Chen #ifdef CONFIG_TPL_BUILD 44*1881cdb1SYouMin Chen #define PMUGRF_BASE_ADDR 0xFF010000 45*1881cdb1SYouMin Chen #define CRU_BASE_ADDR 0xFF2B0000 46*1881cdb1SYouMin Chen #define GRF_BASE_ADDR 0xFF140000 47*1881cdb1SYouMin Chen #define DDRC_BASE_ADDR 0xFF600000 48*1881cdb1SYouMin Chen #define DDR_PHY_BASE_ADDR 0xFF2A0000 49*1881cdb1SYouMin Chen #define SERVER_MSCH0_BASE_ADDR 0xFF530000 50*1881cdb1SYouMin Chen #define DDR_GRF_BASE_ADDR 0xff630000 51*1881cdb1SYouMin Chen 52*1881cdb1SYouMin Chen struct dram_info dram_info; 53*1881cdb1SYouMin Chen 54*1881cdb1SYouMin Chen struct px30_sdram_params sdram_configs[] = { 55*1881cdb1SYouMin Chen #include "sdram-px30-lpddr3-detect-333.inc" 56*1881cdb1SYouMin Chen }; 57*1881cdb1SYouMin Chen 58*1881cdb1SYouMin Chen struct px30_ddr_skew skew = { 59*1881cdb1SYouMin Chen #include "sdram-px30-ddr_skew.inc" 60*1881cdb1SYouMin Chen }; 61*1881cdb1SYouMin Chen 62*1881cdb1SYouMin Chen static void rkclk_ddr_reset(struct dram_info *dram, 63*1881cdb1SYouMin Chen u32 ctl_srstn, u32 ctl_psrstn, 64*1881cdb1SYouMin Chen u32 phy_srstn, u32 phy_psrstn) 65*1881cdb1SYouMin Chen { 66*1881cdb1SYouMin Chen writel(upctl2_srstn_req(ctl_srstn) | upctl2_psrstn_req(ctl_psrstn) | 67*1881cdb1SYouMin Chen upctl2_asrstn_req(ctl_srstn), 68*1881cdb1SYouMin Chen &dram->cru->softrst_con[1]); 69*1881cdb1SYouMin Chen writel(ddrphy_srstn_req(phy_srstn) | ddrphy_psrstn_req(phy_psrstn), 70*1881cdb1SYouMin Chen &dram->cru->softrst_con[2]); 71*1881cdb1SYouMin Chen } 72*1881cdb1SYouMin Chen 73*1881cdb1SYouMin Chen static void rkclk_set_dpll(struct dram_info *dram, unsigned int mhz) 74*1881cdb1SYouMin Chen { 75*1881cdb1SYouMin Chen unsigned int refdiv, postdiv1, postdiv2, fbdiv; 76*1881cdb1SYouMin Chen int delay = 1000; 77*1881cdb1SYouMin Chen 78*1881cdb1SYouMin Chen refdiv = 1; 79*1881cdb1SYouMin Chen if (mhz <= 300) { 80*1881cdb1SYouMin Chen postdiv1 = 4; 81*1881cdb1SYouMin Chen postdiv2 = 2; 82*1881cdb1SYouMin Chen } else if (mhz <= 400) { 83*1881cdb1SYouMin Chen postdiv1 = 6; 84*1881cdb1SYouMin Chen postdiv2 = 1; 85*1881cdb1SYouMin Chen } else if (mhz <= 600) { 86*1881cdb1SYouMin Chen postdiv1 = 4; 87*1881cdb1SYouMin Chen postdiv2 = 1; 88*1881cdb1SYouMin Chen } else if (mhz <= 800) { 89*1881cdb1SYouMin Chen postdiv1 = 3; 90*1881cdb1SYouMin Chen postdiv2 = 1; 91*1881cdb1SYouMin Chen } else if (mhz <= 1600) { 92*1881cdb1SYouMin Chen postdiv1 = 2; 93*1881cdb1SYouMin Chen postdiv2 = 1; 94*1881cdb1SYouMin Chen } else { 95*1881cdb1SYouMin Chen postdiv1 = 1; 96*1881cdb1SYouMin Chen postdiv2 = 1; 97*1881cdb1SYouMin Chen } 98*1881cdb1SYouMin Chen fbdiv = (mhz * refdiv * postdiv1 * postdiv2) / 24; 99*1881cdb1SYouMin Chen 100*1881cdb1SYouMin Chen writel(DPLL_MODE(CLOCK_FROM_XIN_OSC), &dram->cru->mode); 101*1881cdb1SYouMin Chen 102*1881cdb1SYouMin Chen writel(POSTDIV1(postdiv1) | FBDIV(fbdiv), &dram->cru->pll[1].con0); 103*1881cdb1SYouMin Chen writel(DSMPD(1) | POSTDIV2(postdiv2) | REFDIV(refdiv), 104*1881cdb1SYouMin Chen &dram->cru->pll[1].con1); 105*1881cdb1SYouMin Chen 106*1881cdb1SYouMin Chen while (delay > 0) { 107*1881cdb1SYouMin Chen udelay(1); 108*1881cdb1SYouMin Chen if (LOCK(readl(&dram->cru->pll[1].con1))) 109*1881cdb1SYouMin Chen break; 110*1881cdb1SYouMin Chen delay--; 111*1881cdb1SYouMin Chen } 112*1881cdb1SYouMin Chen 113*1881cdb1SYouMin Chen writel(DPLL_MODE(CLOCK_FROM_PLL), &dram->cru->mode); 114*1881cdb1SYouMin Chen } 115*1881cdb1SYouMin Chen 116*1881cdb1SYouMin Chen static void rkclk_configure_ddr(struct dram_info *dram, 117*1881cdb1SYouMin Chen struct px30_sdram_params *sdram_params) 118*1881cdb1SYouMin Chen { 119*1881cdb1SYouMin Chen /* for inno ddr phy need 2*freq */ 120*1881cdb1SYouMin Chen rkclk_set_dpll(dram, sdram_params->ddr_freq * 2); 121*1881cdb1SYouMin Chen } 122*1881cdb1SYouMin Chen 123*1881cdb1SYouMin Chen static void phy_soft_reset(struct dram_info *dram) 124*1881cdb1SYouMin Chen { 125*1881cdb1SYouMin Chen void __iomem *phy_base = dram->phy; 126*1881cdb1SYouMin Chen 127*1881cdb1SYouMin Chen clrbits_le32(PHY_REG(phy_base, 0), 0x3 << 2); 128*1881cdb1SYouMin Chen udelay(1); 129*1881cdb1SYouMin Chen setbits_le32(PHY_REG(phy_base, 0), ANALOG_DERESET); 130*1881cdb1SYouMin Chen udelay(5); 131*1881cdb1SYouMin Chen setbits_le32(PHY_REG(phy_base, 0), DIGITAL_DERESET); 132*1881cdb1SYouMin Chen udelay(1); 133*1881cdb1SYouMin Chen } 134*1881cdb1SYouMin Chen 135*1881cdb1SYouMin Chen static int pctl_cfg(struct dram_info *dram, 136*1881cdb1SYouMin Chen struct px30_sdram_params *sdram_params) 137*1881cdb1SYouMin Chen { 138*1881cdb1SYouMin Chen u32 i; 139*1881cdb1SYouMin Chen void __iomem *pctl_base = dram->pctl; 140*1881cdb1SYouMin Chen 141*1881cdb1SYouMin Chen for (i = 0; sdram_params->pctl_regs.pctl[i][0] != 0xFFFFFFFF; i++) { 142*1881cdb1SYouMin Chen writel(sdram_params->pctl_regs.pctl[i][1], 143*1881cdb1SYouMin Chen pctl_base + sdram_params->pctl_regs.pctl[i][0]); 144*1881cdb1SYouMin Chen } 145*1881cdb1SYouMin Chen clrsetbits_le32(pctl_base + DDR_PCTL2_PWRTMG, 146*1881cdb1SYouMin Chen (0xff << 16) | 0x1f, 147*1881cdb1SYouMin Chen ((SR_IDLE & 0xff) << 16) | (PD_IDLE & 0x1f)); 148*1881cdb1SYouMin Chen 149*1881cdb1SYouMin Chen clrsetbits_le32(pctl_base + DDR_PCTL2_HWLPCTL, 150*1881cdb1SYouMin Chen 0xfff << 16, 151*1881cdb1SYouMin Chen 5 << 16); 152*1881cdb1SYouMin Chen /* disable zqcs */ 153*1881cdb1SYouMin Chen setbits_le32(pctl_base + DDR_PCTL2_ZQCTL0, 1u << 31); 154*1881cdb1SYouMin Chen 155*1881cdb1SYouMin Chen return 0; 156*1881cdb1SYouMin Chen } 157*1881cdb1SYouMin Chen 158*1881cdb1SYouMin Chen /* return ddrconfig value 159*1881cdb1SYouMin Chen * (-1), find ddrconfig fail 160*1881cdb1SYouMin Chen * other, the ddrconfig value 161*1881cdb1SYouMin Chen * only support cs0_row >= cs1_row 162*1881cdb1SYouMin Chen */ 163*1881cdb1SYouMin Chen static unsigned int calculate_ddrconfig(struct px30_sdram_params *sdram_params) 164*1881cdb1SYouMin Chen { 165*1881cdb1SYouMin Chen u32 bw, die_bw, col, bank; 166*1881cdb1SYouMin Chen u32 i, tmp; 167*1881cdb1SYouMin Chen u32 ddrconf = -1; 168*1881cdb1SYouMin Chen 169*1881cdb1SYouMin Chen bw = sdram_params->ch.bw; 170*1881cdb1SYouMin Chen die_bw = sdram_params->ch.dbw; 171*1881cdb1SYouMin Chen col = sdram_params->ch.col; 172*1881cdb1SYouMin Chen bank = sdram_params->ch.bk; 173*1881cdb1SYouMin Chen 174*1881cdb1SYouMin Chen if (sdram_params->dramtype == DDR4) { 175*1881cdb1SYouMin Chen if (die_bw == 0) 176*1881cdb1SYouMin Chen ddrconf = 7 + bw; 177*1881cdb1SYouMin Chen else 178*1881cdb1SYouMin Chen ddrconf = 12 - bw; 179*1881cdb1SYouMin Chen ddrconf = d4_rbc_2_d3_rbc[ddrconf - 7]; 180*1881cdb1SYouMin Chen } else { 181*1881cdb1SYouMin Chen tmp = ((bank - 2) << 3) | (col + bw - 10); 182*1881cdb1SYouMin Chen for (i = 0; i < 7; i++) 183*1881cdb1SYouMin Chen if ((ddr_cfg_2_rbc[i] & 0xf) == tmp) { 184*1881cdb1SYouMin Chen ddrconf = i; 185*1881cdb1SYouMin Chen break; 186*1881cdb1SYouMin Chen } 187*1881cdb1SYouMin Chen if (i > 6) 188*1881cdb1SYouMin Chen printascii("calculate ddrconfig error\n"); 189*1881cdb1SYouMin Chen } 190*1881cdb1SYouMin Chen 191*1881cdb1SYouMin Chen return ddrconf; 192*1881cdb1SYouMin Chen } 193*1881cdb1SYouMin Chen 194*1881cdb1SYouMin Chen /* n: Unit bytes */ 195*1881cdb1SYouMin Chen static void copy_to_reg(u32 *dest, u32 *src, u32 n) 196*1881cdb1SYouMin Chen { 197*1881cdb1SYouMin Chen int i; 198*1881cdb1SYouMin Chen 199*1881cdb1SYouMin Chen for (i = 0; i < n / sizeof(u32); i++) { 200*1881cdb1SYouMin Chen writel(*src, dest); 201*1881cdb1SYouMin Chen src++; 202*1881cdb1SYouMin Chen dest++; 203*1881cdb1SYouMin Chen } 204*1881cdb1SYouMin Chen } 205*1881cdb1SYouMin Chen 206*1881cdb1SYouMin Chen /* 207*1881cdb1SYouMin Chen * calculate controller dram address map, and setting to register. 208*1881cdb1SYouMin Chen * argument sdram_params->ch.ddrconf must be right value before 209*1881cdb1SYouMin Chen * call this function. 210*1881cdb1SYouMin Chen */ 211*1881cdb1SYouMin Chen static void set_ctl_address_map(struct dram_info *dram, 212*1881cdb1SYouMin Chen struct px30_sdram_params *sdram_params) 213*1881cdb1SYouMin Chen { 214*1881cdb1SYouMin Chen void __iomem *pctl_base = dram->pctl; 215*1881cdb1SYouMin Chen u32 cs_pst, bg, max_row, ddrconf; 216*1881cdb1SYouMin Chen u32 i; 217*1881cdb1SYouMin Chen 218*1881cdb1SYouMin Chen if (sdram_params->dramtype == DDR4) 219*1881cdb1SYouMin Chen /* 220*1881cdb1SYouMin Chen * DDR4 8bit dram BG = 2(4bank groups), 221*1881cdb1SYouMin Chen * 16bit dram BG = 1 (2 bank groups) 222*1881cdb1SYouMin Chen */ 223*1881cdb1SYouMin Chen bg = (sdram_params->ch.dbw == 0) ? 2 : 1; 224*1881cdb1SYouMin Chen else 225*1881cdb1SYouMin Chen bg = 0; 226*1881cdb1SYouMin Chen 227*1881cdb1SYouMin Chen cs_pst = sdram_params->ch.bw + sdram_params->ch.col + 228*1881cdb1SYouMin Chen bg + sdram_params->ch.bk + sdram_params->ch.cs0_row; 229*1881cdb1SYouMin Chen if (cs_pst >= 32 || sdram_params->ch.rank == 1) 230*1881cdb1SYouMin Chen writel(0x1f, pctl_base + DDR_PCTL2_ADDRMAP0); 231*1881cdb1SYouMin Chen else 232*1881cdb1SYouMin Chen writel(cs_pst - 8, pctl_base + DDR_PCTL2_ADDRMAP0); 233*1881cdb1SYouMin Chen 234*1881cdb1SYouMin Chen ddrconf = sdram_params->ch.ddrconfig; 235*1881cdb1SYouMin Chen if (sdram_params->dramtype == DDR4) { 236*1881cdb1SYouMin Chen for (i = 0; i < ARRAY_SIZE(d4_rbc_2_d3_rbc); i++) { 237*1881cdb1SYouMin Chen if (d4_rbc_2_d3_rbc[i] == ddrconf) { 238*1881cdb1SYouMin Chen ddrconf = 7 + i; 239*1881cdb1SYouMin Chen break; 240*1881cdb1SYouMin Chen } 241*1881cdb1SYouMin Chen } 242*1881cdb1SYouMin Chen } 243*1881cdb1SYouMin Chen 244*1881cdb1SYouMin Chen copy_to_reg((u32 *)(pctl_base + DDR_PCTL2_ADDRMAP1), 245*1881cdb1SYouMin Chen &addrmap[ddrconf][0], 8 * 4); 246*1881cdb1SYouMin Chen max_row = cs_pst - 1 - 8 - (addrmap[ddrconf][5] & 0xf); 247*1881cdb1SYouMin Chen 248*1881cdb1SYouMin Chen if (max_row < 12) 249*1881cdb1SYouMin Chen printascii("set addrmap fail\n"); 250*1881cdb1SYouMin Chen /* need to disable row ahead of rank by set to 0xf */ 251*1881cdb1SYouMin Chen for (i = 17; i > max_row; i--) 252*1881cdb1SYouMin Chen clrsetbits_le32(pctl_base + DDR_PCTL2_ADDRMAP6 + 253*1881cdb1SYouMin Chen ((i - 12) * 8 / 32) * 4, 254*1881cdb1SYouMin Chen 0xf << ((i - 12) * 8 % 32), 255*1881cdb1SYouMin Chen 0xf << ((i - 12) * 8 % 32)); 256*1881cdb1SYouMin Chen 257*1881cdb1SYouMin Chen if ((sdram_params->dramtype == LPDDR3 || 258*1881cdb1SYouMin Chen sdram_params->dramtype == LPDDR2) && 259*1881cdb1SYouMin Chen sdram_params->ch.row_3_4) 260*1881cdb1SYouMin Chen setbits_le32(pctl_base + DDR_PCTL2_ADDRMAP6, 1 << 31); 261*1881cdb1SYouMin Chen if (sdram_params->dramtype == DDR4 && sdram_params->ch.bw != 0x2) 262*1881cdb1SYouMin Chen setbits_le32(pctl_base + DDR_PCTL2_PCCFG, 1 << 8); 263*1881cdb1SYouMin Chen } 264*1881cdb1SYouMin Chen 265*1881cdb1SYouMin Chen static void phy_dll_bypass_set(struct dram_info *dram, u32 freq) 266*1881cdb1SYouMin Chen { 267*1881cdb1SYouMin Chen void __iomem *phy_base = dram->phy; 268*1881cdb1SYouMin Chen u32 tmp; 269*1881cdb1SYouMin Chen u32 i, j; 270*1881cdb1SYouMin Chen 271*1881cdb1SYouMin Chen setbits_le32(PHY_REG(phy_base, 0x13), 1 << 4); 272*1881cdb1SYouMin Chen clrbits_le32(PHY_REG(phy_base, 0x14), 1 << 3); 273*1881cdb1SYouMin Chen for (i = 0; i < 4; i++) { 274*1881cdb1SYouMin Chen j = 0x26 + i * 0x10; 275*1881cdb1SYouMin Chen setbits_le32(PHY_REG(phy_base, j), 1 << 4); 276*1881cdb1SYouMin Chen clrbits_le32(PHY_REG(phy_base, j + 0x1), 1 << 3); 277*1881cdb1SYouMin Chen } 278*1881cdb1SYouMin Chen 279*1881cdb1SYouMin Chen if (freq <= (400 * MHz)) 280*1881cdb1SYouMin Chen /* DLL bypass */ 281*1881cdb1SYouMin Chen setbits_le32(PHY_REG(phy_base, 0xa4), 0x1f); 282*1881cdb1SYouMin Chen else 283*1881cdb1SYouMin Chen clrbits_le32(PHY_REG(phy_base, 0xa4), 0x1f); 284*1881cdb1SYouMin Chen 285*1881cdb1SYouMin Chen if (freq <= (801 * MHz)) 286*1881cdb1SYouMin Chen tmp = 2; 287*1881cdb1SYouMin Chen else 288*1881cdb1SYouMin Chen tmp = 1; 289*1881cdb1SYouMin Chen 290*1881cdb1SYouMin Chen for (i = 0; i < 4; i++) { 291*1881cdb1SYouMin Chen j = 0x28 + i * 0x10; 292*1881cdb1SYouMin Chen writel(tmp, PHY_REG(phy_base, j)); 293*1881cdb1SYouMin Chen } 294*1881cdb1SYouMin Chen } 295*1881cdb1SYouMin Chen 296*1881cdb1SYouMin Chen static void set_ds_odt(struct dram_info *dram, 297*1881cdb1SYouMin Chen struct px30_sdram_params *sdram_params) 298*1881cdb1SYouMin Chen { 299*1881cdb1SYouMin Chen void __iomem *phy_base = dram->phy; 300*1881cdb1SYouMin Chen u32 cmd_drv, clk_drv, dqs_drv, dqs_odt; 301*1881cdb1SYouMin Chen u32 i, j; 302*1881cdb1SYouMin Chen 303*1881cdb1SYouMin Chen if (sdram_params->dramtype == DDR3) { 304*1881cdb1SYouMin Chen cmd_drv = PHY_DDR3_RON_RTT_34ohm; 305*1881cdb1SYouMin Chen clk_drv = PHY_DDR3_RON_RTT_45ohm; 306*1881cdb1SYouMin Chen dqs_drv = PHY_DDR3_RON_RTT_34ohm; 307*1881cdb1SYouMin Chen dqs_odt = PHY_DDR3_RON_RTT_225ohm; 308*1881cdb1SYouMin Chen } else { 309*1881cdb1SYouMin Chen cmd_drv = PHY_DDR4_LPDDR3_RON_RTT_34ohm; 310*1881cdb1SYouMin Chen clk_drv = PHY_DDR4_LPDDR3_RON_RTT_43ohm; 311*1881cdb1SYouMin Chen dqs_drv = PHY_DDR4_LPDDR3_RON_RTT_34ohm; 312*1881cdb1SYouMin Chen if (sdram_params->dramtype == LPDDR2) 313*1881cdb1SYouMin Chen dqs_odt = PHY_DDR4_LPDDR3_RON_RTT_DISABLE; 314*1881cdb1SYouMin Chen else 315*1881cdb1SYouMin Chen dqs_odt = PHY_DDR4_LPDDR3_RON_RTT_240ohm; 316*1881cdb1SYouMin Chen } 317*1881cdb1SYouMin Chen /* DS */ 318*1881cdb1SYouMin Chen writel(cmd_drv, PHY_REG(phy_base, 0x11)); 319*1881cdb1SYouMin Chen clrsetbits_le32(PHY_REG(phy_base, 0x12), 0x1f << 3, cmd_drv << 3); 320*1881cdb1SYouMin Chen writel(clk_drv, PHY_REG(phy_base, 0x16)); 321*1881cdb1SYouMin Chen writel(clk_drv, PHY_REG(phy_base, 0x18)); 322*1881cdb1SYouMin Chen 323*1881cdb1SYouMin Chen for (i = 0; i < 4; i++) { 324*1881cdb1SYouMin Chen j = 0x20 + i * 0x10; 325*1881cdb1SYouMin Chen writel(dqs_drv, PHY_REG(phy_base, j)); 326*1881cdb1SYouMin Chen writel(dqs_drv, PHY_REG(phy_base, j + 0xf)); 327*1881cdb1SYouMin Chen /* ODT */ 328*1881cdb1SYouMin Chen writel(dqs_odt, PHY_REG(phy_base, j + 0x1)); 329*1881cdb1SYouMin Chen writel(dqs_odt, PHY_REG(phy_base, j + 0xe)); 330*1881cdb1SYouMin Chen } 331*1881cdb1SYouMin Chen } 332*1881cdb1SYouMin Chen 333*1881cdb1SYouMin Chen static void phy_cfg(struct dram_info *dram, 334*1881cdb1SYouMin Chen struct px30_sdram_params *sdram_params) 335*1881cdb1SYouMin Chen { 336*1881cdb1SYouMin Chen void __iomem *phy_base = dram->phy; 337*1881cdb1SYouMin Chen u32 i; 338*1881cdb1SYouMin Chen 339*1881cdb1SYouMin Chen phy_dll_bypass_set(dram, sdram_params->ddr_freq); 340*1881cdb1SYouMin Chen for (i = 0; sdram_params->phy_regs.phy[i][0] != 0xFFFFFFFF; i++) { 341*1881cdb1SYouMin Chen writel(sdram_params->phy_regs.phy[i][1], 342*1881cdb1SYouMin Chen phy_base + sdram_params->phy_regs.phy[i][0]); 343*1881cdb1SYouMin Chen } 344*1881cdb1SYouMin Chen if (sdram_params->ch.bw == 2) { 345*1881cdb1SYouMin Chen clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 0xf << 4); 346*1881cdb1SYouMin Chen } else if (sdram_params->ch.bw == 1) { 347*1881cdb1SYouMin Chen clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 3 << 4); 348*1881cdb1SYouMin Chen /* disable DQS2,DQS3 tx dll for saving power */ 349*1881cdb1SYouMin Chen clrbits_le32(PHY_REG(phy_base, 0x46), 1 << 3); 350*1881cdb1SYouMin Chen clrbits_le32(PHY_REG(phy_base, 0x56), 1 << 3); 351*1881cdb1SYouMin Chen } else { 352*1881cdb1SYouMin Chen clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 1 << 4); 353*1881cdb1SYouMin Chen /* disable DQS2,DQS3 tx dll for saving power */ 354*1881cdb1SYouMin Chen clrbits_le32(PHY_REG(phy_base, 0x36), 1 << 3); 355*1881cdb1SYouMin Chen clrbits_le32(PHY_REG(phy_base, 0x46), 1 << 3); 356*1881cdb1SYouMin Chen clrbits_le32(PHY_REG(phy_base, 0x56), 1 << 3); 357*1881cdb1SYouMin Chen } 358*1881cdb1SYouMin Chen set_ds_odt(dram, sdram_params); 359*1881cdb1SYouMin Chen 360*1881cdb1SYouMin Chen /* deskew */ 361*1881cdb1SYouMin Chen setbits_le32(PHY_REG(phy_base, 2), 8); 362*1881cdb1SYouMin Chen copy_to_reg(PHY_REG(phy_base, 0xb0), 363*1881cdb1SYouMin Chen &sdram_params->skew->a0_a1_skew[0], 15 * 4); 364*1881cdb1SYouMin Chen copy_to_reg(PHY_REG(phy_base, 0x70), 365*1881cdb1SYouMin Chen &sdram_params->skew->cs0_dm0_skew[0], 44 * 4); 366*1881cdb1SYouMin Chen copy_to_reg(PHY_REG(phy_base, 0xc0), 367*1881cdb1SYouMin Chen &sdram_params->skew->cs0_dm1_skew[0], 44 * 4); 368*1881cdb1SYouMin Chen } 369*1881cdb1SYouMin Chen 370*1881cdb1SYouMin Chen static int update_refresh_reg(struct dram_info *dram) 371*1881cdb1SYouMin Chen { 372*1881cdb1SYouMin Chen void __iomem *pctl_base = dram->pctl; 373*1881cdb1SYouMin Chen u32 ret; 374*1881cdb1SYouMin Chen 375*1881cdb1SYouMin Chen ret = readl(pctl_base + DDR_PCTL2_RFSHCTL3) ^ (1 << 1); 376*1881cdb1SYouMin Chen writel(ret, pctl_base + DDR_PCTL2_RFSHCTL3); 377*1881cdb1SYouMin Chen 378*1881cdb1SYouMin Chen return 0; 379*1881cdb1SYouMin Chen } 380*1881cdb1SYouMin Chen 381*1881cdb1SYouMin Chen /* 382*1881cdb1SYouMin Chen * rank = 1: cs0 383*1881cdb1SYouMin Chen * rank = 2: cs1 384*1881cdb1SYouMin Chen */ 385*1881cdb1SYouMin Chen int read_mr(struct dram_info *dram, u32 rank, u32 mr_num) 386*1881cdb1SYouMin Chen { 387*1881cdb1SYouMin Chen void __iomem *pctl_base = dram->pctl; 388*1881cdb1SYouMin Chen void __iomem *ddr_grf_base = dram->ddr_grf; 389*1881cdb1SYouMin Chen 390*1881cdb1SYouMin Chen writel((rank << 4) | (1 << 0), pctl_base + DDR_PCTL2_MRCTRL0); 391*1881cdb1SYouMin Chen writel((mr_num << 8), pctl_base + DDR_PCTL2_MRCTRL1); 392*1881cdb1SYouMin Chen setbits_le32(pctl_base + DDR_PCTL2_MRCTRL0, 1u << 31); 393*1881cdb1SYouMin Chen while (readl(pctl_base + DDR_PCTL2_MRCTRL0) & (1u << 31)) 394*1881cdb1SYouMin Chen continue; 395*1881cdb1SYouMin Chen while (readl(pctl_base + DDR_PCTL2_MRSTAT) & MR_WR_BUSY) 396*1881cdb1SYouMin Chen continue; 397*1881cdb1SYouMin Chen 398*1881cdb1SYouMin Chen return (readl(ddr_grf_base + DDR_GRF_STATUS(0)) & 0xff); 399*1881cdb1SYouMin Chen } 400*1881cdb1SYouMin Chen 401*1881cdb1SYouMin Chen u32 disable_zqcs_arefresh(struct dram_info *dram) 402*1881cdb1SYouMin Chen { 403*1881cdb1SYouMin Chen void __iomem *pctl_base = dram->pctl; 404*1881cdb1SYouMin Chen u32 dis_auto_zq = 0; 405*1881cdb1SYouMin Chen 406*1881cdb1SYouMin Chen /* disable zqcs */ 407*1881cdb1SYouMin Chen if (!(readl(pctl_base + DDR_PCTL2_ZQCTL0) & 408*1881cdb1SYouMin Chen (1ul << 31))) { 409*1881cdb1SYouMin Chen dis_auto_zq = 1; 410*1881cdb1SYouMin Chen setbits_le32(pctl_base + DDR_PCTL2_ZQCTL0, 1 << 31); 411*1881cdb1SYouMin Chen } 412*1881cdb1SYouMin Chen 413*1881cdb1SYouMin Chen /* disable auto refresh */ 414*1881cdb1SYouMin Chen setbits_le32(pctl_base + DDR_PCTL2_RFSHCTL3, 1); 415*1881cdb1SYouMin Chen 416*1881cdb1SYouMin Chen update_refresh_reg(dram); 417*1881cdb1SYouMin Chen 418*1881cdb1SYouMin Chen return dis_auto_zq; 419*1881cdb1SYouMin Chen } 420*1881cdb1SYouMin Chen 421*1881cdb1SYouMin Chen void restore_zqcs_arefresh(struct dram_info *dram, u32 dis_auto_zq) 422*1881cdb1SYouMin Chen { 423*1881cdb1SYouMin Chen void __iomem *pctl_base = dram->pctl; 424*1881cdb1SYouMin Chen 425*1881cdb1SYouMin Chen /* restore zqcs */ 426*1881cdb1SYouMin Chen if (dis_auto_zq) 427*1881cdb1SYouMin Chen clrbits_le32(pctl_base + DDR_PCTL2_ZQCTL0, 1 << 31); 428*1881cdb1SYouMin Chen 429*1881cdb1SYouMin Chen /* restore auto refresh */ 430*1881cdb1SYouMin Chen clrbits_le32(pctl_base + DDR_PCTL2_RFSHCTL3, 1); 431*1881cdb1SYouMin Chen 432*1881cdb1SYouMin Chen update_refresh_reg(dram); 433*1881cdb1SYouMin Chen } 434*1881cdb1SYouMin Chen 435*1881cdb1SYouMin Chen #define MIN(a, b) (((a) > (b)) ? (b) : (a)) 436*1881cdb1SYouMin Chen #define MAX(a, b) (((a) > (b)) ? (a) : (b)) 437*1881cdb1SYouMin Chen static u32 check_rd_gate(struct dram_info *dram) 438*1881cdb1SYouMin Chen { 439*1881cdb1SYouMin Chen void __iomem *phy_base = dram->phy; 440*1881cdb1SYouMin Chen 441*1881cdb1SYouMin Chen u32 max_val = 0; 442*1881cdb1SYouMin Chen u32 min_val = 0xff; 443*1881cdb1SYouMin Chen u32 gate[4]; 444*1881cdb1SYouMin Chen u32 i, bw; 445*1881cdb1SYouMin Chen 446*1881cdb1SYouMin Chen bw = (readl(PHY_REG(phy_base, 0x0)) >> 4) & 0xf; 447*1881cdb1SYouMin Chen switch (bw) { 448*1881cdb1SYouMin Chen case 0x1: 449*1881cdb1SYouMin Chen bw = 1; 450*1881cdb1SYouMin Chen break; 451*1881cdb1SYouMin Chen case 0x3: 452*1881cdb1SYouMin Chen bw = 2; 453*1881cdb1SYouMin Chen break; 454*1881cdb1SYouMin Chen case 0xf: 455*1881cdb1SYouMin Chen default: 456*1881cdb1SYouMin Chen bw = 4; 457*1881cdb1SYouMin Chen break; 458*1881cdb1SYouMin Chen } 459*1881cdb1SYouMin Chen 460*1881cdb1SYouMin Chen for (i = 0; i < bw; i++) { 461*1881cdb1SYouMin Chen gate[i] = readl(PHY_REG(phy_base, 0xfb + i)); 462*1881cdb1SYouMin Chen max_val = MAX(max_val, gate[i]); 463*1881cdb1SYouMin Chen min_val = MIN(min_val, gate[i]); 464*1881cdb1SYouMin Chen } 465*1881cdb1SYouMin Chen 466*1881cdb1SYouMin Chen if (max_val > 0x80 || min_val < 0x20) 467*1881cdb1SYouMin Chen return -1; 468*1881cdb1SYouMin Chen else 469*1881cdb1SYouMin Chen return 0; 470*1881cdb1SYouMin Chen } 471*1881cdb1SYouMin Chen 472*1881cdb1SYouMin Chen static int data_training(struct dram_info *dram, u32 cs, u32 dramtype) 473*1881cdb1SYouMin Chen { 474*1881cdb1SYouMin Chen void __iomem *phy_base = dram->phy; 475*1881cdb1SYouMin Chen u32 ret; 476*1881cdb1SYouMin Chen u32 dis_auto_zq = 0; 477*1881cdb1SYouMin Chen u32 odt_val; 478*1881cdb1SYouMin Chen u32 i, j; 479*1881cdb1SYouMin Chen 480*1881cdb1SYouMin Chen odt_val = readl(PHY_REG(phy_base, 0x2e)); 481*1881cdb1SYouMin Chen 482*1881cdb1SYouMin Chen for (i = 0; i < 4; i++) { 483*1881cdb1SYouMin Chen j = 0x20 + i * 0x10; 484*1881cdb1SYouMin Chen writel(PHY_DDR3_RON_RTT_225ohm, PHY_REG(phy_base, j + 0x1)); 485*1881cdb1SYouMin Chen writel(0, PHY_REG(phy_base, j + 0xe)); 486*1881cdb1SYouMin Chen } 487*1881cdb1SYouMin Chen 488*1881cdb1SYouMin Chen dis_auto_zq = disable_zqcs_arefresh(dram); 489*1881cdb1SYouMin Chen 490*1881cdb1SYouMin Chen if (dramtype == DDR4) { 491*1881cdb1SYouMin Chen clrsetbits_le32(PHY_REG(phy_base, 0x29), 0x3, 0); 492*1881cdb1SYouMin Chen clrsetbits_le32(PHY_REG(phy_base, 0x39), 0x3, 0); 493*1881cdb1SYouMin Chen clrsetbits_le32(PHY_REG(phy_base, 0x49), 0x3, 0); 494*1881cdb1SYouMin Chen clrsetbits_le32(PHY_REG(phy_base, 0x59), 0x3, 0); 495*1881cdb1SYouMin Chen } 496*1881cdb1SYouMin Chen /* choose training cs */ 497*1881cdb1SYouMin Chen clrsetbits_le32(PHY_REG(phy_base, 2), 0x33, (0x20 >> cs)); 498*1881cdb1SYouMin Chen /* enable gate training */ 499*1881cdb1SYouMin Chen clrsetbits_le32(PHY_REG(phy_base, 2), 0x33, (0x20 >> cs) | 1); 500*1881cdb1SYouMin Chen udelay(50); 501*1881cdb1SYouMin Chen ret = readl(PHY_REG(phy_base, 0xff)); 502*1881cdb1SYouMin Chen /* disable gate training */ 503*1881cdb1SYouMin Chen clrsetbits_le32(PHY_REG(phy_base, 2), 0x33, (0x20 >> cs) | 0); 504*1881cdb1SYouMin Chen clrbits_le32(PHY_REG(phy_base, 2), 0x30); 505*1881cdb1SYouMin Chen restore_zqcs_arefresh(dram, dis_auto_zq); 506*1881cdb1SYouMin Chen 507*1881cdb1SYouMin Chen if (dramtype == DDR4) { 508*1881cdb1SYouMin Chen clrsetbits_le32(PHY_REG(phy_base, 0x29), 0x3, 0x2); 509*1881cdb1SYouMin Chen clrsetbits_le32(PHY_REG(phy_base, 0x39), 0x3, 0x2); 510*1881cdb1SYouMin Chen clrsetbits_le32(PHY_REG(phy_base, 0x49), 0x3, 0x2); 511*1881cdb1SYouMin Chen clrsetbits_le32(PHY_REG(phy_base, 0x59), 0x3, 0x2); 512*1881cdb1SYouMin Chen } 513*1881cdb1SYouMin Chen 514*1881cdb1SYouMin Chen if (ret & 0x10) { 515*1881cdb1SYouMin Chen ret = -1; 516*1881cdb1SYouMin Chen } else { 517*1881cdb1SYouMin Chen ret = (ret & 0xf) ^ (readl(PHY_REG(phy_base, 0)) >> 4); 518*1881cdb1SYouMin Chen ret = (ret == 0) ? 0 : -1; 519*1881cdb1SYouMin Chen } 520*1881cdb1SYouMin Chen 521*1881cdb1SYouMin Chen for (i = 0; i < 4; i++) { 522*1881cdb1SYouMin Chen j = 0x20 + i * 0x10; 523*1881cdb1SYouMin Chen writel(odt_val, PHY_REG(phy_base, j + 0x1)); 524*1881cdb1SYouMin Chen writel(odt_val, PHY_REG(phy_base, j + 0xe)); 525*1881cdb1SYouMin Chen } 526*1881cdb1SYouMin Chen 527*1881cdb1SYouMin Chen return ret; 528*1881cdb1SYouMin Chen } 529*1881cdb1SYouMin Chen 530*1881cdb1SYouMin Chen /* rank = 1: cs0 531*1881cdb1SYouMin Chen * rank = 2: cs1 532*1881cdb1SYouMin Chen * rank = 3: cs0 & cs1 533*1881cdb1SYouMin Chen * note: be careful of keep mr original val 534*1881cdb1SYouMin Chen */ 535*1881cdb1SYouMin Chen static int write_mr(struct dram_info *dram, u32 rank, u32 mr_num, u32 arg, 536*1881cdb1SYouMin Chen u32 dramtype) 537*1881cdb1SYouMin Chen { 538*1881cdb1SYouMin Chen void __iomem *pctl_base = dram->pctl; 539*1881cdb1SYouMin Chen 540*1881cdb1SYouMin Chen while (readl(pctl_base + DDR_PCTL2_MRSTAT) & MR_WR_BUSY) 541*1881cdb1SYouMin Chen continue; 542*1881cdb1SYouMin Chen if (dramtype == DDR3 || dramtype == DDR4) { 543*1881cdb1SYouMin Chen writel((mr_num << 12) | (rank << 4) | (0 << 0), 544*1881cdb1SYouMin Chen pctl_base + DDR_PCTL2_MRCTRL0); 545*1881cdb1SYouMin Chen writel(arg, pctl_base + DDR_PCTL2_MRCTRL1); 546*1881cdb1SYouMin Chen } else { 547*1881cdb1SYouMin Chen writel((rank << 4) | (0 << 0), 548*1881cdb1SYouMin Chen pctl_base + DDR_PCTL2_MRCTRL0); 549*1881cdb1SYouMin Chen writel((mr_num << 8) | (arg & 0xff), 550*1881cdb1SYouMin Chen pctl_base + DDR_PCTL2_MRCTRL1); 551*1881cdb1SYouMin Chen } 552*1881cdb1SYouMin Chen 553*1881cdb1SYouMin Chen setbits_le32(pctl_base + DDR_PCTL2_MRCTRL0, 1u << 31); 554*1881cdb1SYouMin Chen while (readl(pctl_base + DDR_PCTL2_MRCTRL0) & (1u << 31)) 555*1881cdb1SYouMin Chen continue; 556*1881cdb1SYouMin Chen while (readl(pctl_base + DDR_PCTL2_MRSTAT) & MR_WR_BUSY) 557*1881cdb1SYouMin Chen continue; 558*1881cdb1SYouMin Chen 559*1881cdb1SYouMin Chen return 0; 560*1881cdb1SYouMin Chen } 561*1881cdb1SYouMin Chen 562*1881cdb1SYouMin Chen /* 563*1881cdb1SYouMin Chen * rank : 1:cs0, 2:cs1, 3:cs0&cs1 564*1881cdb1SYouMin Chen * vrefrate: 4500: 45%, 565*1881cdb1SYouMin Chen */ 566*1881cdb1SYouMin Chen static int write_vrefdq(struct dram_info *dram, u32 rank, u32 vrefrate, 567*1881cdb1SYouMin Chen u32 dramtype) 568*1881cdb1SYouMin Chen { 569*1881cdb1SYouMin Chen void __iomem *pctl_base = dram->pctl; 570*1881cdb1SYouMin Chen u32 tccd_l, value; 571*1881cdb1SYouMin Chen u32 dis_auto_zq = 0; 572*1881cdb1SYouMin Chen 573*1881cdb1SYouMin Chen if (dramtype != DDR4 || vrefrate < 4500 || 574*1881cdb1SYouMin Chen vrefrate > 9200) 575*1881cdb1SYouMin Chen return (-1); 576*1881cdb1SYouMin Chen 577*1881cdb1SYouMin Chen tccd_l = (readl(pctl_base + DDR_PCTL2_DRAMTMG4) >> 16) & 0xf; 578*1881cdb1SYouMin Chen tccd_l = (tccd_l - 4) << 10; 579*1881cdb1SYouMin Chen 580*1881cdb1SYouMin Chen if (vrefrate > 7500) { 581*1881cdb1SYouMin Chen /* range 1 */ 582*1881cdb1SYouMin Chen value = ((vrefrate - 6000) / 65) | tccd_l; 583*1881cdb1SYouMin Chen } else { 584*1881cdb1SYouMin Chen /* range 2 */ 585*1881cdb1SYouMin Chen value = ((vrefrate - 4500) / 65) | tccd_l | (1 << 6); 586*1881cdb1SYouMin Chen } 587*1881cdb1SYouMin Chen 588*1881cdb1SYouMin Chen dis_auto_zq = disable_zqcs_arefresh(dram); 589*1881cdb1SYouMin Chen 590*1881cdb1SYouMin Chen /* enable vrefdq calibratin */ 591*1881cdb1SYouMin Chen write_mr(dram, rank, 6, value | (1 << 7), dramtype); 592*1881cdb1SYouMin Chen udelay(1);/* tvrefdqe */ 593*1881cdb1SYouMin Chen /* write vrefdq value */ 594*1881cdb1SYouMin Chen write_mr(dram, rank, 6, value | (1 << 7), dramtype); 595*1881cdb1SYouMin Chen udelay(1);/* tvref_time */ 596*1881cdb1SYouMin Chen write_mr(dram, rank, 6, value | (0 << 7), dramtype); 597*1881cdb1SYouMin Chen udelay(1);/* tvrefdqx */ 598*1881cdb1SYouMin Chen 599*1881cdb1SYouMin Chen restore_zqcs_arefresh(dram, dis_auto_zq); 600*1881cdb1SYouMin Chen 601*1881cdb1SYouMin Chen return 0; 602*1881cdb1SYouMin Chen } 603*1881cdb1SYouMin Chen 604*1881cdb1SYouMin Chen /* 605*1881cdb1SYouMin Chen * cs: 0:cs0 606*1881cdb1SYouMin Chen * 1:cs1 607*1881cdb1SYouMin Chen * else cs0+cs1 608*1881cdb1SYouMin Chen * note: it didn't consider about row_3_4 609*1881cdb1SYouMin Chen */ 610*1881cdb1SYouMin Chen u64 get_cs_cap(struct px30_sdram_params *sdram_params, u32 cs) 611*1881cdb1SYouMin Chen { 612*1881cdb1SYouMin Chen u32 bg; 613*1881cdb1SYouMin Chen u64 cap[2]; 614*1881cdb1SYouMin Chen 615*1881cdb1SYouMin Chen if (sdram_params->dramtype == DDR4) 616*1881cdb1SYouMin Chen /* DDR4 8bit dram BG = 2(4bank groups), 617*1881cdb1SYouMin Chen * 16bit dram BG = 1 (2 bank groups) 618*1881cdb1SYouMin Chen */ 619*1881cdb1SYouMin Chen bg = (sdram_params->ch.dbw == 0) ? 2 : 1; 620*1881cdb1SYouMin Chen else 621*1881cdb1SYouMin Chen bg = 0; 622*1881cdb1SYouMin Chen cap[0] = 1llu << (sdram_params->ch.bw + sdram_params->ch.col + 623*1881cdb1SYouMin Chen bg + sdram_params->ch.bk + sdram_params->ch.cs0_row); 624*1881cdb1SYouMin Chen 625*1881cdb1SYouMin Chen if (sdram_params->ch.rank == 2) 626*1881cdb1SYouMin Chen cap[1] = 1llu << (sdram_params->ch.bw + sdram_params->ch.col + 627*1881cdb1SYouMin Chen bg + sdram_params->ch.bk + sdram_params->ch.cs1_row); 628*1881cdb1SYouMin Chen else 629*1881cdb1SYouMin Chen cap[1] = 0; 630*1881cdb1SYouMin Chen 631*1881cdb1SYouMin Chen if (cs == 0) 632*1881cdb1SYouMin Chen return cap[0]; 633*1881cdb1SYouMin Chen else if (cs == 1) 634*1881cdb1SYouMin Chen return cap[1]; 635*1881cdb1SYouMin Chen else 636*1881cdb1SYouMin Chen return (cap[0] + cap[1]); 637*1881cdb1SYouMin Chen } 638*1881cdb1SYouMin Chen 639*1881cdb1SYouMin Chen static void set_ddrconfig(struct dram_info *dram, u32 ddrconfig) 640*1881cdb1SYouMin Chen { 641*1881cdb1SYouMin Chen writel(ddrconfig | (ddrconfig << 8), &dram->msch->deviceconf); 642*1881cdb1SYouMin Chen rk_clrsetreg(&dram->grf->soc_noc_con[1], 0x3 << 14, 0 << 14); 643*1881cdb1SYouMin Chen } 644*1881cdb1SYouMin Chen 645*1881cdb1SYouMin Chen static void dram_all_config(struct dram_info *dram, 646*1881cdb1SYouMin Chen struct px30_sdram_params *sdram_params) 647*1881cdb1SYouMin Chen { 648*1881cdb1SYouMin Chen u32 sys_reg = 0; 649*1881cdb1SYouMin Chen u32 sys_reg3 = 0; 650*1881cdb1SYouMin Chen u64 cs_cap[2]; 651*1881cdb1SYouMin Chen 652*1881cdb1SYouMin Chen set_ddrconfig(dram, sdram_params->ch.ddrconfig); 653*1881cdb1SYouMin Chen 654*1881cdb1SYouMin Chen sys_reg |= SYS_REG_ENC_DDRTYPE(sdram_params->dramtype); 655*1881cdb1SYouMin Chen sys_reg |= SYS_REG_ENC_ROW_3_4(sdram_params->ch.row_3_4); 656*1881cdb1SYouMin Chen sys_reg |= SYS_REG_ENC_RANK(sdram_params->ch.rank); 657*1881cdb1SYouMin Chen sys_reg |= SYS_REG_ENC_COL(sdram_params->ch.col); 658*1881cdb1SYouMin Chen sys_reg |= SYS_REG_ENC_BK(sdram_params->ch.bk); 659*1881cdb1SYouMin Chen sys_reg |= SYS_REG_ENC_BW(sdram_params->ch.bw); 660*1881cdb1SYouMin Chen sys_reg |= SYS_REG_ENC_DBW(sdram_params->ch.dbw); 661*1881cdb1SYouMin Chen 662*1881cdb1SYouMin Chen SYS_REG_ENC_CS0_ROW_(sdram_params->ch.cs0_row, sys_reg, sys_reg3); 663*1881cdb1SYouMin Chen if (sdram_params->ch.cs1_row) 664*1881cdb1SYouMin Chen SYS_REG_ENC_CS1_ROW_(sdram_params->ch.cs1_row, sys_reg, 665*1881cdb1SYouMin Chen sys_reg3); 666*1881cdb1SYouMin Chen sys_reg3 |= SYS_REG_ENC_CS1_COL(sdram_params->ch.col); 667*1881cdb1SYouMin Chen sys_reg3 |= SYS_REG_ENC_VERSION(DDR_SYS_REG_VERSION); 668*1881cdb1SYouMin Chen 669*1881cdb1SYouMin Chen writel(sys_reg, &dram->pmugrf->os_reg[2]); 670*1881cdb1SYouMin Chen writel(sys_reg3, &dram->pmugrf->os_reg[3]); 671*1881cdb1SYouMin Chen 672*1881cdb1SYouMin Chen cs_cap[0] = get_cs_cap(sdram_params, 0); 673*1881cdb1SYouMin Chen cs_cap[1] = get_cs_cap(sdram_params, 1); 674*1881cdb1SYouMin Chen writel(((((cs_cap[1] >> 20) / 64) & 0xff) << 8) | 675*1881cdb1SYouMin Chen (((cs_cap[0] >> 20) / 64) & 0xff), 676*1881cdb1SYouMin Chen &dram->msch->devicesize); 677*1881cdb1SYouMin Chen 678*1881cdb1SYouMin Chen writel(sdram_params->ch.noc_timings.ddrtiminga0.d32, 679*1881cdb1SYouMin Chen &dram->msch->ddrtiminga0); 680*1881cdb1SYouMin Chen writel(sdram_params->ch.noc_timings.ddrtimingb0.d32, 681*1881cdb1SYouMin Chen &dram->msch->ddrtimingb0); 682*1881cdb1SYouMin Chen writel(sdram_params->ch.noc_timings.ddrtimingc0.d32, 683*1881cdb1SYouMin Chen &dram->msch->ddrtimingc0); 684*1881cdb1SYouMin Chen writel(sdram_params->ch.noc_timings.devtodev0.d32, 685*1881cdb1SYouMin Chen &dram->msch->devtodev0); 686*1881cdb1SYouMin Chen writel(sdram_params->ch.noc_timings.ddrmode.d32, &dram->msch->ddrmode); 687*1881cdb1SYouMin Chen writel(sdram_params->ch.noc_timings.ddr4timing.d32, 688*1881cdb1SYouMin Chen &dram->msch->ddr4timing); 689*1881cdb1SYouMin Chen writel(sdram_params->ch.noc_timings.agingx0, &dram->msch->agingx0); 690*1881cdb1SYouMin Chen writel(sdram_params->ch.noc_timings.agingx0, &dram->msch->aging0); 691*1881cdb1SYouMin Chen writel(sdram_params->ch.noc_timings.agingx0, &dram->msch->aging1); 692*1881cdb1SYouMin Chen writel(sdram_params->ch.noc_timings.agingx0, &dram->msch->aging2); 693*1881cdb1SYouMin Chen writel(sdram_params->ch.noc_timings.agingx0, &dram->msch->aging3); 694*1881cdb1SYouMin Chen } 695*1881cdb1SYouMin Chen 696*1881cdb1SYouMin Chen static void enable_low_power(struct dram_info *dram, 697*1881cdb1SYouMin Chen struct px30_sdram_params *sdram_params) 698*1881cdb1SYouMin Chen { 699*1881cdb1SYouMin Chen void __iomem *pctl_base = dram->pctl; 700*1881cdb1SYouMin Chen void __iomem *ddr_grf_base = dram->ddr_grf; 701*1881cdb1SYouMin Chen u32 grf_lp_con; 702*1881cdb1SYouMin Chen 703*1881cdb1SYouMin Chen /* 704*1881cdb1SYouMin Chen * bit0: grf_upctl_axi_cg_en = 1 enable upctl2 axi clk auto gating 705*1881cdb1SYouMin Chen * bit1: grf_upctl_apb_cg_en = 1 ungated axi,core clk for apb access 706*1881cdb1SYouMin Chen * bit2: grf_upctl_core_cg_en = 1 enable upctl2 core clk auto gating 707*1881cdb1SYouMin Chen * bit3: grf_selfref_type2_en = 0 disable core clk gating when type2 sr 708*1881cdb1SYouMin Chen * bit4: grf_upctl_syscreq_cg_en = 1 709*1881cdb1SYouMin Chen * ungating coreclk when c_sysreq assert 710*1881cdb1SYouMin Chen * bit8-11: grf_auto_sr_dly = 6 711*1881cdb1SYouMin Chen */ 712*1881cdb1SYouMin Chen writel(0x1f1f0617, &dram->ddr_grf->ddr_grf_con[1]); 713*1881cdb1SYouMin Chen 714*1881cdb1SYouMin Chen if (sdram_params->dramtype == DDR4) 715*1881cdb1SYouMin Chen grf_lp_con = (0x7 << 16) | (1 << 1); 716*1881cdb1SYouMin Chen else if (sdram_params->dramtype == DDR3) 717*1881cdb1SYouMin Chen grf_lp_con = (0x7 << 16) | (1 << 0); 718*1881cdb1SYouMin Chen else 719*1881cdb1SYouMin Chen grf_lp_con = (0x7 << 16) | (1 << 2); 720*1881cdb1SYouMin Chen 721*1881cdb1SYouMin Chen /* en lpckdis_en */ 722*1881cdb1SYouMin Chen grf_lp_con = grf_lp_con | (0x1 << (9 + 16)) | (0x1 << 9); 723*1881cdb1SYouMin Chen writel(grf_lp_con, ddr_grf_base + DDR_GRF_LP_CON); 724*1881cdb1SYouMin Chen 725*1881cdb1SYouMin Chen /* enable sr, pd */ 726*1881cdb1SYouMin Chen if (PD_IDLE == 0) 727*1881cdb1SYouMin Chen clrbits_le32(pctl_base + DDR_PCTL2_PWRCTL, (1 << 1)); 728*1881cdb1SYouMin Chen else 729*1881cdb1SYouMin Chen setbits_le32(pctl_base + DDR_PCTL2_PWRCTL, (1 << 1)); 730*1881cdb1SYouMin Chen if (SR_IDLE == 0) 731*1881cdb1SYouMin Chen clrbits_le32(pctl_base + DDR_PCTL2_PWRCTL, 1); 732*1881cdb1SYouMin Chen else 733*1881cdb1SYouMin Chen setbits_le32(pctl_base + DDR_PCTL2_PWRCTL, 1); 734*1881cdb1SYouMin Chen setbits_le32(pctl_base + DDR_PCTL2_PWRCTL, (1 << 3)); 735*1881cdb1SYouMin Chen } 736*1881cdb1SYouMin Chen 737*1881cdb1SYouMin Chen static int print_dec2hex(int i) 738*1881cdb1SYouMin Chen { 739*1881cdb1SYouMin Chen int tmp; 740*1881cdb1SYouMin Chen 741*1881cdb1SYouMin Chen tmp = (i % 10); 742*1881cdb1SYouMin Chen tmp |= ((i % 100) / 10) << 4; 743*1881cdb1SYouMin Chen tmp |= ((i % 1000) / 100) << 8; 744*1881cdb1SYouMin Chen 745*1881cdb1SYouMin Chen return tmp; 746*1881cdb1SYouMin Chen } 747*1881cdb1SYouMin Chen 748*1881cdb1SYouMin Chen /* 749*1881cdb1SYouMin Chen * pre_init: 0: pre init for dram cap detect 750*1881cdb1SYouMin Chen * 1: detect correct cap(except cs1 row)info, than reinit 751*1881cdb1SYouMin Chen * 2: after reinit, we detect cs1_row, if cs1_row not equal 752*1881cdb1SYouMin Chen * to cs0_row and cs is in middle on ddrconf map, we need 753*1881cdb1SYouMin Chen * to reinit dram, than set the correct ddrconf. 754*1881cdb1SYouMin Chen */ 755*1881cdb1SYouMin Chen static int sdram_init_(struct dram_info *dram, 756*1881cdb1SYouMin Chen struct px30_sdram_params *sdram_params, u32 pre_init) 757*1881cdb1SYouMin Chen { 758*1881cdb1SYouMin Chen void __iomem *pctl_base = dram->pctl; 759*1881cdb1SYouMin Chen 760*1881cdb1SYouMin Chen rkclk_ddr_reset(dram, 1, 1, 1, 1); 761*1881cdb1SYouMin Chen udelay(10); 762*1881cdb1SYouMin Chen /* 763*1881cdb1SYouMin Chen * dereset ddr phy psrstn to config pll, 764*1881cdb1SYouMin Chen * if using phy pll psrstn must be dereset 765*1881cdb1SYouMin Chen * before config pll 766*1881cdb1SYouMin Chen */ 767*1881cdb1SYouMin Chen rkclk_ddr_reset(dram, 1, 1, 1, 0); 768*1881cdb1SYouMin Chen rkclk_configure_ddr(dram, sdram_params); 769*1881cdb1SYouMin Chen 770*1881cdb1SYouMin Chen if (pre_init == 1) { 771*1881cdb1SYouMin Chen switch (sdram_params->dramtype) { 772*1881cdb1SYouMin Chen case DDR3: 773*1881cdb1SYouMin Chen printascii("DDR3\n"); 774*1881cdb1SYouMin Chen break; 775*1881cdb1SYouMin Chen case DDR4: 776*1881cdb1SYouMin Chen printascii("DDR4\n"); 777*1881cdb1SYouMin Chen break; 778*1881cdb1SYouMin Chen case LPDDR2: 779*1881cdb1SYouMin Chen printascii("LPDDR2\n"); 780*1881cdb1SYouMin Chen break; 781*1881cdb1SYouMin Chen case LPDDR3: 782*1881cdb1SYouMin Chen default: 783*1881cdb1SYouMin Chen printascii("LPDDR3\n"); 784*1881cdb1SYouMin Chen break; 785*1881cdb1SYouMin Chen } 786*1881cdb1SYouMin Chen printhex4(print_dec2hex(sdram_params->ddr_freq)); 787*1881cdb1SYouMin Chen printascii("MHz\n"); 788*1881cdb1SYouMin Chen } 789*1881cdb1SYouMin Chen 790*1881cdb1SYouMin Chen /* release phy srst to provide clk to ctrl */ 791*1881cdb1SYouMin Chen rkclk_ddr_reset(dram, 1, 1, 0, 0); 792*1881cdb1SYouMin Chen udelay(10); 793*1881cdb1SYouMin Chen phy_soft_reset(dram); 794*1881cdb1SYouMin Chen /* release ctrl presetn, and config ctl registers */ 795*1881cdb1SYouMin Chen rkclk_ddr_reset(dram, 1, 0, 0, 0); 796*1881cdb1SYouMin Chen pctl_cfg(dram, sdram_params); 797*1881cdb1SYouMin Chen sdram_params->ch.ddrconfig = calculate_ddrconfig(sdram_params); 798*1881cdb1SYouMin Chen set_ctl_address_map(dram, sdram_params); 799*1881cdb1SYouMin Chen phy_cfg(dram, sdram_params); 800*1881cdb1SYouMin Chen 801*1881cdb1SYouMin Chen /* enable dfi_init_start to init phy after ctl srstn deassert */ 802*1881cdb1SYouMin Chen setbits_le32(pctl_base + DDR_PCTL2_DFIMISC, (1 << 5) | (1 << 4)); 803*1881cdb1SYouMin Chen 804*1881cdb1SYouMin Chen rkclk_ddr_reset(dram, 0, 0, 0, 0); 805*1881cdb1SYouMin Chen /* wait for dfi_init_done and dram init complete */ 806*1881cdb1SYouMin Chen while ((readl(pctl_base + DDR_PCTL2_STAT) & 0x7) == 0) 807*1881cdb1SYouMin Chen continue; 808*1881cdb1SYouMin Chen 809*1881cdb1SYouMin Chen if (sdram_params->dramtype == LPDDR3) 810*1881cdb1SYouMin Chen write_mr(dram, 3, 11, 3, LPDDR3); 811*1881cdb1SYouMin Chen 812*1881cdb1SYouMin Chen /* do ddr gate training */ 813*1881cdb1SYouMin Chen redo_cs0_training: 814*1881cdb1SYouMin Chen if (data_training(dram, 0, sdram_params->dramtype) != 0) { 815*1881cdb1SYouMin Chen if (pre_init != 0) 816*1881cdb1SYouMin Chen printascii("DTT cs0 error\n"); 817*1881cdb1SYouMin Chen return -1; 818*1881cdb1SYouMin Chen } 819*1881cdb1SYouMin Chen if (check_rd_gate(dram)) { 820*1881cdb1SYouMin Chen printascii("re training cs0"); 821*1881cdb1SYouMin Chen goto redo_cs0_training; 822*1881cdb1SYouMin Chen } 823*1881cdb1SYouMin Chen 824*1881cdb1SYouMin Chen if (sdram_params->dramtype == LPDDR3) { 825*1881cdb1SYouMin Chen if ((read_mr(dram, 1, 8) & 0x3) != 0x3) 826*1881cdb1SYouMin Chen return -1; 827*1881cdb1SYouMin Chen } else if (sdram_params->dramtype == LPDDR2) { 828*1881cdb1SYouMin Chen if ((read_mr(dram, 1, 8) & 0x3) != 0x0) 829*1881cdb1SYouMin Chen return -1; 830*1881cdb1SYouMin Chen } 831*1881cdb1SYouMin Chen /* for px30: when 2cs, both 2 cs should be training */ 832*1881cdb1SYouMin Chen if (pre_init != 0 && sdram_params->ch.rank == 2) { 833*1881cdb1SYouMin Chen redo_cs1_training: 834*1881cdb1SYouMin Chen if (data_training(dram, 1, sdram_params->dramtype) != 0) { 835*1881cdb1SYouMin Chen printascii("DTT cs1 error\n"); 836*1881cdb1SYouMin Chen return -1; 837*1881cdb1SYouMin Chen } 838*1881cdb1SYouMin Chen if (check_rd_gate(dram)) { 839*1881cdb1SYouMin Chen printascii("re training cs1"); 840*1881cdb1SYouMin Chen goto redo_cs1_training; 841*1881cdb1SYouMin Chen } 842*1881cdb1SYouMin Chen } 843*1881cdb1SYouMin Chen 844*1881cdb1SYouMin Chen if (sdram_params->dramtype == DDR4) 845*1881cdb1SYouMin Chen write_vrefdq(dram, 0x3, 5670, sdram_params->dramtype); 846*1881cdb1SYouMin Chen 847*1881cdb1SYouMin Chen dram_all_config(dram, sdram_params); 848*1881cdb1SYouMin Chen enable_low_power(dram, sdram_params); 849*1881cdb1SYouMin Chen 850*1881cdb1SYouMin Chen return 0; 851*1881cdb1SYouMin Chen } 852*1881cdb1SYouMin Chen 853*1881cdb1SYouMin Chen static u64 dram_detect_cap(struct dram_info *dram, 854*1881cdb1SYouMin Chen struct px30_sdram_params *sdram_params, 855*1881cdb1SYouMin Chen unsigned char channel) 856*1881cdb1SYouMin Chen { 857*1881cdb1SYouMin Chen void __iomem *pctl_base = dram->pctl; 858*1881cdb1SYouMin Chen void __iomem *phy_base = dram->phy; 859*1881cdb1SYouMin Chen 860*1881cdb1SYouMin Chen /* 861*1881cdb1SYouMin Chen * for ddr3: ddrconf = 3 862*1881cdb1SYouMin Chen * for ddr4: ddrconf = 12 863*1881cdb1SYouMin Chen * for lpddr3: ddrconf = 3 864*1881cdb1SYouMin Chen * default bw = 1 865*1881cdb1SYouMin Chen */ 866*1881cdb1SYouMin Chen u32 bk, bktmp; 867*1881cdb1SYouMin Chen u32 col, coltmp; 868*1881cdb1SYouMin Chen u32 row, rowtmp, row_3_4; 869*1881cdb1SYouMin Chen void __iomem *test_addr, *test_addr1; 870*1881cdb1SYouMin Chen u32 dbw; 871*1881cdb1SYouMin Chen u32 cs; 872*1881cdb1SYouMin Chen u32 bw = 1; 873*1881cdb1SYouMin Chen u64 cap = 0; 874*1881cdb1SYouMin Chen u32 dram_type = sdram_params->dramtype; 875*1881cdb1SYouMin Chen u32 pwrctl; 876*1881cdb1SYouMin Chen 877*1881cdb1SYouMin Chen if (dram_type != DDR4) { 878*1881cdb1SYouMin Chen /* detect col and bk for ddr3/lpddr3 */ 879*1881cdb1SYouMin Chen coltmp = 12; 880*1881cdb1SYouMin Chen bktmp = 3; 881*1881cdb1SYouMin Chen rowtmp = 16; 882*1881cdb1SYouMin Chen 883*1881cdb1SYouMin Chen for (col = coltmp; col >= 9; col -= 1) { 884*1881cdb1SYouMin Chen writel(0, CONFIG_SYS_SDRAM_BASE); 885*1881cdb1SYouMin Chen test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE + 886*1881cdb1SYouMin Chen (1ul << (col + bw - 1ul))); 887*1881cdb1SYouMin Chen writel(PATTERN, test_addr); 888*1881cdb1SYouMin Chen if ((readl(test_addr) == PATTERN) && 889*1881cdb1SYouMin Chen (readl(CONFIG_SYS_SDRAM_BASE) == 0)) 890*1881cdb1SYouMin Chen break; 891*1881cdb1SYouMin Chen } 892*1881cdb1SYouMin Chen if (col == 8) { 893*1881cdb1SYouMin Chen printascii("col error\n"); 894*1881cdb1SYouMin Chen goto cap_err; 895*1881cdb1SYouMin Chen } 896*1881cdb1SYouMin Chen 897*1881cdb1SYouMin Chen test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE + 898*1881cdb1SYouMin Chen (1ul << (coltmp + bktmp + bw - 1ul))); 899*1881cdb1SYouMin Chen writel(0, CONFIG_SYS_SDRAM_BASE); 900*1881cdb1SYouMin Chen writel(PATTERN, test_addr); 901*1881cdb1SYouMin Chen if ((readl(test_addr) == PATTERN) && 902*1881cdb1SYouMin Chen (readl(CONFIG_SYS_SDRAM_BASE) == 0)) 903*1881cdb1SYouMin Chen bk = 3; 904*1881cdb1SYouMin Chen else 905*1881cdb1SYouMin Chen bk = 2; 906*1881cdb1SYouMin Chen if (dram_type == DDR3) 907*1881cdb1SYouMin Chen dbw = 1; 908*1881cdb1SYouMin Chen else 909*1881cdb1SYouMin Chen dbw = 2; 910*1881cdb1SYouMin Chen } else { 911*1881cdb1SYouMin Chen /* detect bg for ddr4 */ 912*1881cdb1SYouMin Chen coltmp = 10; 913*1881cdb1SYouMin Chen bktmp = 4; 914*1881cdb1SYouMin Chen rowtmp = 17; 915*1881cdb1SYouMin Chen 916*1881cdb1SYouMin Chen col = 10; 917*1881cdb1SYouMin Chen bk = 2; 918*1881cdb1SYouMin Chen test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE + 919*1881cdb1SYouMin Chen (1ul << (coltmp + bw + 1ul))); 920*1881cdb1SYouMin Chen writel(0, CONFIG_SYS_SDRAM_BASE); 921*1881cdb1SYouMin Chen writel(PATTERN, test_addr); 922*1881cdb1SYouMin Chen if ((readl(test_addr) == PATTERN) && 923*1881cdb1SYouMin Chen (readl(CONFIG_SYS_SDRAM_BASE) == 0)) 924*1881cdb1SYouMin Chen dbw = 0; 925*1881cdb1SYouMin Chen else 926*1881cdb1SYouMin Chen dbw = 1; 927*1881cdb1SYouMin Chen } 928*1881cdb1SYouMin Chen /* detect row */ 929*1881cdb1SYouMin Chen for (row = rowtmp; row > 12; row--) { 930*1881cdb1SYouMin Chen writel(0, CONFIG_SYS_SDRAM_BASE); 931*1881cdb1SYouMin Chen test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE + 932*1881cdb1SYouMin Chen (1ul << (row + bktmp + coltmp + bw - 1ul))); 933*1881cdb1SYouMin Chen writel(PATTERN, test_addr); 934*1881cdb1SYouMin Chen if ((readl(test_addr) == PATTERN) && 935*1881cdb1SYouMin Chen (readl(CONFIG_SYS_SDRAM_BASE) == 0)) 936*1881cdb1SYouMin Chen break; 937*1881cdb1SYouMin Chen } 938*1881cdb1SYouMin Chen if (row == 12) { 939*1881cdb1SYouMin Chen printascii("row error"); 940*1881cdb1SYouMin Chen goto cap_err; 941*1881cdb1SYouMin Chen } 942*1881cdb1SYouMin Chen /* detect row_3_4 */ 943*1881cdb1SYouMin Chen test_addr = CONFIG_SYS_SDRAM_BASE; 944*1881cdb1SYouMin Chen test_addr1 = (void __iomem *)(CONFIG_SYS_SDRAM_BASE + 945*1881cdb1SYouMin Chen (0x3ul << (row + bktmp + coltmp + bw - 1ul - 1ul))); 946*1881cdb1SYouMin Chen 947*1881cdb1SYouMin Chen writel(0, test_addr); 948*1881cdb1SYouMin Chen writel(PATTERN, test_addr1); 949*1881cdb1SYouMin Chen if ((readl(test_addr) == 0) && 950*1881cdb1SYouMin Chen (readl(test_addr1) == PATTERN)) 951*1881cdb1SYouMin Chen row_3_4 = 0; 952*1881cdb1SYouMin Chen else 953*1881cdb1SYouMin Chen row_3_4 = 1; 954*1881cdb1SYouMin Chen 955*1881cdb1SYouMin Chen /* disable auto low-power */ 956*1881cdb1SYouMin Chen pwrctl = readl(pctl_base + DDR_PCTL2_PWRCTL); 957*1881cdb1SYouMin Chen writel(0, pctl_base + DDR_PCTL2_PWRCTL); 958*1881cdb1SYouMin Chen 959*1881cdb1SYouMin Chen /* bw and cs detect using phy read gate training */ 960*1881cdb1SYouMin Chen if (data_training(dram, 1, dram_type) == 0) 961*1881cdb1SYouMin Chen cs = 1; 962*1881cdb1SYouMin Chen else 963*1881cdb1SYouMin Chen cs = 0; 964*1881cdb1SYouMin Chen 965*1881cdb1SYouMin Chen clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 0xf << 4); 966*1881cdb1SYouMin Chen setbits_le32(PHY_REG(phy_base, 0x46), 1 << 3); 967*1881cdb1SYouMin Chen setbits_le32(PHY_REG(phy_base, 0x56), 1 << 3); 968*1881cdb1SYouMin Chen 969*1881cdb1SYouMin Chen phy_soft_reset(dram); 970*1881cdb1SYouMin Chen 971*1881cdb1SYouMin Chen if (data_training(dram, 0, dram_type) == 0) 972*1881cdb1SYouMin Chen bw = 2; 973*1881cdb1SYouMin Chen else 974*1881cdb1SYouMin Chen bw = 1; 975*1881cdb1SYouMin Chen 976*1881cdb1SYouMin Chen /* restore auto low-power */ 977*1881cdb1SYouMin Chen writel(pwrctl, pctl_base + DDR_PCTL2_PWRCTL); 978*1881cdb1SYouMin Chen 979*1881cdb1SYouMin Chen sdram_params->ch.rank = cs + 1; 980*1881cdb1SYouMin Chen sdram_params->ch.col = col; 981*1881cdb1SYouMin Chen sdram_params->ch.bk = bk; 982*1881cdb1SYouMin Chen sdram_params->ch.dbw = dbw; 983*1881cdb1SYouMin Chen sdram_params->ch.bw = bw; 984*1881cdb1SYouMin Chen sdram_params->ch.cs0_row = row; 985*1881cdb1SYouMin Chen sdram_params->ch.cs0_high16bit_row = row; 986*1881cdb1SYouMin Chen if (cs) { 987*1881cdb1SYouMin Chen sdram_params->ch.cs1_row = row; 988*1881cdb1SYouMin Chen sdram_params->ch.cs1_high16bit_row = row; 989*1881cdb1SYouMin Chen } else { 990*1881cdb1SYouMin Chen sdram_params->ch.cs1_row = 0; 991*1881cdb1SYouMin Chen sdram_params->ch.cs1_high16bit_row = 0; 992*1881cdb1SYouMin Chen } 993*1881cdb1SYouMin Chen sdram_params->ch.row_3_4 = row_3_4; 994*1881cdb1SYouMin Chen 995*1881cdb1SYouMin Chen if (dram_type == DDR4) 996*1881cdb1SYouMin Chen cap = 1llu << (cs + row + bk + col + ((dbw == 0) ? 2 : 1) + bw); 997*1881cdb1SYouMin Chen else 998*1881cdb1SYouMin Chen cap = 1llu << (cs + row + bk + col + bw); 999*1881cdb1SYouMin Chen 1000*1881cdb1SYouMin Chen return cap; 1001*1881cdb1SYouMin Chen 1002*1881cdb1SYouMin Chen cap_err: 1003*1881cdb1SYouMin Chen return 0; 1004*1881cdb1SYouMin Chen } 1005*1881cdb1SYouMin Chen 1006*1881cdb1SYouMin Chen static u32 remodify_sdram_params(struct px30_sdram_params *sdram_params) 1007*1881cdb1SYouMin Chen { 1008*1881cdb1SYouMin Chen u32 tmp = 0, tmp_adr = 0, i; 1009*1881cdb1SYouMin Chen 1010*1881cdb1SYouMin Chen for (i = 0; sdram_params->pctl_regs.pctl[i][0] != 0xFFFFFFFF; i++) { 1011*1881cdb1SYouMin Chen if (sdram_params->pctl_regs.pctl[i][0] == 0) { 1012*1881cdb1SYouMin Chen tmp = sdram_params->pctl_regs.pctl[i][1];/* MSTR */ 1013*1881cdb1SYouMin Chen tmp_adr = i; 1014*1881cdb1SYouMin Chen } 1015*1881cdb1SYouMin Chen } 1016*1881cdb1SYouMin Chen 1017*1881cdb1SYouMin Chen tmp &= ~((3ul << 30) | (3ul << 24) | (3ul << 12)); 1018*1881cdb1SYouMin Chen 1019*1881cdb1SYouMin Chen switch (sdram_params->ch.dbw) { 1020*1881cdb1SYouMin Chen case 2: 1021*1881cdb1SYouMin Chen tmp |= (3ul << 30); 1022*1881cdb1SYouMin Chen break; 1023*1881cdb1SYouMin Chen case 1: 1024*1881cdb1SYouMin Chen tmp |= (2ul << 30); 1025*1881cdb1SYouMin Chen break; 1026*1881cdb1SYouMin Chen case 0: 1027*1881cdb1SYouMin Chen default: 1028*1881cdb1SYouMin Chen tmp |= (1ul << 30); 1029*1881cdb1SYouMin Chen break; 1030*1881cdb1SYouMin Chen } 1031*1881cdb1SYouMin Chen 1032*1881cdb1SYouMin Chen if (sdram_params->ch.rank == 2) 1033*1881cdb1SYouMin Chen tmp |= 3 << 24; 1034*1881cdb1SYouMin Chen else 1035*1881cdb1SYouMin Chen tmp |= 1 << 24; 1036*1881cdb1SYouMin Chen 1037*1881cdb1SYouMin Chen tmp |= (2 - sdram_params->ch.bw) << 12; 1038*1881cdb1SYouMin Chen 1039*1881cdb1SYouMin Chen sdram_params->pctl_regs.pctl[tmp_adr][1] = tmp; 1040*1881cdb1SYouMin Chen 1041*1881cdb1SYouMin Chen return 0; 1042*1881cdb1SYouMin Chen } 1043*1881cdb1SYouMin Chen 1044*1881cdb1SYouMin Chen int dram_detect_high_row(struct dram_info *dram, 1045*1881cdb1SYouMin Chen struct px30_sdram_params *sdram_params, 1046*1881cdb1SYouMin Chen unsigned char channel) 1047*1881cdb1SYouMin Chen { 1048*1881cdb1SYouMin Chen sdram_params->ch.cs0_high16bit_row = sdram_params->ch.cs0_row; 1049*1881cdb1SYouMin Chen sdram_params->ch.cs1_high16bit_row = sdram_params->ch.cs1_row; 1050*1881cdb1SYouMin Chen 1051*1881cdb1SYouMin Chen return 0; 1052*1881cdb1SYouMin Chen } 1053*1881cdb1SYouMin Chen 1054*1881cdb1SYouMin Chen static int dram_detect_cs1_row(struct px30_sdram_params *sdram_params, 1055*1881cdb1SYouMin Chen unsigned char channel) 1056*1881cdb1SYouMin Chen { 1057*1881cdb1SYouMin Chen u32 ret = 0; 1058*1881cdb1SYouMin Chen void __iomem *test_addr; 1059*1881cdb1SYouMin Chen u32 row, bktmp, coltmp, bw; 1060*1881cdb1SYouMin Chen u64 cs0_cap; 1061*1881cdb1SYouMin Chen u32 byte_mask; 1062*1881cdb1SYouMin Chen 1063*1881cdb1SYouMin Chen if (sdram_params->ch.rank == 2) { 1064*1881cdb1SYouMin Chen cs0_cap = get_cs_cap(sdram_params, 0); 1065*1881cdb1SYouMin Chen 1066*1881cdb1SYouMin Chen if (sdram_params->dramtype == DDR4) { 1067*1881cdb1SYouMin Chen if (sdram_params->ch.dbw == 0) 1068*1881cdb1SYouMin Chen bktmp = sdram_params->ch.bk + 2; 1069*1881cdb1SYouMin Chen else 1070*1881cdb1SYouMin Chen bktmp = sdram_params->ch.bk + 1; 1071*1881cdb1SYouMin Chen } else { 1072*1881cdb1SYouMin Chen bktmp = sdram_params->ch.bk; 1073*1881cdb1SYouMin Chen } 1074*1881cdb1SYouMin Chen bw = sdram_params->ch.bw; 1075*1881cdb1SYouMin Chen coltmp = sdram_params->ch.col; 1076*1881cdb1SYouMin Chen 1077*1881cdb1SYouMin Chen /* 1078*1881cdb1SYouMin Chen * because px30 support axi split,min bandwidth 1079*1881cdb1SYouMin Chen * is 8bit. if cs0 is 32bit, cs1 may 32bit or 16bit 1080*1881cdb1SYouMin Chen * so we check low 16bit data when detect cs1 row. 1081*1881cdb1SYouMin Chen * if cs0 is 16bit/8bit, we check low 8bit data. 1082*1881cdb1SYouMin Chen */ 1083*1881cdb1SYouMin Chen if (bw == 2) 1084*1881cdb1SYouMin Chen byte_mask = 0xFFFF; 1085*1881cdb1SYouMin Chen else 1086*1881cdb1SYouMin Chen byte_mask = 0xFF; 1087*1881cdb1SYouMin Chen 1088*1881cdb1SYouMin Chen /* detect cs1 row */ 1089*1881cdb1SYouMin Chen for (row = sdram_params->ch.cs0_row; row > 12; row--) { 1090*1881cdb1SYouMin Chen test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE + 1091*1881cdb1SYouMin Chen cs0_cap + 1092*1881cdb1SYouMin Chen (1ul << (row + bktmp + coltmp + bw - 1ul))); 1093*1881cdb1SYouMin Chen writel(0, CONFIG_SYS_SDRAM_BASE + cs0_cap); 1094*1881cdb1SYouMin Chen writel(PATTERN, test_addr); 1095*1881cdb1SYouMin Chen 1096*1881cdb1SYouMin Chen if (((readl(test_addr) & byte_mask) == 1097*1881cdb1SYouMin Chen (PATTERN & byte_mask)) && 1098*1881cdb1SYouMin Chen ((readl(CONFIG_SYS_SDRAM_BASE + cs0_cap) & 1099*1881cdb1SYouMin Chen byte_mask) == 0)) { 1100*1881cdb1SYouMin Chen ret = row; 1101*1881cdb1SYouMin Chen break; 1102*1881cdb1SYouMin Chen } 1103*1881cdb1SYouMin Chen } 1104*1881cdb1SYouMin Chen } 1105*1881cdb1SYouMin Chen 1106*1881cdb1SYouMin Chen return ret; 1107*1881cdb1SYouMin Chen } 1108*1881cdb1SYouMin Chen 1109*1881cdb1SYouMin Chen /* return: 0 = success, other = fail */ 1110*1881cdb1SYouMin Chen static int sdram_init_detect(struct dram_info *dram, 1111*1881cdb1SYouMin Chen struct px30_sdram_params *sdram_params) 1112*1881cdb1SYouMin Chen { 1113*1881cdb1SYouMin Chen u32 ret; 1114*1881cdb1SYouMin Chen u32 sys_reg = 0; 1115*1881cdb1SYouMin Chen u32 sys_reg3 = 0; 1116*1881cdb1SYouMin Chen 1117*1881cdb1SYouMin Chen if (sdram_init_(dram, sdram_params, 0) != 0) 1118*1881cdb1SYouMin Chen return -1; 1119*1881cdb1SYouMin Chen 1120*1881cdb1SYouMin Chen if (dram_detect_cap(dram, sdram_params, 0) == 0) 1121*1881cdb1SYouMin Chen return -1; 1122*1881cdb1SYouMin Chen 1123*1881cdb1SYouMin Chen /* modify bw, cs related timing */ 1124*1881cdb1SYouMin Chen remodify_sdram_params(sdram_params); 1125*1881cdb1SYouMin Chen /* reinit sdram by real dram cap */ 1126*1881cdb1SYouMin Chen ret = sdram_init_(dram, sdram_params, 1); 1127*1881cdb1SYouMin Chen if (ret != 0) 1128*1881cdb1SYouMin Chen goto out; 1129*1881cdb1SYouMin Chen 1130*1881cdb1SYouMin Chen /* redetect cs1 row */ 1131*1881cdb1SYouMin Chen sdram_params->ch.cs1_row = 1132*1881cdb1SYouMin Chen dram_detect_cs1_row(sdram_params, 0); 1133*1881cdb1SYouMin Chen if (sdram_params->ch.cs1_row) { 1134*1881cdb1SYouMin Chen sys_reg = readl(&dram->pmugrf->os_reg[2]); 1135*1881cdb1SYouMin Chen sys_reg3 = readl(&dram->pmugrf->os_reg[3]); 1136*1881cdb1SYouMin Chen SYS_REG_ENC_CS1_ROW_(sdram_params->ch.cs1_row, 1137*1881cdb1SYouMin Chen sys_reg, sys_reg3); 1138*1881cdb1SYouMin Chen writel(sys_reg, &dram->pmugrf->os_reg[2]); 1139*1881cdb1SYouMin Chen writel(sys_reg3, &dram->pmugrf->os_reg[3]); 1140*1881cdb1SYouMin Chen } 1141*1881cdb1SYouMin Chen 1142*1881cdb1SYouMin Chen ret = dram_detect_high_row(dram, sdram_params, 0); 1143*1881cdb1SYouMin Chen 1144*1881cdb1SYouMin Chen out: 1145*1881cdb1SYouMin Chen return ret; 1146*1881cdb1SYouMin Chen } 1147*1881cdb1SYouMin Chen 1148*1881cdb1SYouMin Chen struct px30_sdram_params 1149*1881cdb1SYouMin Chen *get_default_sdram_config(void) 1150*1881cdb1SYouMin Chen { 1151*1881cdb1SYouMin Chen sdram_configs[0].skew = &skew; 1152*1881cdb1SYouMin Chen 1153*1881cdb1SYouMin Chen return &sdram_configs[0]; 1154*1881cdb1SYouMin Chen } 1155*1881cdb1SYouMin Chen 1156*1881cdb1SYouMin Chen /* return: 0 = success, other = fail */ 1157*1881cdb1SYouMin Chen int sdram_init(void) 1158*1881cdb1SYouMin Chen { 1159*1881cdb1SYouMin Chen struct px30_sdram_params *sdram_params; 1160*1881cdb1SYouMin Chen int ret = 0; 1161*1881cdb1SYouMin Chen 1162*1881cdb1SYouMin Chen printascii("DDR Init V1.07\n"); 1163*1881cdb1SYouMin Chen 1164*1881cdb1SYouMin Chen dram_info.phy = (void *)DDR_PHY_BASE_ADDR; 1165*1881cdb1SYouMin Chen dram_info.pctl = (void *)DDRC_BASE_ADDR; 1166*1881cdb1SYouMin Chen dram_info.grf = (void *)GRF_BASE_ADDR; 1167*1881cdb1SYouMin Chen dram_info.cru = (void *)CRU_BASE_ADDR; 1168*1881cdb1SYouMin Chen dram_info.msch = (void *)SERVER_MSCH0_BASE_ADDR; 1169*1881cdb1SYouMin Chen dram_info.ddr_grf = (void *)DDR_GRF_BASE_ADDR; 1170*1881cdb1SYouMin Chen dram_info.pmugrf = (void *)PMUGRF_BASE_ADDR; 1171*1881cdb1SYouMin Chen 1172*1881cdb1SYouMin Chen sdram_params = get_default_sdram_config(); 1173*1881cdb1SYouMin Chen ret = sdram_init_detect(&dram_info, sdram_params); 1174*1881cdb1SYouMin Chen 1175*1881cdb1SYouMin Chen if (ret) 1176*1881cdb1SYouMin Chen goto error; 1177*1881cdb1SYouMin Chen 1178*1881cdb1SYouMin Chen printascii("out\n"); 1179*1881cdb1SYouMin Chen return ret; 1180*1881cdb1SYouMin Chen error: 1181*1881cdb1SYouMin Chen return (-1); 1182*1881cdb1SYouMin Chen } 1183*1881cdb1SYouMin Chen 1184*1881cdb1SYouMin Chen #else /* CONFIG_TPL_BUILD */ 1185*1881cdb1SYouMin Chen 11865eeb396bSKever Yang static int px30_dmc_probe(struct udevice *dev) 11875eeb396bSKever Yang { 11885eeb396bSKever Yang struct dram_info *priv = dev_get_priv(dev); 11895eeb396bSKever Yang 119089f991f8SJoseph Chen priv->pmugrf = syscon_get_first_range(ROCKCHIP_SYSCON_PMUGRF); 11915eeb396bSKever Yang debug("%s: pmugrf=%p\n", __func__, priv->pmugrf); 11925eeb396bSKever Yang priv->info.base = CONFIG_SYS_SDRAM_BASE; 1193*1881cdb1SYouMin Chen priv->info.size = 1194*1881cdb1SYouMin Chen rockchip_sdram_size((phys_addr_t)&priv->pmugrf->os_reg[2]); 11955eeb396bSKever Yang 11965eeb396bSKever Yang return 0; 11975eeb396bSKever Yang } 11985eeb396bSKever Yang 11995eeb396bSKever Yang static int px30_dmc_get_info(struct udevice *dev, struct ram_info *info) 12005eeb396bSKever Yang { 12015eeb396bSKever Yang struct dram_info *priv = dev_get_priv(dev); 12025eeb396bSKever Yang 12035eeb396bSKever Yang *info = priv->info; 12045eeb396bSKever Yang 12055eeb396bSKever Yang return 0; 12065eeb396bSKever Yang } 12075eeb396bSKever Yang 12085eeb396bSKever Yang static struct ram_ops px30_dmc_ops = { 12095eeb396bSKever Yang .get_info = px30_dmc_get_info, 12105eeb396bSKever Yang }; 12115eeb396bSKever Yang 12125eeb396bSKever Yang static const struct udevice_id px30_dmc_ids[] = { 12135eeb396bSKever Yang { .compatible = "rockchip,px30-dmc" }, 12145eeb396bSKever Yang { } 12155eeb396bSKever Yang }; 12165eeb396bSKever Yang 12175eeb396bSKever Yang U_BOOT_DRIVER(dmc_px30) = { 12185eeb396bSKever Yang .name = "rockchip_px30_dmc", 12195eeb396bSKever Yang .id = UCLASS_RAM, 12205eeb396bSKever Yang .of_match = px30_dmc_ids, 12215eeb396bSKever Yang .ops = &px30_dmc_ops, 12225eeb396bSKever Yang .probe = px30_dmc_probe, 12235eeb396bSKever Yang .priv_auto_alloc_size = sizeof(struct dram_info), 12245eeb396bSKever Yang }; 1225*1881cdb1SYouMin Chen #endif /* CONFIG_TPL_BUILD */ 1226