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>
16e1f97ec3SYouMin Chen #include <asm/arch/sdram.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 {
3355c5751eSYouMin Chen struct ddr_pctl_regs *pctl;
3455c5751eSYouMin Chen struct ddr_phy_regs *phy;
351881cdb1SYouMin Chen struct px30_cru *cru;
3655c5751eSYouMin Chen struct 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[] = {
54c90232abSKever Yang #ifdef CONFIG_ROCKCHIP_RK3326
55c90232abSKever Yang #include "sdram-px30-lpddr3-detect-333.inc"
56c90232abSKever Yang #else
5793db2afcSKever Yang #include "sdram-px30-ddr3-detect-333.inc"
58c90232abSKever Yang #endif
591881cdb1SYouMin Chen };
601881cdb1SYouMin Chen
6155c5751eSYouMin Chen struct ddr_phy_skew skew = {
621881cdb1SYouMin Chen #include "sdram-px30-ddr_skew.inc"
631881cdb1SYouMin Chen };
641881cdb1SYouMin Chen
rkclk_ddr_reset(struct dram_info * dram,u32 ctl_srstn,u32 ctl_psrstn,u32 phy_srstn,u32 phy_psrstn)651881cdb1SYouMin Chen static void rkclk_ddr_reset(struct dram_info *dram,
661881cdb1SYouMin Chen u32 ctl_srstn, u32 ctl_psrstn,
671881cdb1SYouMin Chen u32 phy_srstn, u32 phy_psrstn)
681881cdb1SYouMin Chen {
691881cdb1SYouMin Chen writel(upctl2_srstn_req(ctl_srstn) | upctl2_psrstn_req(ctl_psrstn) |
701881cdb1SYouMin Chen upctl2_asrstn_req(ctl_srstn),
711881cdb1SYouMin Chen &dram->cru->softrst_con[1]);
721881cdb1SYouMin Chen writel(ddrphy_srstn_req(phy_srstn) | ddrphy_psrstn_req(phy_psrstn),
731881cdb1SYouMin Chen &dram->cru->softrst_con[2]);
741881cdb1SYouMin Chen }
751881cdb1SYouMin Chen
rkclk_set_dpll(struct dram_info * dram,unsigned int hz)7655c5751eSYouMin Chen static void rkclk_set_dpll(struct dram_info *dram, unsigned int hz)
771881cdb1SYouMin Chen {
781881cdb1SYouMin Chen unsigned int refdiv, postdiv1, postdiv2, fbdiv;
791881cdb1SYouMin Chen int delay = 1000;
8055c5751eSYouMin Chen u32 mhz = hz / MHz;
811881cdb1SYouMin Chen
821881cdb1SYouMin Chen refdiv = 1;
831881cdb1SYouMin Chen if (mhz <= 300) {
841881cdb1SYouMin Chen postdiv1 = 4;
851881cdb1SYouMin Chen postdiv2 = 2;
861881cdb1SYouMin Chen } else if (mhz <= 400) {
871881cdb1SYouMin Chen postdiv1 = 6;
881881cdb1SYouMin Chen postdiv2 = 1;
891881cdb1SYouMin Chen } else if (mhz <= 600) {
901881cdb1SYouMin Chen postdiv1 = 4;
911881cdb1SYouMin Chen postdiv2 = 1;
921881cdb1SYouMin Chen } else if (mhz <= 800) {
931881cdb1SYouMin Chen postdiv1 = 3;
941881cdb1SYouMin Chen postdiv2 = 1;
951881cdb1SYouMin Chen } else if (mhz <= 1600) {
961881cdb1SYouMin Chen postdiv1 = 2;
971881cdb1SYouMin Chen postdiv2 = 1;
981881cdb1SYouMin Chen } else {
991881cdb1SYouMin Chen postdiv1 = 1;
1001881cdb1SYouMin Chen postdiv2 = 1;
1011881cdb1SYouMin Chen }
1021881cdb1SYouMin Chen fbdiv = (mhz * refdiv * postdiv1 * postdiv2) / 24;
1031881cdb1SYouMin Chen
1041881cdb1SYouMin Chen writel(DPLL_MODE(CLOCK_FROM_XIN_OSC), &dram->cru->mode);
1051881cdb1SYouMin Chen
1061881cdb1SYouMin Chen writel(POSTDIV1(postdiv1) | FBDIV(fbdiv), &dram->cru->pll[1].con0);
1071881cdb1SYouMin Chen writel(DSMPD(1) | POSTDIV2(postdiv2) | REFDIV(refdiv),
1081881cdb1SYouMin Chen &dram->cru->pll[1].con1);
1091881cdb1SYouMin Chen
1101881cdb1SYouMin Chen while (delay > 0) {
1111881cdb1SYouMin Chen udelay(1);
1121881cdb1SYouMin Chen if (LOCK(readl(&dram->cru->pll[1].con1)))
1131881cdb1SYouMin Chen break;
1141881cdb1SYouMin Chen delay--;
1151881cdb1SYouMin Chen }
1161881cdb1SYouMin Chen
1171881cdb1SYouMin Chen writel(DPLL_MODE(CLOCK_FROM_PLL), &dram->cru->mode);
1181881cdb1SYouMin Chen }
1191881cdb1SYouMin Chen
rkclk_configure_ddr(struct dram_info * dram,struct px30_sdram_params * sdram_params)1201881cdb1SYouMin Chen static void rkclk_configure_ddr(struct dram_info *dram,
1211881cdb1SYouMin Chen struct px30_sdram_params *sdram_params)
1221881cdb1SYouMin Chen {
123*5d4a323cSTang Yun ping /* for ddr phy need 2*freq */
12455c5751eSYouMin Chen rkclk_set_dpll(dram, sdram_params->base.ddr_freq * MHz * 2);
1251881cdb1SYouMin Chen }
1261881cdb1SYouMin Chen
1271881cdb1SYouMin Chen /* return ddrconfig value
1281881cdb1SYouMin Chen * (-1), find ddrconfig fail
1291881cdb1SYouMin Chen * other, the ddrconfig value
1301881cdb1SYouMin Chen * only support cs0_row >= cs1_row
1311881cdb1SYouMin Chen */
calculate_ddrconfig(struct px30_sdram_params * sdram_params)1321881cdb1SYouMin Chen static unsigned int calculate_ddrconfig(struct px30_sdram_params *sdram_params)
1331881cdb1SYouMin Chen {
13455c5751eSYouMin Chen struct sdram_cap_info *cap_info = &sdram_params->ch.cap_info;
1351881cdb1SYouMin Chen u32 bw, die_bw, col, bank;
1361881cdb1SYouMin Chen u32 i, tmp;
1371881cdb1SYouMin Chen u32 ddrconf = -1;
1381881cdb1SYouMin Chen
13955c5751eSYouMin Chen bw = cap_info->bw;
14055c5751eSYouMin Chen die_bw = cap_info->dbw;
14155c5751eSYouMin Chen col = cap_info->col;
14255c5751eSYouMin Chen bank = cap_info->bk;
1431881cdb1SYouMin Chen
14455c5751eSYouMin Chen if (sdram_params->base.dramtype == DDR4) {
1451881cdb1SYouMin Chen if (die_bw == 0)
1461881cdb1SYouMin Chen ddrconf = 7 + bw;
1471881cdb1SYouMin Chen else
1481881cdb1SYouMin Chen ddrconf = 12 - bw;
1491881cdb1SYouMin Chen ddrconf = d4_rbc_2_d3_rbc[ddrconf - 7];
1501881cdb1SYouMin Chen } else {
1511881cdb1SYouMin Chen tmp = ((bank - 2) << 3) | (col + bw - 10);
1521881cdb1SYouMin Chen for (i = 0; i < 7; i++)
1531881cdb1SYouMin Chen if ((ddr_cfg_2_rbc[i] & 0xf) == tmp) {
1541881cdb1SYouMin Chen ddrconf = i;
1551881cdb1SYouMin Chen break;
1561881cdb1SYouMin Chen }
1571881cdb1SYouMin Chen if (i > 6)
1581881cdb1SYouMin Chen printascii("calculate ddrconfig error\n");
1591881cdb1SYouMin Chen }
1601881cdb1SYouMin Chen
1611881cdb1SYouMin Chen return ddrconf;
1621881cdb1SYouMin Chen }
1631881cdb1SYouMin Chen
1641881cdb1SYouMin Chen /*
1651881cdb1SYouMin Chen * calculate controller dram address map, and setting to register.
1661881cdb1SYouMin Chen * argument sdram_params->ch.ddrconf must be right value before
1671881cdb1SYouMin Chen * call this function.
1681881cdb1SYouMin Chen */
set_ctl_address_map(struct dram_info * dram,struct px30_sdram_params * sdram_params)1691881cdb1SYouMin Chen static void set_ctl_address_map(struct dram_info *dram,
1701881cdb1SYouMin Chen struct px30_sdram_params *sdram_params)
1711881cdb1SYouMin Chen {
17255c5751eSYouMin Chen struct sdram_cap_info *cap_info = &sdram_params->ch.cap_info;
1731881cdb1SYouMin Chen void __iomem *pctl_base = dram->pctl;
1741881cdb1SYouMin Chen u32 cs_pst, bg, max_row, ddrconf;
1751881cdb1SYouMin Chen u32 i;
1761881cdb1SYouMin Chen
17755c5751eSYouMin Chen if (sdram_params->base.dramtype == DDR4)
1781881cdb1SYouMin Chen /*
1791881cdb1SYouMin Chen * DDR4 8bit dram BG = 2(4bank groups),
1801881cdb1SYouMin Chen * 16bit dram BG = 1 (2 bank groups)
1811881cdb1SYouMin Chen */
18255c5751eSYouMin Chen bg = (cap_info->dbw == 0) ? 2 : 1;
1831881cdb1SYouMin Chen else
1841881cdb1SYouMin Chen bg = 0;
1851881cdb1SYouMin Chen
18655c5751eSYouMin Chen cs_pst = cap_info->bw + cap_info->col +
18755c5751eSYouMin Chen bg + cap_info->bk + cap_info->cs0_row;
18855c5751eSYouMin Chen if (cs_pst >= 32 || cap_info->rank == 1)
1891881cdb1SYouMin Chen writel(0x1f, pctl_base + DDR_PCTL2_ADDRMAP0);
1901881cdb1SYouMin Chen else
1911881cdb1SYouMin Chen writel(cs_pst - 8, pctl_base + DDR_PCTL2_ADDRMAP0);
1921881cdb1SYouMin Chen
19355c5751eSYouMin Chen ddrconf = cap_info->ddrconfig;
19455c5751eSYouMin Chen if (sdram_params->base.dramtype == DDR4) {
1951881cdb1SYouMin Chen for (i = 0; i < ARRAY_SIZE(d4_rbc_2_d3_rbc); i++) {
1961881cdb1SYouMin Chen if (d4_rbc_2_d3_rbc[i] == ddrconf) {
1971881cdb1SYouMin Chen ddrconf = 7 + i;
1981881cdb1SYouMin Chen break;
1991881cdb1SYouMin Chen }
2001881cdb1SYouMin Chen }
2011881cdb1SYouMin Chen }
2021881cdb1SYouMin Chen
20355c5751eSYouMin Chen sdram_copy_to_reg((u32 *)(pctl_base + DDR_PCTL2_ADDRMAP1),
2041881cdb1SYouMin Chen &addrmap[ddrconf][0], 8 * 4);
2051881cdb1SYouMin Chen max_row = cs_pst - 1 - 8 - (addrmap[ddrconf][5] & 0xf);
2061881cdb1SYouMin Chen
2071881cdb1SYouMin Chen if (max_row < 12)
2081881cdb1SYouMin Chen printascii("set addrmap fail\n");
2091881cdb1SYouMin Chen /* need to disable row ahead of rank by set to 0xf */
2101881cdb1SYouMin Chen for (i = 17; i > max_row; i--)
2111881cdb1SYouMin Chen clrsetbits_le32(pctl_base + DDR_PCTL2_ADDRMAP6 +
2121881cdb1SYouMin Chen ((i - 12) * 8 / 32) * 4,
2131881cdb1SYouMin Chen 0xf << ((i - 12) * 8 % 32),
2141881cdb1SYouMin Chen 0xf << ((i - 12) * 8 % 32));
2151881cdb1SYouMin Chen
21655c5751eSYouMin Chen if ((sdram_params->base.dramtype == LPDDR3 ||
21755c5751eSYouMin Chen sdram_params->base.dramtype == LPDDR2) &&
21855c5751eSYouMin Chen cap_info->row_3_4)
2191881cdb1SYouMin Chen setbits_le32(pctl_base + DDR_PCTL2_ADDRMAP6, 1 << 31);
22055c5751eSYouMin Chen if (sdram_params->base.dramtype == DDR4 && cap_info->bw != 0x2)
2211881cdb1SYouMin Chen setbits_le32(pctl_base + DDR_PCTL2_PCCFG, 1 << 8);
2221881cdb1SYouMin Chen }
2231881cdb1SYouMin Chen
2241881cdb1SYouMin Chen /*
2251881cdb1SYouMin Chen * rank = 1: cs0
2261881cdb1SYouMin Chen * rank = 2: cs1
2271881cdb1SYouMin Chen */
read_mr(struct dram_info * dram,u32 rank,u32 mr_num)2281881cdb1SYouMin Chen int read_mr(struct dram_info *dram, u32 rank, u32 mr_num)
2291881cdb1SYouMin Chen {
2301881cdb1SYouMin Chen void __iomem *ddr_grf_base = dram->ddr_grf;
2311881cdb1SYouMin Chen
23255c5751eSYouMin Chen pctl_read_mr(dram->pctl, rank, mr_num);
2331881cdb1SYouMin Chen
2341881cdb1SYouMin Chen return (readl(ddr_grf_base + DDR_GRF_STATUS(0)) & 0xff);
2351881cdb1SYouMin Chen }
2361881cdb1SYouMin Chen
2371881cdb1SYouMin Chen #define MIN(a, b) (((a) > (b)) ? (b) : (a))
2381881cdb1SYouMin Chen #define MAX(a, b) (((a) > (b)) ? (a) : (b))
check_rd_gate(struct dram_info * dram)2391881cdb1SYouMin Chen static u32 check_rd_gate(struct dram_info *dram)
2401881cdb1SYouMin Chen {
2411881cdb1SYouMin Chen void __iomem *phy_base = dram->phy;
2421881cdb1SYouMin Chen
2431881cdb1SYouMin Chen u32 max_val = 0;
2441881cdb1SYouMin Chen u32 min_val = 0xff;
2451881cdb1SYouMin Chen u32 gate[4];
2461881cdb1SYouMin Chen u32 i, bw;
2471881cdb1SYouMin Chen
2481881cdb1SYouMin Chen bw = (readl(PHY_REG(phy_base, 0x0)) >> 4) & 0xf;
2491881cdb1SYouMin Chen switch (bw) {
2501881cdb1SYouMin Chen case 0x1:
2511881cdb1SYouMin Chen bw = 1;
2521881cdb1SYouMin Chen break;
2531881cdb1SYouMin Chen case 0x3:
2541881cdb1SYouMin Chen bw = 2;
2551881cdb1SYouMin Chen break;
2561881cdb1SYouMin Chen case 0xf:
2571881cdb1SYouMin Chen default:
2581881cdb1SYouMin Chen bw = 4;
2591881cdb1SYouMin Chen break;
2601881cdb1SYouMin Chen }
2611881cdb1SYouMin Chen
2621881cdb1SYouMin Chen for (i = 0; i < bw; i++) {
2631881cdb1SYouMin Chen gate[i] = readl(PHY_REG(phy_base, 0xfb + i));
2641881cdb1SYouMin Chen max_val = MAX(max_val, gate[i]);
2651881cdb1SYouMin Chen min_val = MIN(min_val, gate[i]);
2661881cdb1SYouMin Chen }
2671881cdb1SYouMin Chen
2681881cdb1SYouMin Chen if (max_val > 0x80 || min_val < 0x20)
2691881cdb1SYouMin Chen return -1;
2701881cdb1SYouMin Chen else
2711881cdb1SYouMin Chen return 0;
2721881cdb1SYouMin Chen }
2731881cdb1SYouMin Chen
data_training(struct dram_info * dram,u32 cs,u32 dramtype)2741881cdb1SYouMin Chen static int data_training(struct dram_info *dram, u32 cs, u32 dramtype)
2751881cdb1SYouMin Chen {
27655c5751eSYouMin Chen void __iomem *pctl_base = dram->pctl;
2771881cdb1SYouMin Chen u32 dis_auto_zq = 0;
27855c5751eSYouMin Chen u32 pwrctl;
27955c5751eSYouMin Chen u32 ret;
2801881cdb1SYouMin Chen
28155c5751eSYouMin Chen /* disable auto low-power */
28255c5751eSYouMin Chen pwrctl = readl(pctl_base + DDR_PCTL2_PWRCTL);
28355c5751eSYouMin Chen writel(0, pctl_base + DDR_PCTL2_PWRCTL);
2841881cdb1SYouMin Chen
28555c5751eSYouMin Chen dis_auto_zq = pctl_dis_zqcs_aref(dram->pctl);
2861881cdb1SYouMin Chen
28755c5751eSYouMin Chen ret = phy_data_training(dram->phy, cs, dramtype);
2881881cdb1SYouMin Chen
28955c5751eSYouMin Chen pctl_rest_zqcs_aref(dram->pctl, dis_auto_zq);
2901881cdb1SYouMin Chen
29155c5751eSYouMin Chen /* restore auto low-power */
29255c5751eSYouMin Chen writel(pwrctl, pctl_base + DDR_PCTL2_PWRCTL);
2931881cdb1SYouMin Chen
2941881cdb1SYouMin Chen return ret;
2951881cdb1SYouMin Chen }
2961881cdb1SYouMin Chen
dram_set_bw(struct dram_info * dram,u32 bw)29755c5751eSYouMin Chen static void dram_set_bw(struct dram_info *dram, u32 bw)
2981881cdb1SYouMin Chen {
29955c5751eSYouMin Chen phy_dram_set_bw(dram->phy, bw);
3001881cdb1SYouMin Chen }
3011881cdb1SYouMin Chen
set_ddrconfig(struct dram_info * dram,u32 ddrconfig)3021881cdb1SYouMin Chen static void set_ddrconfig(struct dram_info *dram, u32 ddrconfig)
3031881cdb1SYouMin Chen {
3041881cdb1SYouMin Chen writel(ddrconfig | (ddrconfig << 8), &dram->msch->deviceconf);
3051881cdb1SYouMin Chen rk_clrsetreg(&dram->grf->soc_noc_con[1], 0x3 << 14, 0 << 14);
3061881cdb1SYouMin Chen }
3071881cdb1SYouMin Chen
sdram_msch_config(struct msch_regs * msch,struct sdram_msch_timings * noc_timings,struct sdram_cap_info * cap_info,struct sdram_base_params * base)3085e6e8f2dSYouMin Chen static void sdram_msch_config(struct msch_regs *msch,
3095e6e8f2dSYouMin Chen struct sdram_msch_timings *noc_timings,
3105e6e8f2dSYouMin Chen struct sdram_cap_info *cap_info,
3115e6e8f2dSYouMin Chen struct sdram_base_params *base)
3125e6e8f2dSYouMin Chen {
3135e6e8f2dSYouMin Chen u64 cs_cap[2];
3145e6e8f2dSYouMin Chen
3155e6e8f2dSYouMin Chen cs_cap[0] = sdram_get_cs_cap(cap_info, 0, base->dramtype);
3165e6e8f2dSYouMin Chen cs_cap[1] = sdram_get_cs_cap(cap_info, 1, base->dramtype);
3175e6e8f2dSYouMin Chen writel(((((cs_cap[1] >> 20) / 64) & 0xff) << 8) |
3185e6e8f2dSYouMin Chen (((cs_cap[0] >> 20) / 64) & 0xff),
3195e6e8f2dSYouMin Chen &msch->devicesize);
3205e6e8f2dSYouMin Chen
3215e6e8f2dSYouMin Chen writel(noc_timings->ddrtiminga0.d32,
3225e6e8f2dSYouMin Chen &msch->ddrtiminga0);
3235e6e8f2dSYouMin Chen writel(noc_timings->ddrtimingb0.d32,
3245e6e8f2dSYouMin Chen &msch->ddrtimingb0);
3255e6e8f2dSYouMin Chen writel(noc_timings->ddrtimingc0.d32,
3265e6e8f2dSYouMin Chen &msch->ddrtimingc0);
3275e6e8f2dSYouMin Chen writel(noc_timings->devtodev0.d32,
3285e6e8f2dSYouMin Chen &msch->devtodev0);
3295e6e8f2dSYouMin Chen writel(noc_timings->ddrmode.d32, &msch->ddrmode);
3305e6e8f2dSYouMin Chen writel(noc_timings->ddr4timing.d32,
3315e6e8f2dSYouMin Chen &msch->ddr4timing);
3325e6e8f2dSYouMin Chen writel(noc_timings->agingx0, &msch->agingx0);
3335e6e8f2dSYouMin Chen writel(noc_timings->agingx0, &msch->aging0);
3345e6e8f2dSYouMin Chen writel(noc_timings->agingx0, &msch->aging1);
3355e6e8f2dSYouMin Chen writel(noc_timings->agingx0, &msch->aging2);
3365e6e8f2dSYouMin Chen writel(noc_timings->agingx0, &msch->aging3);
3375e6e8f2dSYouMin Chen }
3385e6e8f2dSYouMin Chen
dram_all_config(struct dram_info * dram,struct px30_sdram_params * sdram_params)3391881cdb1SYouMin Chen static void dram_all_config(struct dram_info *dram,
3401881cdb1SYouMin Chen struct px30_sdram_params *sdram_params)
3411881cdb1SYouMin Chen {
34255c5751eSYouMin Chen struct sdram_cap_info *cap_info = &sdram_params->ch.cap_info;
34355c5751eSYouMin Chen u32 sys_reg2 = 0;
3441881cdb1SYouMin Chen u32 sys_reg3 = 0;
3451881cdb1SYouMin Chen
34655c5751eSYouMin Chen set_ddrconfig(dram, cap_info->ddrconfig);
34755c5751eSYouMin Chen sdram_org_config(cap_info, &sdram_params->base, &sys_reg2,
34855c5751eSYouMin Chen &sys_reg3, 0);
34955c5751eSYouMin Chen writel(sys_reg2, &dram->pmugrf->os_reg[2]);
3501881cdb1SYouMin Chen writel(sys_reg3, &dram->pmugrf->os_reg[3]);
35155c5751eSYouMin Chen sdram_msch_config(dram->msch, &sdram_params->ch.noc_timings, cap_info,
35255c5751eSYouMin Chen &sdram_params->base);
3531881cdb1SYouMin Chen }
3541881cdb1SYouMin Chen
enable_low_power(struct dram_info * dram,struct px30_sdram_params * sdram_params)3551881cdb1SYouMin Chen static void enable_low_power(struct dram_info *dram,
3561881cdb1SYouMin Chen struct px30_sdram_params *sdram_params)
3571881cdb1SYouMin Chen {
3581881cdb1SYouMin Chen void __iomem *pctl_base = dram->pctl;
359a82a427dSYouMin Chen void __iomem *phy_base = dram->phy;
3601881cdb1SYouMin Chen void __iomem *ddr_grf_base = dram->ddr_grf;
3611881cdb1SYouMin Chen u32 grf_lp_con;
3621881cdb1SYouMin Chen
3631881cdb1SYouMin Chen /*
3641881cdb1SYouMin Chen * bit0: grf_upctl_axi_cg_en = 1 enable upctl2 axi clk auto gating
3651881cdb1SYouMin Chen * bit1: grf_upctl_apb_cg_en = 1 ungated axi,core clk for apb access
3661881cdb1SYouMin Chen * bit2: grf_upctl_core_cg_en = 1 enable upctl2 core clk auto gating
3671881cdb1SYouMin Chen * bit3: grf_selfref_type2_en = 0 disable core clk gating when type2 sr
3681881cdb1SYouMin Chen * bit4: grf_upctl_syscreq_cg_en = 1
3691881cdb1SYouMin Chen * ungating coreclk when c_sysreq assert
3701881cdb1SYouMin Chen * bit8-11: grf_auto_sr_dly = 6
3711881cdb1SYouMin Chen */
3721881cdb1SYouMin Chen writel(0x1f1f0617, &dram->ddr_grf->ddr_grf_con[1]);
3731881cdb1SYouMin Chen
37455c5751eSYouMin Chen if (sdram_params->base.dramtype == DDR4)
3751881cdb1SYouMin Chen grf_lp_con = (0x7 << 16) | (1 << 1);
37655c5751eSYouMin Chen else if (sdram_params->base.dramtype == DDR3)
3771881cdb1SYouMin Chen grf_lp_con = (0x7 << 16) | (1 << 0);
3781881cdb1SYouMin Chen else
3791881cdb1SYouMin Chen grf_lp_con = (0x7 << 16) | (1 << 2);
3801881cdb1SYouMin Chen
3811881cdb1SYouMin Chen /* en lpckdis_en */
3821881cdb1SYouMin Chen grf_lp_con = grf_lp_con | (0x1 << (9 + 16)) | (0x1 << 9);
3831881cdb1SYouMin Chen writel(grf_lp_con, ddr_grf_base + DDR_GRF_LP_CON);
3841881cdb1SYouMin Chen
385a82a427dSYouMin Chen /* off digit module clock when enter power down */
386a82a427dSYouMin Chen setbits_le32(PHY_REG(phy_base, 7), 1 << 7);
387a82a427dSYouMin Chen
3881881cdb1SYouMin Chen /* enable sr, pd */
3891881cdb1SYouMin Chen if (PD_IDLE == 0)
3901881cdb1SYouMin Chen clrbits_le32(pctl_base + DDR_PCTL2_PWRCTL, (1 << 1));
3911881cdb1SYouMin Chen else
3921881cdb1SYouMin Chen setbits_le32(pctl_base + DDR_PCTL2_PWRCTL, (1 << 1));
3931881cdb1SYouMin Chen if (SR_IDLE == 0)
3941881cdb1SYouMin Chen clrbits_le32(pctl_base + DDR_PCTL2_PWRCTL, 1);
3951881cdb1SYouMin Chen else
3961881cdb1SYouMin Chen setbits_le32(pctl_base + DDR_PCTL2_PWRCTL, 1);
3971881cdb1SYouMin Chen setbits_le32(pctl_base + DDR_PCTL2_PWRCTL, (1 << 3));
3981881cdb1SYouMin Chen }
3991881cdb1SYouMin Chen
4001881cdb1SYouMin Chen /*
4011881cdb1SYouMin Chen * pre_init: 0: pre init for dram cap detect
4021881cdb1SYouMin Chen * 1: detect correct cap(except cs1 row)info, than reinit
4031881cdb1SYouMin Chen * 2: after reinit, we detect cs1_row, if cs1_row not equal
4041881cdb1SYouMin Chen * to cs0_row and cs is in middle on ddrconf map, we need
4051881cdb1SYouMin Chen * to reinit dram, than set the correct ddrconf.
4061881cdb1SYouMin Chen */
sdram_init_(struct dram_info * dram,struct px30_sdram_params * sdram_params,u32 pre_init)4071881cdb1SYouMin Chen static int sdram_init_(struct dram_info *dram,
4081881cdb1SYouMin Chen struct px30_sdram_params *sdram_params, u32 pre_init)
4091881cdb1SYouMin Chen {
41055c5751eSYouMin Chen struct sdram_cap_info *cap_info = &sdram_params->ch.cap_info;
4111881cdb1SYouMin Chen void __iomem *pctl_base = dram->pctl;
4121881cdb1SYouMin Chen
4131881cdb1SYouMin Chen rkclk_ddr_reset(dram, 1, 1, 1, 1);
4141881cdb1SYouMin Chen udelay(10);
4151881cdb1SYouMin Chen /*
4161881cdb1SYouMin Chen * dereset ddr phy psrstn to config pll,
4171881cdb1SYouMin Chen * if using phy pll psrstn must be dereset
4181881cdb1SYouMin Chen * before config pll
4191881cdb1SYouMin Chen */
4201881cdb1SYouMin Chen rkclk_ddr_reset(dram, 1, 1, 1, 0);
4211881cdb1SYouMin Chen rkclk_configure_ddr(dram, sdram_params);
4221881cdb1SYouMin Chen
4231881cdb1SYouMin Chen /* release phy srst to provide clk to ctrl */
4241881cdb1SYouMin Chen rkclk_ddr_reset(dram, 1, 1, 0, 0);
4251881cdb1SYouMin Chen udelay(10);
42655c5751eSYouMin Chen phy_soft_reset(dram->phy);
4271881cdb1SYouMin Chen /* release ctrl presetn, and config ctl registers */
4281881cdb1SYouMin Chen rkclk_ddr_reset(dram, 1, 0, 0, 0);
42955c5751eSYouMin Chen pctl_cfg(dram->pctl, &sdram_params->pctl_regs, SR_IDLE, PD_IDLE);
43055c5751eSYouMin Chen cap_info->ddrconfig = calculate_ddrconfig(sdram_params);
4311881cdb1SYouMin Chen set_ctl_address_map(dram, sdram_params);
43255c5751eSYouMin Chen phy_cfg(dram->phy, &sdram_params->phy_regs, sdram_params->skew,
43355c5751eSYouMin Chen &sdram_params->base, cap_info->bw);
4341881cdb1SYouMin Chen
4351881cdb1SYouMin Chen /* enable dfi_init_start to init phy after ctl srstn deassert */
4361881cdb1SYouMin Chen setbits_le32(pctl_base + DDR_PCTL2_DFIMISC, (1 << 5) | (1 << 4));
4371881cdb1SYouMin Chen
4381881cdb1SYouMin Chen rkclk_ddr_reset(dram, 0, 0, 0, 0);
4391881cdb1SYouMin Chen /* wait for dfi_init_done and dram init complete */
4401881cdb1SYouMin Chen while ((readl(pctl_base + DDR_PCTL2_STAT) & 0x7) == 0)
4411881cdb1SYouMin Chen continue;
4421881cdb1SYouMin Chen
44355c5751eSYouMin Chen if (sdram_params->base.dramtype == LPDDR3)
44455c5751eSYouMin Chen pctl_write_mr(dram->pctl, 3, 11, 3, LPDDR3);
4451881cdb1SYouMin Chen
4461881cdb1SYouMin Chen /* do ddr gate training */
4471881cdb1SYouMin Chen redo_cs0_training:
44855c5751eSYouMin Chen if (data_training(dram, 0, sdram_params->base.dramtype) != 0) {
4491881cdb1SYouMin Chen if (pre_init != 0)
4501881cdb1SYouMin Chen printascii("DTT cs0 error\n");
4511881cdb1SYouMin Chen return -1;
4521881cdb1SYouMin Chen }
4531881cdb1SYouMin Chen if (check_rd_gate(dram)) {
4541881cdb1SYouMin Chen printascii("re training cs0");
4551881cdb1SYouMin Chen goto redo_cs0_training;
4561881cdb1SYouMin Chen }
4571881cdb1SYouMin Chen
45855c5751eSYouMin Chen if (sdram_params->base.dramtype == LPDDR3) {
4591881cdb1SYouMin Chen if ((read_mr(dram, 1, 8) & 0x3) != 0x3)
4601881cdb1SYouMin Chen return -1;
46155c5751eSYouMin Chen } else if (sdram_params->base.dramtype == LPDDR2) {
4621881cdb1SYouMin Chen if ((read_mr(dram, 1, 8) & 0x3) != 0x0)
4631881cdb1SYouMin Chen return -1;
4641881cdb1SYouMin Chen }
4651881cdb1SYouMin Chen /* for px30: when 2cs, both 2 cs should be training */
46655c5751eSYouMin Chen if (pre_init != 0 && cap_info->rank == 2) {
4671881cdb1SYouMin Chen redo_cs1_training:
46855c5751eSYouMin Chen if (data_training(dram, 1, sdram_params->base.dramtype) != 0) {
4691881cdb1SYouMin Chen printascii("DTT cs1 error\n");
4701881cdb1SYouMin Chen return -1;
4711881cdb1SYouMin Chen }
4721881cdb1SYouMin Chen if (check_rd_gate(dram)) {
4731881cdb1SYouMin Chen printascii("re training cs1");
4741881cdb1SYouMin Chen goto redo_cs1_training;
4751881cdb1SYouMin Chen }
4761881cdb1SYouMin Chen }
4771881cdb1SYouMin Chen
47855c5751eSYouMin Chen if (sdram_params->base.dramtype == DDR4)
47955c5751eSYouMin Chen pctl_write_vrefdq(dram->pctl, 0x3, 5670,
48055c5751eSYouMin Chen sdram_params->base.dramtype);
4811881cdb1SYouMin Chen
4821881cdb1SYouMin Chen dram_all_config(dram, sdram_params);
4831881cdb1SYouMin Chen enable_low_power(dram, sdram_params);
4841881cdb1SYouMin Chen
4851881cdb1SYouMin Chen return 0;
4861881cdb1SYouMin Chen }
4871881cdb1SYouMin Chen
dram_detect_cap(struct dram_info * dram,struct px30_sdram_params * sdram_params,unsigned char channel)48855c5751eSYouMin Chen static int dram_detect_cap(struct dram_info *dram,
4891881cdb1SYouMin Chen struct px30_sdram_params *sdram_params,
4901881cdb1SYouMin Chen unsigned char channel)
4911881cdb1SYouMin Chen {
492e1652d39SZhihuan He void __iomem *pctl_base = dram->pctl;
49355c5751eSYouMin Chen struct sdram_cap_info *cap_info = &sdram_params->ch.cap_info;
4941881cdb1SYouMin Chen
4951881cdb1SYouMin Chen /*
4961881cdb1SYouMin Chen * for ddr3: ddrconf = 3
4971881cdb1SYouMin Chen * for ddr4: ddrconf = 12
4981881cdb1SYouMin Chen * for lpddr3: ddrconf = 3
4991881cdb1SYouMin Chen * default bw = 1
5001881cdb1SYouMin Chen */
5011881cdb1SYouMin Chen u32 bk, bktmp;
5021881cdb1SYouMin Chen u32 col, coltmp;
50355c5751eSYouMin Chen u32 rowtmp;
5041881cdb1SYouMin Chen u32 cs;
5051881cdb1SYouMin Chen u32 bw = 1;
50655c5751eSYouMin Chen u32 dram_type = sdram_params->base.dramtype;
5071881cdb1SYouMin Chen
5081881cdb1SYouMin Chen if (dram_type != DDR4) {
5091881cdb1SYouMin Chen /* detect col and bk for ddr3/lpddr3 */
5101881cdb1SYouMin Chen coltmp = 12;
5111881cdb1SYouMin Chen bktmp = 3;
512f588f59eSYouMin Chen if (dram_type == LPDDR2)
513f588f59eSYouMin Chen rowtmp = 15;
514f588f59eSYouMin Chen else
5151881cdb1SYouMin Chen rowtmp = 16;
5161881cdb1SYouMin Chen
51755c5751eSYouMin Chen if (sdram_detect_col(cap_info, coltmp) != 0)
5181881cdb1SYouMin Chen goto cap_err;
519e1652d39SZhihuan He sdram_detect_bank(cap_info, pctl_base, coltmp, bktmp);
52055c5751eSYouMin Chen sdram_detect_dbw(cap_info, dram_type);
5211881cdb1SYouMin Chen } else {
5221881cdb1SYouMin Chen /* detect bg for ddr4 */
5231881cdb1SYouMin Chen coltmp = 10;
5241881cdb1SYouMin Chen bktmp = 4;
5251881cdb1SYouMin Chen rowtmp = 17;
5261881cdb1SYouMin Chen
5271881cdb1SYouMin Chen col = 10;
5281881cdb1SYouMin Chen bk = 2;
52955c5751eSYouMin Chen cap_info->col = col;
53055c5751eSYouMin Chen cap_info->bk = bk;
531e1652d39SZhihuan He sdram_detect_bg(cap_info, pctl_base, coltmp);
5321881cdb1SYouMin Chen }
53355c5751eSYouMin Chen
5341881cdb1SYouMin Chen /* detect row */
53555c5751eSYouMin Chen if (sdram_detect_row(cap_info, coltmp, bktmp, rowtmp) != 0)
5361881cdb1SYouMin Chen goto cap_err;
53755c5751eSYouMin Chen
5381881cdb1SYouMin Chen /* detect row_3_4 */
53955c5751eSYouMin Chen sdram_detect_row_3_4(cap_info, coltmp, bktmp);
5401881cdb1SYouMin Chen
54155c5751eSYouMin Chen /* bw and cs detect using data training */
5421881cdb1SYouMin Chen if (data_training(dram, 1, dram_type) == 0)
5431881cdb1SYouMin Chen cs = 1;
5441881cdb1SYouMin Chen else
5451881cdb1SYouMin Chen cs = 0;
54655c5751eSYouMin Chen cap_info->rank = cs + 1;
5471881cdb1SYouMin Chen
54855c5751eSYouMin Chen dram_set_bw(dram, 2);
5491881cdb1SYouMin Chen if (data_training(dram, 0, dram_type) == 0)
5501881cdb1SYouMin Chen bw = 2;
5511881cdb1SYouMin Chen else
5521881cdb1SYouMin Chen bw = 1;
55355c5751eSYouMin Chen cap_info->bw = bw;
5541881cdb1SYouMin Chen
55555c5751eSYouMin Chen cap_info->cs0_high16bit_row = cap_info->cs0_row;
5561881cdb1SYouMin Chen if (cs) {
55755c5751eSYouMin Chen cap_info->cs1_row = cap_info->cs0_row;
55855c5751eSYouMin Chen cap_info->cs1_high16bit_row = cap_info->cs0_row;
5591881cdb1SYouMin Chen } else {
56055c5751eSYouMin Chen cap_info->cs1_row = 0;
56155c5751eSYouMin Chen cap_info->cs1_high16bit_row = 0;
5621881cdb1SYouMin Chen }
5631881cdb1SYouMin Chen
56455c5751eSYouMin Chen return 0;
5651881cdb1SYouMin Chen cap_err:
56655c5751eSYouMin Chen return -1;
5671881cdb1SYouMin Chen }
5681881cdb1SYouMin Chen
get_ddr_param(struct px30_sdram_params * sdram_params,struct ddr_param * ddr_param)569cfadd6bbSYouMin Chen void get_ddr_param(struct px30_sdram_params *sdram_params,
570cfadd6bbSYouMin Chen struct ddr_param *ddr_param)
571cfadd6bbSYouMin Chen {
57255c5751eSYouMin Chen struct sdram_cap_info *cap_info = &sdram_params->ch.cap_info;
57355c5751eSYouMin Chen u32 dram_type = sdram_params->base.dramtype;
574cfadd6bbSYouMin Chen u64 cs_cap[2];
575cfadd6bbSYouMin Chen
57655c5751eSYouMin Chen cs_cap[0] = sdram_get_cs_cap(cap_info, 0, dram_type);
57755c5751eSYouMin Chen cs_cap[1] = sdram_get_cs_cap(cap_info, 1, dram_type);
578cfadd6bbSYouMin Chen
57955c5751eSYouMin Chen if (cap_info->row_3_4) {
580cfadd6bbSYouMin Chen cs_cap[0] = cs_cap[0] * 3 / 4;
581cfadd6bbSYouMin Chen cs_cap[1] = cs_cap[1] * 3 / 4;
582cfadd6bbSYouMin Chen }
583cfadd6bbSYouMin Chen
58455c5751eSYouMin Chen if (cap_info->row_3_4 && cap_info->rank == 2) {
585cfadd6bbSYouMin Chen ddr_param->count = 2;
586cfadd6bbSYouMin Chen ddr_param->para[0] = 0;
587cfadd6bbSYouMin Chen ddr_param->para[1] = cs_cap[0] * 4 / 3;
588cfadd6bbSYouMin Chen ddr_param->para[2] = cs_cap[0];
589cfadd6bbSYouMin Chen ddr_param->para[3] = cs_cap[1];
590cfadd6bbSYouMin Chen } else {
591cfadd6bbSYouMin Chen ddr_param->count = 1;
592cfadd6bbSYouMin Chen ddr_param->para[0] = 0;
593cfadd6bbSYouMin Chen ddr_param->para[1] = (u64)cs_cap[0] + (u64)cs_cap[1];
594cfadd6bbSYouMin Chen }
595cfadd6bbSYouMin Chen }
596cfadd6bbSYouMin Chen
5971881cdb1SYouMin Chen /* return: 0 = success, other = fail */
sdram_init_detect(struct dram_info * dram,struct px30_sdram_params * sdram_params)5981881cdb1SYouMin Chen static int sdram_init_detect(struct dram_info *dram,
5991881cdb1SYouMin Chen struct px30_sdram_params *sdram_params)
6001881cdb1SYouMin Chen {
60155c5751eSYouMin Chen struct sdram_cap_info *cap_info = &sdram_params->ch.cap_info;
6021881cdb1SYouMin Chen u32 ret;
6031881cdb1SYouMin Chen u32 sys_reg = 0;
6041881cdb1SYouMin Chen u32 sys_reg3 = 0;
6051881cdb1SYouMin Chen
6061881cdb1SYouMin Chen if (sdram_init_(dram, sdram_params, 0) != 0)
6071881cdb1SYouMin Chen return -1;
6081881cdb1SYouMin Chen
60955c5751eSYouMin Chen if (dram_detect_cap(dram, sdram_params, 0) != 0)
6101881cdb1SYouMin Chen return -1;
6111881cdb1SYouMin Chen
6121881cdb1SYouMin Chen /* modify bw, cs related timing */
61355c5751eSYouMin Chen pctl_remodify_sdram_params(&sdram_params->pctl_regs, cap_info,
61455c5751eSYouMin Chen sdram_params->base.dramtype);
6151881cdb1SYouMin Chen /* reinit sdram by real dram cap */
6161881cdb1SYouMin Chen ret = sdram_init_(dram, sdram_params, 1);
6171881cdb1SYouMin Chen if (ret != 0)
6181881cdb1SYouMin Chen goto out;
6191881cdb1SYouMin Chen
6201881cdb1SYouMin Chen /* redetect cs1 row */
62155c5751eSYouMin Chen sdram_detect_cs1_row(cap_info, sdram_params->base.dramtype);
62255c5751eSYouMin Chen if (cap_info->cs1_row) {
6231881cdb1SYouMin Chen sys_reg = readl(&dram->pmugrf->os_reg[2]);
6241881cdb1SYouMin Chen sys_reg3 = readl(&dram->pmugrf->os_reg[3]);
62555c5751eSYouMin Chen SYS_REG_ENC_CS1_ROW(cap_info->cs1_row,
62655c5751eSYouMin Chen sys_reg, sys_reg3, 0);
6271881cdb1SYouMin Chen writel(sys_reg, &dram->pmugrf->os_reg[2]);
6281881cdb1SYouMin Chen writel(sys_reg3, &dram->pmugrf->os_reg[3]);
6291881cdb1SYouMin Chen }
6301881cdb1SYouMin Chen
631f627cf25SZhihuan He ret = sdram_detect_high_row(cap_info, sdram_params->base.dramtype);
6321881cdb1SYouMin Chen
6331881cdb1SYouMin Chen out:
6341881cdb1SYouMin Chen return ret;
6351881cdb1SYouMin Chen }
6361881cdb1SYouMin Chen
6371881cdb1SYouMin Chen struct px30_sdram_params
get_default_sdram_config(void)6381881cdb1SYouMin Chen *get_default_sdram_config(void)
6391881cdb1SYouMin Chen {
6401881cdb1SYouMin Chen sdram_configs[0].skew = &skew;
6411881cdb1SYouMin Chen
6421881cdb1SYouMin Chen return &sdram_configs[0];
6431881cdb1SYouMin Chen }
6441881cdb1SYouMin Chen
6451881cdb1SYouMin Chen /* return: 0 = success, other = fail */
sdram_init(void)6461881cdb1SYouMin Chen int sdram_init(void)
6471881cdb1SYouMin Chen {
6481881cdb1SYouMin Chen struct px30_sdram_params *sdram_params;
6491881cdb1SYouMin Chen int ret = 0;
650cfadd6bbSYouMin Chen struct ddr_param ddr_param;
6511881cdb1SYouMin Chen
6521881cdb1SYouMin Chen dram_info.phy = (void *)DDR_PHY_BASE_ADDR;
6531881cdb1SYouMin Chen dram_info.pctl = (void *)DDRC_BASE_ADDR;
6541881cdb1SYouMin Chen dram_info.grf = (void *)GRF_BASE_ADDR;
6551881cdb1SYouMin Chen dram_info.cru = (void *)CRU_BASE_ADDR;
6561881cdb1SYouMin Chen dram_info.msch = (void *)SERVER_MSCH0_BASE_ADDR;
6571881cdb1SYouMin Chen dram_info.ddr_grf = (void *)DDR_GRF_BASE_ADDR;
6581881cdb1SYouMin Chen dram_info.pmugrf = (void *)PMUGRF_BASE_ADDR;
6591881cdb1SYouMin Chen
6601881cdb1SYouMin Chen sdram_params = get_default_sdram_config();
6611881cdb1SYouMin Chen ret = sdram_init_detect(&dram_info, sdram_params);
6621881cdb1SYouMin Chen
6631881cdb1SYouMin Chen if (ret)
6641881cdb1SYouMin Chen goto error;
6651881cdb1SYouMin Chen
666cfadd6bbSYouMin Chen get_ddr_param(sdram_params, &ddr_param);
667cfadd6bbSYouMin Chen rockchip_setup_ddr_param(&ddr_param);
66855c5751eSYouMin Chen sdram_print_ddr_info(&sdram_params->ch.cap_info,
66955c5751eSYouMin Chen &sdram_params->base, 0);
670504e252fSYouMin Chen
6711881cdb1SYouMin Chen printascii("out\n");
6721881cdb1SYouMin Chen return ret;
6731881cdb1SYouMin Chen error:
6741881cdb1SYouMin Chen return (-1);
6751881cdb1SYouMin Chen }
6761881cdb1SYouMin Chen #endif /* CONFIG_TPL_BUILD */
677