uboot/drivers/ram/rockchip/sdram_common.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * (C) Copyright 2018 Rockchip Electronics Co., Ltd.
   4 */
   5
   6#include <common.h>
   7#include <debug_uart.h>
   8#include <ram.h>
   9#include <asm/io.h>
  10#include <asm/arch-rockchip/sdram.h>
  11#include <asm/arch-rockchip/sdram_common.h>
  12
  13#ifdef CONFIG_RAM_ROCKCHIP_DEBUG
  14void sdram_print_dram_type(unsigned char dramtype)
  15{
  16        switch (dramtype) {
  17        case DDR3:
  18                printascii("DDR3");
  19                break;
  20        case DDR4:
  21                printascii("DDR4");
  22                break;
  23        case LPDDR2:
  24                printascii("LPDDR2");
  25                break;
  26        case LPDDR3:
  27                printascii("LPDDR3");
  28                break;
  29        case LPDDR4:
  30                printascii("LPDDR4");
  31                break;
  32        default:
  33                printascii("Unknown Device");
  34                break;
  35        }
  36}
  37
  38void sdram_print_ddr_info(struct sdram_cap_info *cap_info,
  39                          struct sdram_base_params *base)
  40{
  41        u64 cap;
  42        u32 bg;
  43
  44        bg = (cap_info->dbw == 0) ? 2 : 1;
  45
  46        sdram_print_dram_type(base->dramtype);
  47
  48        printascii(", ");
  49        printdec(base->ddr_freq);
  50        printascii("MHz\n");
  51
  52        printascii("BW=");
  53        printdec(8 << cap_info->bw);
  54        printascii(" Col=");
  55        printdec(cap_info->col);
  56        printascii(" Bk=");
  57        printdec(0x1 << cap_info->bk);
  58        if (base->dramtype == DDR4) {
  59                printascii(" BG=");
  60                printdec(1 << bg);
  61        }
  62        printascii(" CS0 Row=");
  63        printdec(cap_info->cs0_row);
  64        if (cap_info->cs0_high16bit_row !=
  65                cap_info->cs0_row) {
  66                printascii("/");
  67                printdec(cap_info->cs0_high16bit_row);
  68        }
  69        if (cap_info->rank > 1) {
  70                printascii(" CS1 Row=");
  71                printdec(cap_info->cs1_row);
  72                if (cap_info->cs1_high16bit_row !=
  73                        cap_info->cs1_row) {
  74                        printascii("/");
  75                        printdec(cap_info->cs1_high16bit_row);
  76                }
  77        }
  78        printascii(" CS=");
  79        printdec(cap_info->rank);
  80        printascii(" Die BW=");
  81        printdec(8 << cap_info->dbw);
  82
  83        cap = sdram_get_cs_cap(cap_info, 3, base->dramtype);
  84        if (cap_info->row_3_4)
  85                cap = cap * 3 / 4;
  86
  87        printascii(" Size=");
  88        printdec(cap >> 20);
  89        printascii("MB\n");
  90}
  91
  92void sdram_print_stride(unsigned int stride)
  93{
  94        switch (stride) {
  95        case 0xc:
  96                printf("128B stride\n");
  97                break;
  98        case 5:
  99        case 9:
 100        case 0xd:
 101        case 0x11:
 102        case 0x19:
 103                printf("256B stride\n");
 104                break;
 105        case 0xa:
 106        case 0xe:
 107        case 0x12:
 108                printf("512B stride\n");
 109                break;
 110        case 0xf:
 111                printf("4K stride\n");
 112                break;
 113        case 0x1f:
 114                printf("32MB + 256B stride\n");
 115                break;
 116        default:
 117                printf("no stride\n");
 118        }
 119}
 120#endif
 121
 122/*
 123 * cs: 0:cs0
 124 *         1:cs1
 125 *     else cs0+cs1
 126 * note: it didn't consider about row_3_4
 127 */
 128u64 sdram_get_cs_cap(struct sdram_cap_info *cap_info, u32 cs, u32 dram_type)
 129{
 130        u32 bg;
 131        u64 cap[2];
 132
 133        if (dram_type == DDR4)
 134                /* DDR4 8bit dram BG = 2(4bank groups),
 135                 * 16bit dram BG = 1 (2 bank groups)
 136                 */
 137                bg = (cap_info->dbw == 0) ? 2 : 1;
 138        else
 139                bg = 0;
 140        cap[0] = 1llu << (cap_info->bw + cap_info->col +
 141                bg + cap_info->bk + cap_info->cs0_row);
 142
 143        if (cap_info->rank == 2)
 144                cap[1] = 1llu << (cap_info->bw + cap_info->col +
 145                        bg + cap_info->bk + cap_info->cs1_row);
 146        else
 147                cap[1] = 0;
 148
 149        if (cs == 0)
 150                return cap[0];
 151        else if (cs == 1)
 152                return cap[1];
 153        else
 154                return (cap[0] + cap[1]);
 155}
 156
 157/* n: Unit bytes */
 158void sdram_copy_to_reg(u32 *dest, const u32 *src, u32 n)
 159{
 160        int i;
 161
 162        for (i = 0; i < n / sizeof(u32); i++) {
 163                writel(*src, dest);
 164                src++;
 165                dest++;
 166        }
 167}
 168
 169void sdram_org_config(struct sdram_cap_info *cap_info,
 170                      struct sdram_base_params *base,
 171                      u32 *p_os_reg2, u32 *p_os_reg3, u32 channel)
 172{
 173        *p_os_reg2 |= SYS_REG_ENC_DDRTYPE(base->dramtype);
 174        *p_os_reg2 |= SYS_REG_ENC_NUM_CH(base->num_channels);
 175
 176        *p_os_reg2 |= SYS_REG_ENC_ROW_3_4(cap_info->row_3_4, channel);
 177        *p_os_reg2 |= SYS_REG_ENC_CHINFO(channel);
 178        *p_os_reg2 |= SYS_REG_ENC_RANK(cap_info->rank, channel);
 179        *p_os_reg2 |= SYS_REG_ENC_COL(cap_info->col, channel);
 180        *p_os_reg2 |= SYS_REG_ENC_BK(cap_info->bk, channel);
 181        *p_os_reg2 |= SYS_REG_ENC_BW(cap_info->bw, channel);
 182        *p_os_reg2 |= SYS_REG_ENC_DBW(cap_info->dbw, channel);
 183
 184        SYS_REG_ENC_CS0_ROW(cap_info->cs0_row, *p_os_reg2, *p_os_reg3, channel);
 185        if (cap_info->cs1_row)
 186                SYS_REG_ENC_CS1_ROW(cap_info->cs1_row, *p_os_reg2,
 187                                    *p_os_reg3, channel);
 188        *p_os_reg3 |= SYS_REG_ENC_CS1_COL(cap_info->col, channel);
 189        *p_os_reg3 |= SYS_REG_ENC_VERSION(DDR_SYS_REG_VERSION);
 190}
 191
 192int sdram_detect_bw(struct sdram_cap_info *cap_info)
 193{
 194        return 0;
 195}
 196
 197int sdram_detect_cs(struct sdram_cap_info *cap_info)
 198{
 199        return 0;
 200}
 201
 202int sdram_detect_col(struct sdram_cap_info *cap_info,
 203                     u32 coltmp)
 204{
 205        void __iomem *test_addr;
 206        u32 col;
 207        u32 bw = cap_info->bw;
 208
 209        for (col = coltmp; col >= 9; col -= 1) {
 210                writel(0, CONFIG_SYS_SDRAM_BASE);
 211                test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
 212                                (1ul << (col + bw - 1ul)));
 213                writel(PATTERN, test_addr);
 214                if ((readl(test_addr) == PATTERN) &&
 215                    (readl(CONFIG_SYS_SDRAM_BASE) == 0))
 216                        break;
 217        }
 218        if (col == 8) {
 219                printascii("col error\n");
 220                return -1;
 221        }
 222
 223        cap_info->col = col;
 224
 225        return 0;
 226}
 227
 228int sdram_detect_bank(struct sdram_cap_info *cap_info,
 229                      u32 coltmp, u32 bktmp)
 230{
 231        void __iomem *test_addr;
 232        u32 bk;
 233        u32 bw = cap_info->bw;
 234
 235        test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
 236                        (1ul << (coltmp + bktmp + bw - 1ul)));
 237        writel(0, CONFIG_SYS_SDRAM_BASE);
 238        writel(PATTERN, test_addr);
 239        if ((readl(test_addr) == PATTERN) &&
 240            (readl(CONFIG_SYS_SDRAM_BASE) == 0))
 241                bk = 3;
 242        else
 243                bk = 2;
 244
 245        cap_info->bk = bk;
 246
 247        return 0;
 248}
 249
 250/* detect bg for ddr4 */
 251int sdram_detect_bg(struct sdram_cap_info *cap_info,
 252                    u32 coltmp)
 253{
 254        void __iomem *test_addr;
 255        u32 dbw;
 256        u32 bw = cap_info->bw;
 257
 258        test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
 259                        (1ul << (coltmp + bw + 1ul)));
 260        writel(0, CONFIG_SYS_SDRAM_BASE);
 261        writel(PATTERN, test_addr);
 262        if ((readl(test_addr) == PATTERN) &&
 263            (readl(CONFIG_SYS_SDRAM_BASE) == 0))
 264                dbw = 0;
 265        else
 266                dbw = 1;
 267
 268        cap_info->dbw = dbw;
 269
 270        return 0;
 271}
 272
 273/* detect dbw for ddr3,lpddr2,lpddr3,lpddr4 */
 274int sdram_detect_dbw(struct sdram_cap_info *cap_info, u32 dram_type)
 275{
 276        u32 row, col, bk, bw, cs_cap, cs;
 277        u32 die_bw_0 = 0, die_bw_1 = 0;
 278
 279        if (dram_type == DDR3 || dram_type == LPDDR4) {
 280                cap_info->dbw = 1;
 281        } else if (dram_type == LPDDR3 || dram_type == LPDDR2) {
 282                row = cap_info->cs0_row;
 283                col = cap_info->col;
 284                bk = cap_info->bk;
 285                cs = cap_info->rank;
 286                bw = cap_info->bw;
 287                cs_cap = (1 << (row + col + bk + bw - 20));
 288                if (bw == 2) {
 289                        if (cs_cap <= 0x2000000) /* 256Mb */
 290                                die_bw_0 = (col < 9) ? 2 : 1;
 291                        else if (cs_cap <= 0x10000000) /* 2Gb */
 292                                die_bw_0 = (col < 10) ? 2 : 1;
 293                        else if (cs_cap <= 0x40000000) /* 8Gb */
 294                                die_bw_0 = (col < 11) ? 2 : 1;
 295                        else
 296                                die_bw_0 = (col < 12) ? 2 : 1;
 297                        if (cs > 1) {
 298                                row = cap_info->cs1_row;
 299                                cs_cap = (1 << (row + col + bk + bw - 20));
 300                                if (cs_cap <= 0x2000000) /* 256Mb */
 301                                        die_bw_0 = (col < 9) ? 2 : 1;
 302                                else if (cs_cap <= 0x10000000) /* 2Gb */
 303                                        die_bw_0 = (col < 10) ? 2 : 1;
 304                                else if (cs_cap <= 0x40000000) /* 8Gb */
 305                                        die_bw_0 = (col < 11) ? 2 : 1;
 306                                else
 307                                        die_bw_0 = (col < 12) ? 2 : 1;
 308                        }
 309                } else {
 310                        die_bw_1 = 1;
 311                        die_bw_0 = 1;
 312                }
 313                cap_info->dbw = (die_bw_0 > die_bw_1) ? die_bw_0 : die_bw_1;
 314        }
 315
 316        return 0;
 317}
 318
 319int sdram_detect_row(struct sdram_cap_info *cap_info,
 320                     u32 coltmp, u32 bktmp, u32 rowtmp)
 321{
 322        u32 row;
 323        u32 bw = cap_info->bw;
 324        void __iomem *test_addr;
 325
 326        for (row = rowtmp; row > 12; row--) {
 327                writel(0, CONFIG_SYS_SDRAM_BASE);
 328                test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
 329                                (1ul << (row + bktmp + coltmp + bw - 1ul)));
 330                writel(PATTERN, test_addr);
 331                if ((readl(test_addr) == PATTERN) &&
 332                    (readl(CONFIG_SYS_SDRAM_BASE) == 0))
 333                        break;
 334        }
 335        if (row == 12) {
 336                printascii("row error");
 337                return -1;
 338        }
 339
 340        cap_info->cs0_row = row;
 341
 342        return 0;
 343}
 344
 345int sdram_detect_row_3_4(struct sdram_cap_info *cap_info,
 346                         u32 coltmp, u32 bktmp)
 347{
 348        u32 row_3_4;
 349        u32 bw = cap_info->bw;
 350        u32 row = cap_info->cs0_row;
 351        void __iomem *test_addr, *test_addr1;
 352
 353        test_addr = CONFIG_SYS_SDRAM_BASE;
 354        test_addr1 = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
 355                        (0x3ul << (row + bktmp + coltmp + bw - 1ul - 1ul)));
 356
 357        writel(0, test_addr);
 358        writel(PATTERN, test_addr1);
 359        if ((readl(test_addr) == 0) && (readl(test_addr1) == PATTERN))
 360                row_3_4 = 0;
 361        else
 362                row_3_4 = 1;
 363
 364        cap_info->row_3_4 = row_3_4;
 365
 366        return 0;
 367}
 368
 369int sdram_detect_high_row(struct sdram_cap_info *cap_info)
 370{
 371        cap_info->cs0_high16bit_row = cap_info->cs0_row;
 372        cap_info->cs1_high16bit_row = cap_info->cs1_row;
 373
 374        return 0;
 375}
 376
 377int sdram_detect_cs1_row(struct sdram_cap_info *cap_info, u32 dram_type)
 378{
 379        void __iomem *test_addr;
 380        u32 row = 0, bktmp, coltmp, bw;
 381        ulong cs0_cap;
 382        u32 byte_mask;
 383
 384        if (cap_info->rank == 2) {
 385                cs0_cap = sdram_get_cs_cap(cap_info, 0, dram_type);
 386
 387                if (dram_type == DDR4) {
 388                        if (cap_info->dbw == 0)
 389                                bktmp = cap_info->bk + 2;
 390                        else
 391                                bktmp = cap_info->bk + 1;
 392                } else {
 393                        bktmp = cap_info->bk;
 394                }
 395                bw = cap_info->bw;
 396                coltmp = cap_info->col;
 397
 398                /*
 399                 * because px30 support axi split,min bandwidth
 400                 * is 8bit. if cs0 is 32bit, cs1 may 32bit or 16bit
 401                 * so we check low 16bit data when detect cs1 row.
 402                 * if cs0 is 16bit/8bit, we check low 8bit data.
 403                 */
 404                if (bw == 2)
 405                        byte_mask = 0xFFFF;
 406                else
 407                        byte_mask = 0xFF;
 408
 409                /* detect cs1 row */
 410                for (row = cap_info->cs0_row; row > 12; row--) {
 411                        test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
 412                                    cs0_cap +
 413                                    (1ul << (row + bktmp + coltmp + bw - 1ul)));
 414                        writel(0, CONFIG_SYS_SDRAM_BASE + cs0_cap);
 415                        writel(PATTERN, test_addr);
 416
 417                        if (((readl(test_addr) & byte_mask) ==
 418                             (PATTERN & byte_mask)) &&
 419                            ((readl(CONFIG_SYS_SDRAM_BASE + cs0_cap) &
 420                              byte_mask) == 0)) {
 421                                break;
 422                        }
 423                }
 424        }
 425
 426        cap_info->cs1_row = row;
 427
 428        return 0;
 429}
 430