15685f66aSYouMin Chen // SPDX-License-Identifier: GPL-2.0 25685f66aSYouMin Chen /* 35685f66aSYouMin Chen * (C) Copyright 2018 Rockchip Electronics Co., Ltd. 45685f66aSYouMin Chen */ 55685f66aSYouMin Chen 65685f66aSYouMin Chen #include <common.h> 75685f66aSYouMin Chen #include <debug_uart.h> 85685f66aSYouMin Chen #include <ram.h> 95685f66aSYouMin Chen #include <asm/io.h> 105685f66aSYouMin Chen #include <asm/arch/sdram.h> 115685f66aSYouMin Chen #include <asm/arch/sdram_common.h> 125685f66aSYouMin Chen 135685f66aSYouMin Chen void sdram_print_dram_type(unsigned char dramtype) 145685f66aSYouMin Chen { 155685f66aSYouMin Chen switch (dramtype) { 165685f66aSYouMin Chen case DDR3: 175685f66aSYouMin Chen printascii("DDR3"); 185685f66aSYouMin Chen break; 195685f66aSYouMin Chen case DDR4: 205685f66aSYouMin Chen printascii("DDR4"); 215685f66aSYouMin Chen break; 225685f66aSYouMin Chen case LPDDR2: 235685f66aSYouMin Chen printascii("LPDDR2"); 245685f66aSYouMin Chen break; 255685f66aSYouMin Chen case LPDDR3: 265685f66aSYouMin Chen printascii("LPDDR3"); 275685f66aSYouMin Chen break; 285685f66aSYouMin Chen case LPDDR4: 295685f66aSYouMin Chen printascii("LPDDR4"); 305685f66aSYouMin Chen break; 31de9242dcSTang Yun ping case LPDDR4X: 32de9242dcSTang Yun ping printascii("LPDDR4X"); 33de9242dcSTang Yun ping break; 345685f66aSYouMin Chen default: 355685f66aSYouMin Chen printascii("Unknown Device"); 365685f66aSYouMin Chen break; 375685f66aSYouMin Chen } 385685f66aSYouMin Chen } 395685f66aSYouMin Chen 405685f66aSYouMin Chen void sdram_print_ddr_info(struct sdram_cap_info *cap_info, 415685f66aSYouMin Chen struct sdram_base_params *base, u32 split) 425685f66aSYouMin Chen { 435685f66aSYouMin Chen u64 cap; 445685f66aSYouMin Chen u32 bg; 455685f66aSYouMin Chen 465685f66aSYouMin Chen bg = (cap_info->dbw == 0) ? 2 : 1; 475685f66aSYouMin Chen 485685f66aSYouMin Chen sdram_print_dram_type(base->dramtype); 495685f66aSYouMin Chen 505685f66aSYouMin Chen printascii(", "); 515685f66aSYouMin Chen printdec(base->ddr_freq); 525685f66aSYouMin Chen printascii("MHz\n"); 535685f66aSYouMin Chen 545685f66aSYouMin Chen printascii("BW="); 555685f66aSYouMin Chen printdec(8 << cap_info->bw); 565685f66aSYouMin Chen printascii(" Col="); 575685f66aSYouMin Chen printdec(cap_info->col); 585685f66aSYouMin Chen printascii(" Bk="); 595685f66aSYouMin Chen printdec(0x1 << cap_info->bk); 605685f66aSYouMin Chen if (base->dramtype == DDR4) { 615685f66aSYouMin Chen printascii(" BG="); 625685f66aSYouMin Chen printdec(1 << bg); 635685f66aSYouMin Chen } 645685f66aSYouMin Chen printascii(" CS0 Row="); 655685f66aSYouMin Chen printdec(cap_info->cs0_row); 665685f66aSYouMin Chen if (cap_info->cs0_high16bit_row != 675685f66aSYouMin Chen cap_info->cs0_row) { 685685f66aSYouMin Chen printascii("/"); 695685f66aSYouMin Chen printdec(cap_info->cs0_high16bit_row); 705685f66aSYouMin Chen } 715685f66aSYouMin Chen if (cap_info->rank > 1) { 725685f66aSYouMin Chen printascii(" CS1 Row="); 735685f66aSYouMin Chen printdec(cap_info->cs1_row); 745685f66aSYouMin Chen if (cap_info->cs1_high16bit_row != 755685f66aSYouMin Chen cap_info->cs1_row) { 765685f66aSYouMin Chen printascii("/"); 775685f66aSYouMin Chen printdec(cap_info->cs1_high16bit_row); 785685f66aSYouMin Chen } 795685f66aSYouMin Chen } 80de9242dcSTang Yun ping if (cap_info->rank > 2) { 81de9242dcSTang Yun ping printascii(" CS2 Row="); 82de9242dcSTang Yun ping printdec(cap_info->cs2_row); 83de9242dcSTang Yun ping printascii(" CS3 Row="); 84de9242dcSTang Yun ping printdec(cap_info->cs3_row); 85de9242dcSTang Yun ping } 865685f66aSYouMin Chen printascii(" CS="); 875685f66aSYouMin Chen printdec(cap_info->rank); 885685f66aSYouMin Chen printascii(" Die BW="); 895685f66aSYouMin Chen printdec(8 << cap_info->dbw); 905685f66aSYouMin Chen 915685f66aSYouMin Chen cap = sdram_get_cs_cap(cap_info, 3, base->dramtype); 925685f66aSYouMin Chen if (cap_info->row_3_4) 935685f66aSYouMin Chen cap = cap * 3 / 4; 945685f66aSYouMin Chen else if (split) 955685f66aSYouMin Chen cap = cap / 2 + (split << 24) / 2; 965685f66aSYouMin Chen 975685f66aSYouMin Chen printascii(" Size="); 985685f66aSYouMin Chen printdec(cap >> 20); 995685f66aSYouMin Chen printascii("MB\n"); 1005685f66aSYouMin Chen } 1015685f66aSYouMin Chen 1025685f66aSYouMin Chen /* 1035685f66aSYouMin Chen * cs: 0:cs0 1045685f66aSYouMin Chen * 1:cs1 1055685f66aSYouMin Chen * else cs0+cs1 1065685f66aSYouMin Chen * note: it didn't consider about row_3_4 1075685f66aSYouMin Chen */ 1085685f66aSYouMin Chen u64 sdram_get_cs_cap(struct sdram_cap_info *cap_info, u32 cs, u32 dram_type) 1095685f66aSYouMin Chen { 1105685f66aSYouMin Chen u32 bg; 111de9242dcSTang Yun ping u64 cap[4]; 1125685f66aSYouMin Chen 1135685f66aSYouMin Chen if (dram_type == DDR4) 1145685f66aSYouMin Chen /* DDR4 8bit dram BG = 2(4bank groups), 1155685f66aSYouMin Chen * 16bit dram BG = 1 (2 bank groups) 1165685f66aSYouMin Chen */ 1175685f66aSYouMin Chen bg = (cap_info->dbw == 0) ? 2 : 1; 1185685f66aSYouMin Chen else 1195685f66aSYouMin Chen bg = 0; 1205685f66aSYouMin Chen cap[0] = 1llu << (cap_info->bw + cap_info->col + 1215685f66aSYouMin Chen bg + cap_info->bk + cap_info->cs0_row); 1225685f66aSYouMin Chen 123de9242dcSTang Yun ping if (cap_info->rank >= 2) 1245685f66aSYouMin Chen cap[1] = 1llu << (cap_info->bw + cap_info->col + 1255685f66aSYouMin Chen bg + cap_info->bk + cap_info->cs1_row); 1265685f66aSYouMin Chen else 1275685f66aSYouMin Chen cap[1] = 0; 1281a6462e1STang Yun ping 129de9242dcSTang Yun ping if (cap_info->rank == 4) { 130de9242dcSTang Yun ping cap[2] = 1llu << (cap_info->bw + cap_info->col + 131de9242dcSTang Yun ping bg + cap_info->bk + cap_info->cs2_row); 132de9242dcSTang Yun ping cap[3] = 1llu << (cap_info->bw + cap_info->col + 133de9242dcSTang Yun ping bg + cap_info->bk + cap_info->cs3_row); 134de9242dcSTang Yun ping } else { 135de9242dcSTang Yun ping cap[2] = 0; 136de9242dcSTang Yun ping cap[3] = 0; 137de9242dcSTang Yun ping } 1385685f66aSYouMin Chen if (cs == 0) 1395685f66aSYouMin Chen return cap[0]; 1405685f66aSYouMin Chen else if (cs == 1) 1415685f66aSYouMin Chen return cap[1]; 1425685f66aSYouMin Chen else 143de9242dcSTang Yun ping return (cap[0] + cap[1] + cap[2] + cap[3]); 1445685f66aSYouMin Chen } 1455685f66aSYouMin Chen 1465685f66aSYouMin Chen /* n: Unit bytes */ 1475685f66aSYouMin Chen void sdram_copy_to_reg(u32 *dest, const u32 *src, u32 n) 1485685f66aSYouMin Chen { 1495685f66aSYouMin Chen int i; 1505685f66aSYouMin Chen 1515685f66aSYouMin Chen for (i = 0; i < n / sizeof(u32); i++) { 1525685f66aSYouMin Chen writel(*src, dest); 1535685f66aSYouMin Chen src++; 1545685f66aSYouMin Chen dest++; 1555685f66aSYouMin Chen } 1565685f66aSYouMin Chen } 1575685f66aSYouMin Chen 1585685f66aSYouMin Chen void sdram_org_config(struct sdram_cap_info *cap_info, 1595685f66aSYouMin Chen struct sdram_base_params *base, 1605685f66aSYouMin Chen u32 *p_os_reg2, u32 *p_os_reg3, u32 channel) 1615685f66aSYouMin Chen { 1625685f66aSYouMin Chen *p_os_reg2 |= SYS_REG_ENC_DDRTYPE(base->dramtype); 1635685f66aSYouMin Chen *p_os_reg2 |= SYS_REG_ENC_NUM_CH(base->num_channels); 1645685f66aSYouMin Chen 1655685f66aSYouMin Chen *p_os_reg2 |= SYS_REG_ENC_ROW_3_4(cap_info->row_3_4, channel); 1665685f66aSYouMin Chen *p_os_reg2 |= SYS_REG_ENC_CHINFO(channel); 1675685f66aSYouMin Chen *p_os_reg2 |= SYS_REG_ENC_RANK(cap_info->rank, channel); 1685685f66aSYouMin Chen *p_os_reg2 |= SYS_REG_ENC_COL(cap_info->col, channel); 1695685f66aSYouMin Chen *p_os_reg2 |= SYS_REG_ENC_BK(cap_info->bk, channel); 1705685f66aSYouMin Chen *p_os_reg2 |= SYS_REG_ENC_BW(cap_info->bw, channel); 1715685f66aSYouMin Chen *p_os_reg2 |= SYS_REG_ENC_DBW(cap_info->dbw, channel); 1725685f66aSYouMin Chen 1735685f66aSYouMin Chen SYS_REG_ENC_CS0_ROW(cap_info->cs0_row, *p_os_reg2, *p_os_reg3, channel); 1745685f66aSYouMin Chen if (cap_info->cs1_row) 1755685f66aSYouMin Chen SYS_REG_ENC_CS1_ROW(cap_info->cs1_row, *p_os_reg2, 1765685f66aSYouMin Chen *p_os_reg3, channel); 1775685f66aSYouMin Chen *p_os_reg3 |= SYS_REG_ENC_CS1_COL(cap_info->col, channel); 1785685f66aSYouMin Chen *p_os_reg3 |= SYS_REG_ENC_VERSION(DDR_SYS_REG_VERSION); 1795685f66aSYouMin Chen } 1805685f66aSYouMin Chen 181c69667e0STang Yun ping void sdram_org_config_v3(struct sdram_cap_info *cap_info, 182c69667e0STang Yun ping struct sdram_base_params *base, 183c69667e0STang Yun ping u32 *p_os_reg2, u32 *p_os_reg3, u32 channel) 184c69667e0STang Yun ping { 185c69667e0STang Yun ping SYS_REG_ENC_DDRTYPE_V3(base->dramtype, *p_os_reg2, *p_os_reg3); 186c69667e0STang Yun ping 187c69667e0STang Yun ping *p_os_reg2 |= SYS_REG_ENC_NUM_CH_V3((base->num_channels > 2) ? 188c69667e0STang Yun ping 2 : base->num_channels); 189c69667e0STang Yun ping 190c69667e0STang Yun ping *p_os_reg2 |= SYS_REG_ENC_ROW_3_4_V3(cap_info->row_3_4, channel); 191c69667e0STang Yun ping *p_os_reg2 |= SYS_REG_ENC_CHINFO_V3((channel >= 2) ? channel - 2 : channel); 192c69667e0STang Yun ping if (channel == 0 || channel == 2) 193c69667e0STang Yun ping SYS_REG_ENC_CH0_2_RANK_V3(cap_info->rank, 194c69667e0STang Yun ping *p_os_reg2, *p_os_reg3); 195c69667e0STang Yun ping else 196c69667e0STang Yun ping *p_os_reg2 |= SYS_REG_ENC_CH1_3_RANK(cap_info->rank); 197c69667e0STang Yun ping 198c69667e0STang Yun ping *p_os_reg2 |= SYS_REG_ENC_COL_V3(cap_info->col, channel); 199c69667e0STang Yun ping *p_os_reg2 |= SYS_REG_ENC_BK_V3(cap_info->bk, channel); 200c69667e0STang Yun ping *p_os_reg2 |= SYS_REG_ENC_BW_V3(cap_info->bw, channel); 201c69667e0STang Yun ping *p_os_reg2 |= SYS_REG_ENC_DBW_V3(cap_info->dbw, channel); 202c69667e0STang Yun ping 203c69667e0STang Yun ping SYS_REG_ENC_CS0_ROW_V3(cap_info->cs0_row, *p_os_reg2, *p_os_reg3, channel); 204c69667e0STang Yun ping if (cap_info->cs1_row) 205c69667e0STang Yun ping SYS_REG_ENC_CS1_ROW_V3(cap_info->cs1_row, *p_os_reg2, 206c69667e0STang Yun ping *p_os_reg3, channel); 207c69667e0STang Yun ping if ((channel == 0 || channel == 2) && cap_info->rank > 2) { 208c69667e0STang Yun ping if (cap_info->cs2_row == cap_info->cs0_row) 209c69667e0STang Yun ping *p_os_reg3 |= SYS_REG_ENC_CS2_DELTA_ROW_V3(0); 210c69667e0STang Yun ping else 211c69667e0STang Yun ping *p_os_reg3 |= SYS_REG_ENC_CS2_DELTA_ROW_V3(1); 212c69667e0STang Yun ping 213c69667e0STang Yun ping if (cap_info->cs3_row == cap_info->cs0_row) 214c69667e0STang Yun ping *p_os_reg3 |= SYS_REG_ENC_CS3_DELTA_ROW_V3(0); 215c69667e0STang Yun ping else 216c69667e0STang Yun ping *p_os_reg3 |= SYS_REG_ENC_CS3_DELTA_ROW_V3(1); 217c69667e0STang Yun ping } 218c69667e0STang Yun ping 219c69667e0STang Yun ping *p_os_reg3 |= SYS_REG_ENC_CS1_COL_V3(cap_info->col, channel); 220c69667e0STang Yun ping *p_os_reg3 |= SYS_REG_ENC_VERSION(DDR_SYS_REG_VERSION_3); 221c69667e0STang Yun ping } 222c69667e0STang Yun ping 2235685f66aSYouMin Chen int sdram_detect_bw(struct sdram_cap_info *cap_info) 2245685f66aSYouMin Chen { 2255685f66aSYouMin Chen return 0; 2265685f66aSYouMin Chen } 2275685f66aSYouMin Chen 2285685f66aSYouMin Chen int sdram_detect_cs(struct sdram_cap_info *cap_info) 2295685f66aSYouMin Chen { 2305685f66aSYouMin Chen return 0; 2315685f66aSYouMin Chen } 2325685f66aSYouMin Chen 2335685f66aSYouMin Chen int sdram_detect_col(struct sdram_cap_info *cap_info, 2345685f66aSYouMin Chen u32 coltmp) 2355685f66aSYouMin Chen { 2365685f66aSYouMin Chen void __iomem *test_addr; 2375685f66aSYouMin Chen u32 col; 2385685f66aSYouMin Chen u32 bw = cap_info->bw; 2395685f66aSYouMin Chen 2405685f66aSYouMin Chen for (col = coltmp; col >= 9; col -= 1) { 2415685f66aSYouMin Chen writel(0, CONFIG_SYS_SDRAM_BASE); 2425685f66aSYouMin Chen test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE + 2435685f66aSYouMin Chen (1ul << (col + bw - 1ul))); 2445685f66aSYouMin Chen writel(PATTERN, test_addr); 2455685f66aSYouMin Chen if ((readl(test_addr) == PATTERN) && 2465685f66aSYouMin Chen (readl(CONFIG_SYS_SDRAM_BASE) == 0)) 2475685f66aSYouMin Chen break; 2485685f66aSYouMin Chen } 2495685f66aSYouMin Chen if (col == 8) { 2505685f66aSYouMin Chen printascii("col error\n"); 2515685f66aSYouMin Chen return -1; 2525685f66aSYouMin Chen } 2535685f66aSYouMin Chen 2545685f66aSYouMin Chen cap_info->col = col; 2555685f66aSYouMin Chen 2565685f66aSYouMin Chen return 0; 2575685f66aSYouMin Chen } 2585685f66aSYouMin Chen 2595685f66aSYouMin Chen int sdram_detect_bank(struct sdram_cap_info *cap_info, 2605685f66aSYouMin Chen u32 coltmp, u32 bktmp) 2615685f66aSYouMin Chen { 2625685f66aSYouMin Chen void __iomem *test_addr; 2635685f66aSYouMin Chen u32 bk; 2645685f66aSYouMin Chen u32 bw = cap_info->bw; 2655685f66aSYouMin Chen 2665685f66aSYouMin Chen test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE + 2675685f66aSYouMin Chen (1ul << (coltmp + bktmp + bw - 1ul))); 2685685f66aSYouMin Chen writel(0, CONFIG_SYS_SDRAM_BASE); 2695685f66aSYouMin Chen writel(PATTERN, test_addr); 2705685f66aSYouMin Chen if ((readl(test_addr) == PATTERN) && 2715685f66aSYouMin Chen (readl(CONFIG_SYS_SDRAM_BASE) == 0)) 2725685f66aSYouMin Chen bk = 3; 2735685f66aSYouMin Chen else 2745685f66aSYouMin Chen bk = 2; 2755685f66aSYouMin Chen 2765685f66aSYouMin Chen cap_info->bk = bk; 2775685f66aSYouMin Chen 2785685f66aSYouMin Chen return 0; 2795685f66aSYouMin Chen } 2805685f66aSYouMin Chen 2815685f66aSYouMin Chen /* detect bg for ddr4 */ 2825685f66aSYouMin Chen int sdram_detect_bg(struct sdram_cap_info *cap_info, 2835685f66aSYouMin Chen u32 coltmp) 2845685f66aSYouMin Chen { 2855685f66aSYouMin Chen void __iomem *test_addr; 2865685f66aSYouMin Chen u32 dbw; 2875685f66aSYouMin Chen u32 bw = cap_info->bw; 2885685f66aSYouMin Chen 2895685f66aSYouMin Chen test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE + 2905685f66aSYouMin Chen (1ul << (coltmp + bw + 1ul))); 2915685f66aSYouMin Chen writel(0, CONFIG_SYS_SDRAM_BASE); 2925685f66aSYouMin Chen writel(PATTERN, test_addr); 2935685f66aSYouMin Chen if ((readl(test_addr) == PATTERN) && 2945685f66aSYouMin Chen (readl(CONFIG_SYS_SDRAM_BASE) == 0)) 2955685f66aSYouMin Chen dbw = 0; 2965685f66aSYouMin Chen else 2975685f66aSYouMin Chen dbw = 1; 2985685f66aSYouMin Chen 2995685f66aSYouMin Chen cap_info->dbw = dbw; 3005685f66aSYouMin Chen 3015685f66aSYouMin Chen return 0; 3025685f66aSYouMin Chen } 3035685f66aSYouMin Chen 3045685f66aSYouMin Chen /* detect dbw for ddr3,lpddr2,lpddr3,lpddr4 */ 3055685f66aSYouMin Chen int sdram_detect_dbw(struct sdram_cap_info *cap_info, u32 dram_type) 3065685f66aSYouMin Chen { 3075685f66aSYouMin Chen u32 row, col, bk, bw, cs_cap, cs; 3085685f66aSYouMin Chen u32 die_bw_0 = 0, die_bw_1 = 0; 3095685f66aSYouMin Chen 310*9d5c314bSWesley Yao if (dram_type == DDR3) { 311*9d5c314bSWesley Yao if (cap_info->bw == 0) 312*9d5c314bSWesley Yao cap_info->dbw = 0; 313*9d5c314bSWesley Yao else 314*9d5c314bSWesley Yao cap_info->dbw = 1; 315*9d5c314bSWesley Yao } else if (dram_type == LPDDR4) { 3165685f66aSYouMin Chen cap_info->dbw = 1; 3175685f66aSYouMin Chen } else if (dram_type == LPDDR3 || dram_type == LPDDR2) { 3185685f66aSYouMin Chen row = cap_info->cs0_row; 3195685f66aSYouMin Chen col = cap_info->col; 3205685f66aSYouMin Chen bk = cap_info->bk; 3215685f66aSYouMin Chen cs = cap_info->rank; 3225685f66aSYouMin Chen bw = cap_info->bw; 3235685f66aSYouMin Chen cs_cap = (1 << (row + col + bk + bw - 20)); 3245685f66aSYouMin Chen if (bw == 2) { 3255685f66aSYouMin Chen if (cs_cap <= 0x2000000) /* 256Mb */ 3265685f66aSYouMin Chen die_bw_0 = (col < 9) ? 2 : 1; 3275685f66aSYouMin Chen else if (cs_cap <= 0x10000000) /* 2Gb */ 3285685f66aSYouMin Chen die_bw_0 = (col < 10) ? 2 : 1; 3295685f66aSYouMin Chen else if (cs_cap <= 0x40000000) /* 8Gb */ 3305685f66aSYouMin Chen die_bw_0 = (col < 11) ? 2 : 1; 3315685f66aSYouMin Chen else 3325685f66aSYouMin Chen die_bw_0 = (col < 12) ? 2 : 1; 3335685f66aSYouMin Chen if (cs > 1) { 3345685f66aSYouMin Chen row = cap_info->cs1_row; 3355685f66aSYouMin Chen cs_cap = (1 << (row + col + bk + bw - 20)); 3365685f66aSYouMin Chen if (cs_cap <= 0x2000000) /* 256Mb */ 3375685f66aSYouMin Chen die_bw_0 = (col < 9) ? 2 : 1; 3385685f66aSYouMin Chen else if (cs_cap <= 0x10000000) /* 2Gb */ 3395685f66aSYouMin Chen die_bw_0 = (col < 10) ? 2 : 1; 3405685f66aSYouMin Chen else if (cs_cap <= 0x40000000) /* 8Gb */ 3415685f66aSYouMin Chen die_bw_0 = (col < 11) ? 2 : 1; 3425685f66aSYouMin Chen else 3435685f66aSYouMin Chen die_bw_0 = (col < 12) ? 2 : 1; 3445685f66aSYouMin Chen } 3455685f66aSYouMin Chen } else { 3465685f66aSYouMin Chen die_bw_1 = 1; 3475685f66aSYouMin Chen die_bw_0 = 1; 3485685f66aSYouMin Chen } 3495685f66aSYouMin Chen cap_info->dbw = (die_bw_0 > die_bw_1) ? die_bw_0 : die_bw_1; 3505685f66aSYouMin Chen } 3515685f66aSYouMin Chen 3525685f66aSYouMin Chen return 0; 3535685f66aSYouMin Chen } 3545685f66aSYouMin Chen 3555685f66aSYouMin Chen int sdram_detect_row(struct sdram_cap_info *cap_info, 3565685f66aSYouMin Chen u32 coltmp, u32 bktmp, u32 rowtmp) 3575685f66aSYouMin Chen { 3585685f66aSYouMin Chen u32 row; 3595685f66aSYouMin Chen u32 bw = cap_info->bw; 3605685f66aSYouMin Chen void __iomem *test_addr; 3615685f66aSYouMin Chen 3625685f66aSYouMin Chen for (row = rowtmp; row > 12; row--) { 3635685f66aSYouMin Chen writel(0, CONFIG_SYS_SDRAM_BASE); 3645685f66aSYouMin Chen test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE + 3655685f66aSYouMin Chen (1ul << (row + bktmp + coltmp + bw - 1ul))); 3665685f66aSYouMin Chen writel(PATTERN, test_addr); 3675685f66aSYouMin Chen if ((readl(test_addr) == PATTERN) && 3685685f66aSYouMin Chen (readl(CONFIG_SYS_SDRAM_BASE) == 0)) 3695685f66aSYouMin Chen break; 3705685f66aSYouMin Chen } 3715685f66aSYouMin Chen if (row == 12) { 3725685f66aSYouMin Chen printascii("row error"); 3735685f66aSYouMin Chen return -1; 3745685f66aSYouMin Chen } 3755685f66aSYouMin Chen 3765685f66aSYouMin Chen cap_info->cs0_row = row; 3775685f66aSYouMin Chen 3785685f66aSYouMin Chen return 0; 3795685f66aSYouMin Chen } 3805685f66aSYouMin Chen 3815685f66aSYouMin Chen int sdram_detect_row_3_4(struct sdram_cap_info *cap_info, 3825685f66aSYouMin Chen u32 coltmp, u32 bktmp) 3835685f66aSYouMin Chen { 3845685f66aSYouMin Chen u32 row_3_4; 3855685f66aSYouMin Chen u32 bw = cap_info->bw; 3865685f66aSYouMin Chen u32 row = cap_info->cs0_row; 3875685f66aSYouMin Chen void __iomem *test_addr, *test_addr1; 3885685f66aSYouMin Chen 3895685f66aSYouMin Chen test_addr = CONFIG_SYS_SDRAM_BASE; 3905685f66aSYouMin Chen test_addr1 = (void __iomem *)(CONFIG_SYS_SDRAM_BASE + 3915685f66aSYouMin Chen (0x3ul << (row + bktmp + coltmp + bw - 1ul - 1ul))); 3925685f66aSYouMin Chen 3935685f66aSYouMin Chen writel(0, test_addr); 3945685f66aSYouMin Chen writel(PATTERN, test_addr1); 3955685f66aSYouMin Chen if ((readl(test_addr) == 0) && (readl(test_addr1) == PATTERN)) 3965685f66aSYouMin Chen row_3_4 = 0; 3975685f66aSYouMin Chen else 3985685f66aSYouMin Chen row_3_4 = 1; 3995685f66aSYouMin Chen 4005685f66aSYouMin Chen cap_info->row_3_4 = row_3_4; 4015685f66aSYouMin Chen 4025685f66aSYouMin Chen return 0; 4035685f66aSYouMin Chen } 4045685f66aSYouMin Chen 4055685f66aSYouMin Chen int sdram_detect_high_row(struct sdram_cap_info *cap_info) 4065685f66aSYouMin Chen { 4075685f66aSYouMin Chen cap_info->cs0_high16bit_row = cap_info->cs0_row; 4085685f66aSYouMin Chen cap_info->cs1_high16bit_row = cap_info->cs1_row; 4095685f66aSYouMin Chen 4105685f66aSYouMin Chen return 0; 4115685f66aSYouMin Chen } 4125685f66aSYouMin Chen 4135685f66aSYouMin Chen int sdram_detect_cs1_row(struct sdram_cap_info *cap_info, u32 dram_type) 4145685f66aSYouMin Chen { 4155685f66aSYouMin Chen void __iomem *test_addr; 4165685f66aSYouMin Chen u32 row = 0, bktmp, coltmp, bw; 4175685f66aSYouMin Chen ulong cs0_cap; 4185685f66aSYouMin Chen u32 byte_mask; 4195685f66aSYouMin Chen 4205685f66aSYouMin Chen if (cap_info->rank == 2) { 4215685f66aSYouMin Chen cs0_cap = sdram_get_cs_cap(cap_info, 0, dram_type); 4225685f66aSYouMin Chen 4235685f66aSYouMin Chen if (dram_type == DDR4) { 4245685f66aSYouMin Chen if (cap_info->dbw == 0) 4255685f66aSYouMin Chen bktmp = cap_info->bk + 2; 4265685f66aSYouMin Chen else 4275685f66aSYouMin Chen bktmp = cap_info->bk + 1; 4285685f66aSYouMin Chen } else { 4295685f66aSYouMin Chen bktmp = cap_info->bk; 4305685f66aSYouMin Chen } 4315685f66aSYouMin Chen bw = cap_info->bw; 4325685f66aSYouMin Chen coltmp = cap_info->col; 4335685f66aSYouMin Chen 4345685f66aSYouMin Chen /* 4355685f66aSYouMin Chen * because px30 support axi split,min bandwidth 4365685f66aSYouMin Chen * is 8bit. if cs0 is 32bit, cs1 may 32bit or 16bit 4375685f66aSYouMin Chen * so we check low 16bit data when detect cs1 row. 4385685f66aSYouMin Chen * if cs0 is 16bit/8bit, we check low 8bit data. 4395685f66aSYouMin Chen */ 4405685f66aSYouMin Chen if (bw == 2) 4415685f66aSYouMin Chen byte_mask = 0xFFFF; 4425685f66aSYouMin Chen else 4435685f66aSYouMin Chen byte_mask = 0xFF; 4445685f66aSYouMin Chen 4455685f66aSYouMin Chen /* detect cs1 row */ 4465685f66aSYouMin Chen for (row = cap_info->cs0_row; row > 12; row--) { 4475685f66aSYouMin Chen test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE + 4485685f66aSYouMin Chen cs0_cap + 4495685f66aSYouMin Chen (1ul << (row + bktmp + coltmp + bw - 1ul))); 4505685f66aSYouMin Chen writel(0, CONFIG_SYS_SDRAM_BASE + cs0_cap); 4515685f66aSYouMin Chen writel(PATTERN, test_addr); 4525685f66aSYouMin Chen 4535685f66aSYouMin Chen if (((readl(test_addr) & byte_mask) == 4545685f66aSYouMin Chen (PATTERN & byte_mask)) && 4555685f66aSYouMin Chen ((readl(CONFIG_SYS_SDRAM_BASE + cs0_cap) & 4565685f66aSYouMin Chen byte_mask) == 0)) { 4575685f66aSYouMin Chen break; 4585685f66aSYouMin Chen } 4595685f66aSYouMin Chen } 4605685f66aSYouMin Chen } 4615685f66aSYouMin Chen 4625685f66aSYouMin Chen cap_info->cs1_row = row; 4635685f66aSYouMin Chen 4645685f66aSYouMin Chen return 0; 4655685f66aSYouMin Chen } 4665685f66aSYouMin Chen 467