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); 83*f627cf25SZhihuan He if (cap_info->cs2_high16bit_row != 84*f627cf25SZhihuan He cap_info->cs2_row) { 85*f627cf25SZhihuan He printascii("/"); 86*f627cf25SZhihuan He printdec(cap_info->cs2_high16bit_row); 87*f627cf25SZhihuan He } 88de9242dcSTang Yun ping printascii(" CS3 Row="); 89de9242dcSTang Yun ping printdec(cap_info->cs3_row); 90*f627cf25SZhihuan He if (cap_info->cs3_high16bit_row != 91*f627cf25SZhihuan He cap_info->cs3_row) { 92*f627cf25SZhihuan He printascii("/"); 93*f627cf25SZhihuan He printdec(cap_info->cs3_high16bit_row); 94*f627cf25SZhihuan He } 95de9242dcSTang Yun ping } 965685f66aSYouMin Chen printascii(" CS="); 975685f66aSYouMin Chen printdec(cap_info->rank); 985685f66aSYouMin Chen printascii(" Die BW="); 995685f66aSYouMin Chen printdec(8 << cap_info->dbw); 1005685f66aSYouMin Chen 1015685f66aSYouMin Chen cap = sdram_get_cs_cap(cap_info, 3, base->dramtype); 1025685f66aSYouMin Chen if (cap_info->row_3_4) 1035685f66aSYouMin Chen cap = cap * 3 / 4; 1045685f66aSYouMin Chen else if (split) 1055685f66aSYouMin Chen cap = cap / 2 + (split << 24) / 2; 1065685f66aSYouMin Chen 1075685f66aSYouMin Chen printascii(" Size="); 1085685f66aSYouMin Chen printdec(cap >> 20); 1095685f66aSYouMin Chen printascii("MB\n"); 1105685f66aSYouMin Chen } 1115685f66aSYouMin Chen 1125685f66aSYouMin Chen /* 1135685f66aSYouMin Chen * cs: 0:cs0 1145685f66aSYouMin Chen * 1:cs1 1155685f66aSYouMin Chen * else cs0+cs1 1165685f66aSYouMin Chen * note: it didn't consider about row_3_4 1175685f66aSYouMin Chen */ 1185685f66aSYouMin Chen u64 sdram_get_cs_cap(struct sdram_cap_info *cap_info, u32 cs, u32 dram_type) 1195685f66aSYouMin Chen { 1205685f66aSYouMin Chen u32 bg; 121de9242dcSTang Yun ping u64 cap[4]; 1225685f66aSYouMin Chen 1235685f66aSYouMin Chen if (dram_type == DDR4) 1245685f66aSYouMin Chen /* DDR4 8bit dram BG = 2(4bank groups), 1255685f66aSYouMin Chen * 16bit dram BG = 1 (2 bank groups) 1265685f66aSYouMin Chen */ 1275685f66aSYouMin Chen bg = (cap_info->dbw == 0) ? 2 : 1; 1285685f66aSYouMin Chen else 1295685f66aSYouMin Chen bg = 0; 1305685f66aSYouMin Chen cap[0] = 1llu << (cap_info->bw + cap_info->col + 1315685f66aSYouMin Chen bg + cap_info->bk + cap_info->cs0_row); 1325685f66aSYouMin Chen 133de9242dcSTang Yun ping if (cap_info->rank >= 2) 1345685f66aSYouMin Chen cap[1] = 1llu << (cap_info->bw + cap_info->col + 1355685f66aSYouMin Chen bg + cap_info->bk + cap_info->cs1_row); 1365685f66aSYouMin Chen else 1375685f66aSYouMin Chen cap[1] = 0; 1381a6462e1STang Yun ping 139de9242dcSTang Yun ping if (cap_info->rank == 4) { 140de9242dcSTang Yun ping cap[2] = 1llu << (cap_info->bw + cap_info->col + 141de9242dcSTang Yun ping bg + cap_info->bk + cap_info->cs2_row); 142de9242dcSTang Yun ping cap[3] = 1llu << (cap_info->bw + cap_info->col + 143de9242dcSTang Yun ping bg + cap_info->bk + cap_info->cs3_row); 144de9242dcSTang Yun ping } else { 145de9242dcSTang Yun ping cap[2] = 0; 146de9242dcSTang Yun ping cap[3] = 0; 147de9242dcSTang Yun ping } 1485685f66aSYouMin Chen if (cs == 0) 1495685f66aSYouMin Chen return cap[0]; 1505685f66aSYouMin Chen else if (cs == 1) 1515685f66aSYouMin Chen return cap[1]; 1525685f66aSYouMin Chen else 153de9242dcSTang Yun ping return (cap[0] + cap[1] + cap[2] + cap[3]); 1545685f66aSYouMin Chen } 1555685f66aSYouMin Chen 1565685f66aSYouMin Chen /* n: Unit bytes */ 1575685f66aSYouMin Chen void sdram_copy_to_reg(u32 *dest, const u32 *src, u32 n) 1585685f66aSYouMin Chen { 1595685f66aSYouMin Chen int i; 1605685f66aSYouMin Chen 1615685f66aSYouMin Chen for (i = 0; i < n / sizeof(u32); i++) { 1625685f66aSYouMin Chen writel(*src, dest); 1635685f66aSYouMin Chen src++; 1645685f66aSYouMin Chen dest++; 1655685f66aSYouMin Chen } 1665685f66aSYouMin Chen } 1675685f66aSYouMin Chen 1685685f66aSYouMin Chen void sdram_org_config(struct sdram_cap_info *cap_info, 1695685f66aSYouMin Chen struct sdram_base_params *base, 1705685f66aSYouMin Chen u32 *p_os_reg2, u32 *p_os_reg3, u32 channel) 1715685f66aSYouMin Chen { 1725685f66aSYouMin Chen *p_os_reg2 |= SYS_REG_ENC_DDRTYPE(base->dramtype); 1735685f66aSYouMin Chen *p_os_reg2 |= SYS_REG_ENC_NUM_CH(base->num_channels); 1745685f66aSYouMin Chen 1755685f66aSYouMin Chen *p_os_reg2 |= SYS_REG_ENC_ROW_3_4(cap_info->row_3_4, channel); 1765685f66aSYouMin Chen *p_os_reg2 |= SYS_REG_ENC_CHINFO(channel); 1775685f66aSYouMin Chen *p_os_reg2 |= SYS_REG_ENC_RANK(cap_info->rank, channel); 1785685f66aSYouMin Chen *p_os_reg2 |= SYS_REG_ENC_COL(cap_info->col, channel); 1795685f66aSYouMin Chen *p_os_reg2 |= SYS_REG_ENC_BK(cap_info->bk, channel); 1805685f66aSYouMin Chen *p_os_reg2 |= SYS_REG_ENC_BW(cap_info->bw, channel); 1815685f66aSYouMin Chen *p_os_reg2 |= SYS_REG_ENC_DBW(cap_info->dbw, channel); 1825685f66aSYouMin Chen 1835685f66aSYouMin Chen SYS_REG_ENC_CS0_ROW(cap_info->cs0_row, *p_os_reg2, *p_os_reg3, channel); 1845685f66aSYouMin Chen if (cap_info->cs1_row) 1855685f66aSYouMin Chen SYS_REG_ENC_CS1_ROW(cap_info->cs1_row, *p_os_reg2, 1865685f66aSYouMin Chen *p_os_reg3, channel); 1875685f66aSYouMin Chen *p_os_reg3 |= SYS_REG_ENC_CS1_COL(cap_info->col, channel); 1885685f66aSYouMin Chen *p_os_reg3 |= SYS_REG_ENC_VERSION(DDR_SYS_REG_VERSION); 1895685f66aSYouMin Chen } 1905685f66aSYouMin Chen 191c69667e0STang Yun ping void sdram_org_config_v3(struct sdram_cap_info *cap_info, 192c69667e0STang Yun ping struct sdram_base_params *base, 193c69667e0STang Yun ping u32 *p_os_reg2, u32 *p_os_reg3, u32 channel) 194c69667e0STang Yun ping { 195c69667e0STang Yun ping SYS_REG_ENC_DDRTYPE_V3(base->dramtype, *p_os_reg2, *p_os_reg3); 196c69667e0STang Yun ping 197c69667e0STang Yun ping *p_os_reg2 |= SYS_REG_ENC_NUM_CH_V3((base->num_channels > 2) ? 198c69667e0STang Yun ping 2 : base->num_channels); 199c69667e0STang Yun ping 200c69667e0STang Yun ping *p_os_reg2 |= SYS_REG_ENC_ROW_3_4_V3(cap_info->row_3_4, channel); 201c69667e0STang Yun ping *p_os_reg2 |= SYS_REG_ENC_CHINFO_V3((channel >= 2) ? channel - 2 : channel); 202c69667e0STang Yun ping if (channel == 0 || channel == 2) 203c69667e0STang Yun ping SYS_REG_ENC_CH0_2_RANK_V3(cap_info->rank, 204c69667e0STang Yun ping *p_os_reg2, *p_os_reg3); 205c69667e0STang Yun ping else 206c69667e0STang Yun ping *p_os_reg2 |= SYS_REG_ENC_CH1_3_RANK(cap_info->rank); 207c69667e0STang Yun ping 208c69667e0STang Yun ping *p_os_reg2 |= SYS_REG_ENC_COL_V3(cap_info->col, channel); 209c69667e0STang Yun ping *p_os_reg2 |= SYS_REG_ENC_BK_V3(cap_info->bk, channel); 210c69667e0STang Yun ping *p_os_reg2 |= SYS_REG_ENC_BW_V3(cap_info->bw, channel); 211c69667e0STang Yun ping *p_os_reg2 |= SYS_REG_ENC_DBW_V3(cap_info->dbw, channel); 212c69667e0STang Yun ping 213c69667e0STang Yun ping SYS_REG_ENC_CS0_ROW_V3(cap_info->cs0_row, *p_os_reg2, *p_os_reg3, channel); 214c69667e0STang Yun ping if (cap_info->cs1_row) 215c69667e0STang Yun ping SYS_REG_ENC_CS1_ROW_V3(cap_info->cs1_row, *p_os_reg2, 216c69667e0STang Yun ping *p_os_reg3, channel); 217c69667e0STang Yun ping if ((channel == 0 || channel == 2) && cap_info->rank > 2) { 218c69667e0STang Yun ping if (cap_info->cs2_row == cap_info->cs0_row) 219c69667e0STang Yun ping *p_os_reg3 |= SYS_REG_ENC_CS2_DELTA_ROW_V3(0); 220c69667e0STang Yun ping else 221c69667e0STang Yun ping *p_os_reg3 |= SYS_REG_ENC_CS2_DELTA_ROW_V3(1); 222c69667e0STang Yun ping 223c69667e0STang Yun ping if (cap_info->cs3_row == cap_info->cs0_row) 224c69667e0STang Yun ping *p_os_reg3 |= SYS_REG_ENC_CS3_DELTA_ROW_V3(0); 225c69667e0STang Yun ping else 226c69667e0STang Yun ping *p_os_reg3 |= SYS_REG_ENC_CS3_DELTA_ROW_V3(1); 227c69667e0STang Yun ping } 228c69667e0STang Yun ping 229c69667e0STang Yun ping *p_os_reg3 |= SYS_REG_ENC_CS1_COL_V3(cap_info->col, channel); 230c69667e0STang Yun ping *p_os_reg3 |= SYS_REG_ENC_VERSION(DDR_SYS_REG_VERSION_3); 231c69667e0STang Yun ping } 232c69667e0STang Yun ping 2335685f66aSYouMin Chen int sdram_detect_bw(struct sdram_cap_info *cap_info) 2345685f66aSYouMin Chen { 2355685f66aSYouMin Chen return 0; 2365685f66aSYouMin Chen } 2375685f66aSYouMin Chen 2385685f66aSYouMin Chen int sdram_detect_cs(struct sdram_cap_info *cap_info) 2395685f66aSYouMin Chen { 2405685f66aSYouMin Chen return 0; 2415685f66aSYouMin Chen } 2425685f66aSYouMin Chen 2435685f66aSYouMin Chen int sdram_detect_col(struct sdram_cap_info *cap_info, 2445685f66aSYouMin Chen u32 coltmp) 2455685f66aSYouMin Chen { 2465685f66aSYouMin Chen void __iomem *test_addr; 2475685f66aSYouMin Chen u32 col; 2485685f66aSYouMin Chen u32 bw = cap_info->bw; 2495685f66aSYouMin Chen 2505685f66aSYouMin Chen for (col = coltmp; col >= 9; col -= 1) { 2515685f66aSYouMin Chen writel(0, CONFIG_SYS_SDRAM_BASE); 2525685f66aSYouMin Chen test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE + 2535685f66aSYouMin Chen (1ul << (col + bw - 1ul))); 2545685f66aSYouMin Chen writel(PATTERN, test_addr); 2555685f66aSYouMin Chen if ((readl(test_addr) == PATTERN) && 2565685f66aSYouMin Chen (readl(CONFIG_SYS_SDRAM_BASE) == 0)) 2575685f66aSYouMin Chen break; 2585685f66aSYouMin Chen } 2595685f66aSYouMin Chen if (col == 8) { 2605685f66aSYouMin Chen printascii("col error\n"); 2615685f66aSYouMin Chen return -1; 2625685f66aSYouMin Chen } 2635685f66aSYouMin Chen 2645685f66aSYouMin Chen cap_info->col = col; 2655685f66aSYouMin Chen 2665685f66aSYouMin Chen return 0; 2675685f66aSYouMin Chen } 2685685f66aSYouMin Chen 2695685f66aSYouMin Chen int sdram_detect_bank(struct sdram_cap_info *cap_info, 2705685f66aSYouMin Chen u32 coltmp, u32 bktmp) 2715685f66aSYouMin Chen { 2725685f66aSYouMin Chen void __iomem *test_addr; 2735685f66aSYouMin Chen u32 bk; 2745685f66aSYouMin Chen u32 bw = cap_info->bw; 2755685f66aSYouMin Chen 2765685f66aSYouMin Chen test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE + 2775685f66aSYouMin Chen (1ul << (coltmp + bktmp + bw - 1ul))); 2785685f66aSYouMin Chen writel(0, CONFIG_SYS_SDRAM_BASE); 2795685f66aSYouMin Chen writel(PATTERN, test_addr); 2805685f66aSYouMin Chen if ((readl(test_addr) == PATTERN) && 2815685f66aSYouMin Chen (readl(CONFIG_SYS_SDRAM_BASE) == 0)) 2825685f66aSYouMin Chen bk = 3; 2835685f66aSYouMin Chen else 2845685f66aSYouMin Chen bk = 2; 2855685f66aSYouMin Chen 2865685f66aSYouMin Chen cap_info->bk = bk; 2875685f66aSYouMin Chen 2885685f66aSYouMin Chen return 0; 2895685f66aSYouMin Chen } 2905685f66aSYouMin Chen 2915685f66aSYouMin Chen /* detect bg for ddr4 */ 2925685f66aSYouMin Chen int sdram_detect_bg(struct sdram_cap_info *cap_info, 2935685f66aSYouMin Chen u32 coltmp) 2945685f66aSYouMin Chen { 2955685f66aSYouMin Chen void __iomem *test_addr; 2965685f66aSYouMin Chen u32 dbw; 2975685f66aSYouMin Chen u32 bw = cap_info->bw; 2985685f66aSYouMin Chen 2995685f66aSYouMin Chen test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE + 3005685f66aSYouMin Chen (1ul << (coltmp + bw + 1ul))); 3015685f66aSYouMin Chen writel(0, CONFIG_SYS_SDRAM_BASE); 3025685f66aSYouMin Chen writel(PATTERN, test_addr); 3035685f66aSYouMin Chen if ((readl(test_addr) == PATTERN) && 3045685f66aSYouMin Chen (readl(CONFIG_SYS_SDRAM_BASE) == 0)) 3055685f66aSYouMin Chen dbw = 0; 3065685f66aSYouMin Chen else 3075685f66aSYouMin Chen dbw = 1; 3085685f66aSYouMin Chen 3095685f66aSYouMin Chen cap_info->dbw = dbw; 3105685f66aSYouMin Chen 3115685f66aSYouMin Chen return 0; 3125685f66aSYouMin Chen } 3135685f66aSYouMin Chen 3145685f66aSYouMin Chen /* detect dbw for ddr3,lpddr2,lpddr3,lpddr4 */ 3155685f66aSYouMin Chen int sdram_detect_dbw(struct sdram_cap_info *cap_info, u32 dram_type) 3165685f66aSYouMin Chen { 3175685f66aSYouMin Chen u32 row, col, bk, bw, cs_cap, cs; 3185685f66aSYouMin Chen u32 die_bw_0 = 0, die_bw_1 = 0; 3195685f66aSYouMin Chen 3209d5c314bSWesley Yao if (dram_type == DDR3) { 3219d5c314bSWesley Yao if (cap_info->bw == 0) 3229d5c314bSWesley Yao cap_info->dbw = 0; 3239d5c314bSWesley Yao else 3249d5c314bSWesley Yao cap_info->dbw = 1; 3259d5c314bSWesley Yao } else if (dram_type == LPDDR4) { 3265685f66aSYouMin Chen cap_info->dbw = 1; 3275685f66aSYouMin Chen } else if (dram_type == LPDDR3 || dram_type == LPDDR2) { 3285685f66aSYouMin Chen row = cap_info->cs0_row; 3295685f66aSYouMin Chen col = cap_info->col; 3305685f66aSYouMin Chen bk = cap_info->bk; 3315685f66aSYouMin Chen cs = cap_info->rank; 3325685f66aSYouMin Chen bw = cap_info->bw; 3335685f66aSYouMin Chen cs_cap = (1 << (row + col + bk + bw - 20)); 3345685f66aSYouMin Chen if (bw == 2) { 3355685f66aSYouMin Chen if (cs_cap <= 0x2000000) /* 256Mb */ 3365685f66aSYouMin Chen die_bw_0 = (col < 9) ? 2 : 1; 3375685f66aSYouMin Chen else if (cs_cap <= 0x10000000) /* 2Gb */ 3385685f66aSYouMin Chen die_bw_0 = (col < 10) ? 2 : 1; 3395685f66aSYouMin Chen else if (cs_cap <= 0x40000000) /* 8Gb */ 3405685f66aSYouMin Chen die_bw_0 = (col < 11) ? 2 : 1; 3415685f66aSYouMin Chen else 3425685f66aSYouMin Chen die_bw_0 = (col < 12) ? 2 : 1; 3435685f66aSYouMin Chen if (cs > 1) { 3445685f66aSYouMin Chen row = cap_info->cs1_row; 3455685f66aSYouMin Chen cs_cap = (1 << (row + col + bk + bw - 20)); 3465685f66aSYouMin Chen if (cs_cap <= 0x2000000) /* 256Mb */ 3475685f66aSYouMin Chen die_bw_0 = (col < 9) ? 2 : 1; 3485685f66aSYouMin Chen else if (cs_cap <= 0x10000000) /* 2Gb */ 3495685f66aSYouMin Chen die_bw_0 = (col < 10) ? 2 : 1; 3505685f66aSYouMin Chen else if (cs_cap <= 0x40000000) /* 8Gb */ 3515685f66aSYouMin Chen die_bw_0 = (col < 11) ? 2 : 1; 3525685f66aSYouMin Chen else 3535685f66aSYouMin Chen die_bw_0 = (col < 12) ? 2 : 1; 3545685f66aSYouMin Chen } 3555685f66aSYouMin Chen } else { 3565685f66aSYouMin Chen die_bw_1 = 1; 3575685f66aSYouMin Chen die_bw_0 = 1; 3585685f66aSYouMin Chen } 3595685f66aSYouMin Chen cap_info->dbw = (die_bw_0 > die_bw_1) ? die_bw_0 : die_bw_1; 3605685f66aSYouMin Chen } 3615685f66aSYouMin Chen 3625685f66aSYouMin Chen return 0; 3635685f66aSYouMin Chen } 3645685f66aSYouMin Chen 3655685f66aSYouMin Chen int sdram_detect_row(struct sdram_cap_info *cap_info, 3665685f66aSYouMin Chen u32 coltmp, u32 bktmp, u32 rowtmp) 3675685f66aSYouMin Chen { 3685685f66aSYouMin Chen u32 row; 3695685f66aSYouMin Chen u32 bw = cap_info->bw; 3705685f66aSYouMin Chen void __iomem *test_addr; 3715685f66aSYouMin Chen 3725685f66aSYouMin Chen for (row = rowtmp; row > 12; row--) { 3735685f66aSYouMin Chen writel(0, CONFIG_SYS_SDRAM_BASE); 3745685f66aSYouMin Chen test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE + 3755685f66aSYouMin Chen (1ul << (row + bktmp + coltmp + bw - 1ul))); 3765685f66aSYouMin Chen writel(PATTERN, test_addr); 3775685f66aSYouMin Chen if ((readl(test_addr) == PATTERN) && 3785685f66aSYouMin Chen (readl(CONFIG_SYS_SDRAM_BASE) == 0)) 3795685f66aSYouMin Chen break; 3805685f66aSYouMin Chen } 3815685f66aSYouMin Chen if (row == 12) { 3825685f66aSYouMin Chen printascii("row error"); 3835685f66aSYouMin Chen return -1; 3845685f66aSYouMin Chen } 3855685f66aSYouMin Chen 3865685f66aSYouMin Chen cap_info->cs0_row = row; 3875685f66aSYouMin Chen 3885685f66aSYouMin Chen return 0; 3895685f66aSYouMin Chen } 3905685f66aSYouMin Chen 3915685f66aSYouMin Chen int sdram_detect_row_3_4(struct sdram_cap_info *cap_info, 3925685f66aSYouMin Chen u32 coltmp, u32 bktmp) 3935685f66aSYouMin Chen { 3945685f66aSYouMin Chen u32 row_3_4; 3955685f66aSYouMin Chen u32 bw = cap_info->bw; 3965685f66aSYouMin Chen u32 row = cap_info->cs0_row; 3975685f66aSYouMin Chen void __iomem *test_addr, *test_addr1; 3985685f66aSYouMin Chen 3995685f66aSYouMin Chen test_addr = CONFIG_SYS_SDRAM_BASE; 4005685f66aSYouMin Chen test_addr1 = (void __iomem *)(CONFIG_SYS_SDRAM_BASE + 4015685f66aSYouMin Chen (0x3ul << (row + bktmp + coltmp + bw - 1ul - 1ul))); 4025685f66aSYouMin Chen 4035685f66aSYouMin Chen writel(0, test_addr); 4045685f66aSYouMin Chen writel(PATTERN, test_addr1); 4055685f66aSYouMin Chen if ((readl(test_addr) == 0) && (readl(test_addr1) == PATTERN)) 4065685f66aSYouMin Chen row_3_4 = 0; 4075685f66aSYouMin Chen else 4085685f66aSYouMin Chen row_3_4 = 1; 4095685f66aSYouMin Chen 4105685f66aSYouMin Chen cap_info->row_3_4 = row_3_4; 4115685f66aSYouMin Chen 4125685f66aSYouMin Chen return 0; 4135685f66aSYouMin Chen } 4145685f66aSYouMin Chen 415*f627cf25SZhihuan He int sdram_detect_high_row(struct sdram_cap_info *cap_info, u32 dramtype) 4165685f66aSYouMin Chen { 417*f627cf25SZhihuan He unsigned long base_addr; 418*f627cf25SZhihuan He u32 cs0_high_row, cs1_high_row, cs; 419*f627cf25SZhihuan He u64 cap = 0, cs0_cap = 0; 420*f627cf25SZhihuan He u32 i; 421*f627cf25SZhihuan He void __iomem *test_addr, *test_addr1; 422*f627cf25SZhihuan He #ifdef CONFIG_ROCKCHIP_RK3568 423*f627cf25SZhihuan He u32 cs2_high_row, cs3_high_row; 424*f627cf25SZhihuan He #endif 425*f627cf25SZhihuan He 426*f627cf25SZhihuan He cs = cap_info->rank; 427*f627cf25SZhihuan He /* 8bit bandwidth no enable axi split*/ 428*f627cf25SZhihuan He if (!cap_info->bw) { 429*f627cf25SZhihuan He cs0_high_row = cap_info->cs0_row; 430*f627cf25SZhihuan He cs1_high_row = cap_info->cs1_row; 431*f627cf25SZhihuan He #ifdef CONFIG_ROCKCHIP_RK3568 432*f627cf25SZhihuan He if (cs > 2) { 433*f627cf25SZhihuan He cs2_high_row = cap_info->cs2_row; 434*f627cf25SZhihuan He cs3_high_row = cap_info->cs3_row; 435*f627cf25SZhihuan He } 436*f627cf25SZhihuan He #endif 437*f627cf25SZhihuan He goto out; 438*f627cf25SZhihuan He } 439*f627cf25SZhihuan He #ifdef CONFIG_ROCKCHIP_RK3568 440*f627cf25SZhihuan He if (cs > 2) { 441*f627cf25SZhihuan He cs0_high_row = cap_info->cs0_row; 442*f627cf25SZhihuan He cs1_high_row = cap_info->cs1_row; 443*f627cf25SZhihuan He cs2_high_row = cap_info->cs2_row; 444*f627cf25SZhihuan He cs3_high_row = cap_info->cs3_row; 445*f627cf25SZhihuan He 446*f627cf25SZhihuan He goto out; 447*f627cf25SZhihuan He } 448*f627cf25SZhihuan He #endif 449*f627cf25SZhihuan He 450*f627cf25SZhihuan He cs0_cap = sdram_get_cs_cap(cap_info, 0, dramtype); 451*f627cf25SZhihuan He if (cs == 2) { 452*f627cf25SZhihuan He base_addr = CONFIG_SYS_SDRAM_BASE + cs0_cap; 453*f627cf25SZhihuan He cap = sdram_get_cs_cap(cap_info, 1, dramtype); 454*f627cf25SZhihuan He } else { 455*f627cf25SZhihuan He base_addr = CONFIG_SYS_SDRAM_BASE; 456*f627cf25SZhihuan He cap = cs0_cap; 457*f627cf25SZhihuan He } 458*f627cf25SZhihuan He /* detect full bandwidth size */ 459*f627cf25SZhihuan He for (i = 0; i < 4; i++) { 460*f627cf25SZhihuan He test_addr = (void __iomem *)base_addr; 461*f627cf25SZhihuan He test_addr1 = (void __iomem *)(base_addr + 462*f627cf25SZhihuan He (unsigned long)(cap / (1ul << (i + 1)))); 463*f627cf25SZhihuan He writel(0x0, test_addr); 464*f627cf25SZhihuan He writel(PATTERN, test_addr1); 465*f627cf25SZhihuan He if ((readl(test_addr) == 0x0) && 466*f627cf25SZhihuan He (readl(test_addr1) == PATTERN)) 467*f627cf25SZhihuan He break; 468*f627cf25SZhihuan He } 469*f627cf25SZhihuan He if (i == 4 && cs == 1) { 470*f627cf25SZhihuan He printascii("can't support this cap\n"); 471*f627cf25SZhihuan He return -1; 472*f627cf25SZhihuan He } 473*f627cf25SZhihuan He 474*f627cf25SZhihuan He if (cs == 2) { 475*f627cf25SZhihuan He cs0_high_row = cap_info->cs0_row; 476*f627cf25SZhihuan He if (i == 4) 477*f627cf25SZhihuan He cs1_high_row = 0; 478*f627cf25SZhihuan He else 479*f627cf25SZhihuan He cs1_high_row = cap_info->cs1_row - i; 480*f627cf25SZhihuan He } else { 481*f627cf25SZhihuan He cs0_high_row = cap_info->cs0_row - i; 482*f627cf25SZhihuan He cs1_high_row = 0; 483*f627cf25SZhihuan He } 484*f627cf25SZhihuan He 485*f627cf25SZhihuan He out: 486*f627cf25SZhihuan He cap_info->cs0_high16bit_row = cs0_high_row; 487*f627cf25SZhihuan He cap_info->cs1_high16bit_row = cs1_high_row; 488*f627cf25SZhihuan He #ifdef CONFIG_ROCKCHIP_RK3568 489*f627cf25SZhihuan He if (cs > 2) { 490*f627cf25SZhihuan He cap_info->cs2_high16bit_row = cs2_high_row; 491*f627cf25SZhihuan He cap_info->cs3_high16bit_row = cs3_high_row; 492*f627cf25SZhihuan He } 493*f627cf25SZhihuan He #endif 4945685f66aSYouMin Chen 4955685f66aSYouMin Chen return 0; 4965685f66aSYouMin Chen } 4975685f66aSYouMin Chen 4985685f66aSYouMin Chen int sdram_detect_cs1_row(struct sdram_cap_info *cap_info, u32 dram_type) 4995685f66aSYouMin Chen { 5005685f66aSYouMin Chen void __iomem *test_addr; 5015685f66aSYouMin Chen u32 row = 0, bktmp, coltmp, bw; 5025685f66aSYouMin Chen ulong cs0_cap; 5035685f66aSYouMin Chen u32 byte_mask; 5045685f66aSYouMin Chen 5055685f66aSYouMin Chen if (cap_info->rank == 2) { 5065685f66aSYouMin Chen cs0_cap = sdram_get_cs_cap(cap_info, 0, dram_type); 5075685f66aSYouMin Chen 5085685f66aSYouMin Chen if (dram_type == DDR4) { 5095685f66aSYouMin Chen if (cap_info->dbw == 0) 5105685f66aSYouMin Chen bktmp = cap_info->bk + 2; 5115685f66aSYouMin Chen else 5125685f66aSYouMin Chen bktmp = cap_info->bk + 1; 5135685f66aSYouMin Chen } else { 5145685f66aSYouMin Chen bktmp = cap_info->bk; 5155685f66aSYouMin Chen } 5165685f66aSYouMin Chen bw = cap_info->bw; 5175685f66aSYouMin Chen coltmp = cap_info->col; 5185685f66aSYouMin Chen 5195685f66aSYouMin Chen /* 5205685f66aSYouMin Chen * because px30 support axi split,min bandwidth 5215685f66aSYouMin Chen * is 8bit. if cs0 is 32bit, cs1 may 32bit or 16bit 5225685f66aSYouMin Chen * so we check low 16bit data when detect cs1 row. 5235685f66aSYouMin Chen * if cs0 is 16bit/8bit, we check low 8bit data. 5245685f66aSYouMin Chen */ 5255685f66aSYouMin Chen if (bw == 2) 5265685f66aSYouMin Chen byte_mask = 0xFFFF; 5275685f66aSYouMin Chen else 5285685f66aSYouMin Chen byte_mask = 0xFF; 5295685f66aSYouMin Chen 5305685f66aSYouMin Chen /* detect cs1 row */ 5315685f66aSYouMin Chen for (row = cap_info->cs0_row; row > 12; row--) { 5325685f66aSYouMin Chen test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE + 5335685f66aSYouMin Chen cs0_cap + 5345685f66aSYouMin Chen (1ul << (row + bktmp + coltmp + bw - 1ul))); 5355685f66aSYouMin Chen writel(0, CONFIG_SYS_SDRAM_BASE + cs0_cap); 5365685f66aSYouMin Chen writel(PATTERN, test_addr); 5375685f66aSYouMin Chen 5385685f66aSYouMin Chen if (((readl(test_addr) & byte_mask) == 5395685f66aSYouMin Chen (PATTERN & byte_mask)) && 5405685f66aSYouMin Chen ((readl(CONFIG_SYS_SDRAM_BASE + cs0_cap) & 5415685f66aSYouMin Chen byte_mask) == 0)) { 5425685f66aSYouMin Chen break; 5435685f66aSYouMin Chen } 5445685f66aSYouMin Chen } 5455685f66aSYouMin Chen } 5465685f66aSYouMin Chen 5475685f66aSYouMin Chen cap_info->cs1_row = row; 5485685f66aSYouMin Chen 5495685f66aSYouMin Chen return 0; 5505685f66aSYouMin Chen } 5515685f66aSYouMin Chen 552