Tom Rini | 10e4779 | 2018-05-06 17:58:06 -0400 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0+ |
Kever Yang | 5db9e67 | 2017-06-23 16:11:05 +0800 | [diff] [blame] | 2 | /* |
| 3 | * Copyright (C) 2017 Rockchip Electronics Co., Ltd. |
Kever Yang | 5db9e67 | 2017-06-23 16:11:05 +0800 | [diff] [blame] | 4 | */ |
| 5 | |
Tom Rini | dec7ea0 | 2024-05-20 13:35:03 -0600 | [diff] [blame] | 6 | #include <config.h> |
Kever Yang | 5db9e67 | 2017-06-23 16:11:05 +0800 | [diff] [blame] | 7 | #include <dm.h> |
Simon Glass | 6980b6b | 2019-11-14 12:57:45 -0700 | [diff] [blame] | 8 | #include <init.h> |
Simon Glass | 0f2af88 | 2020-05-10 11:40:05 -0600 | [diff] [blame] | 9 | #include <log.h> |
Kever Yang | 5db9e67 | 2017-06-23 16:11:05 +0800 | [diff] [blame] | 10 | #include <ram.h> |
Quentin Schulz | 6ba0686 | 2024-04-25 12:46:24 +0200 | [diff] [blame] | 11 | #include <asm/armv8/mmu.h> |
Simon Glass | 3ba929a | 2020-10-30 21:38:53 -0600 | [diff] [blame] | 12 | #include <asm/global_data.h> |
Kever Yang | 5db9e67 | 2017-06-23 16:11:05 +0800 | [diff] [blame] | 13 | #include <asm/io.h> |
Kever Yang | e47db83 | 2019-11-15 11:04:33 +0800 | [diff] [blame] | 14 | #include <asm/arch-rockchip/sdram.h> |
Kever Yang | 5db9e67 | 2017-06-23 16:11:05 +0800 | [diff] [blame] | 15 | #include <dm/uclass-internal.h> |
| 16 | |
| 17 | DECLARE_GLOBAL_DATA_PTR; |
Kever Yang | dfc8a7d | 2019-07-22 20:02:02 +0800 | [diff] [blame] | 18 | |
| 19 | #define TRUST_PARAMETER_OFFSET (34 * 1024 * 1024) |
| 20 | |
| 21 | struct tos_parameter_t { |
| 22 | u32 version; |
| 23 | u32 checksum; |
| 24 | struct { |
| 25 | char name[8]; |
| 26 | s64 phy_addr; |
| 27 | u32 size; |
| 28 | u32 flags; |
| 29 | } tee_mem; |
| 30 | struct { |
| 31 | char name[8]; |
| 32 | s64 phy_addr; |
| 33 | u32 size; |
| 34 | u32 flags; |
| 35 | } drm_mem; |
| 36 | s64 reserve[8]; |
| 37 | }; |
| 38 | |
Quentin Schulz | 6ba0686 | 2024-04-25 12:46:24 +0200 | [diff] [blame] | 39 | #ifdef CONFIG_ARM64 |
| 40 | /* Tag size and offset */ |
| 41 | #define ATAGS_SIZE SZ_8K |
| 42 | #define ATAGS_OFFSET (SZ_2M - ATAGS_SIZE) |
| 43 | #define ATAGS_PHYS_BASE (CFG_SYS_SDRAM_BASE + ATAGS_OFFSET) |
| 44 | #define ATAGS_PHYS_END (ATAGS_PHYS_BASE + ATAGS_SIZE) |
| 45 | |
| 46 | /* ATAGS memory structures */ |
| 47 | |
| 48 | enum tag_magic { |
| 49 | ATAG_NONE, |
| 50 | ATAG_CORE = 0x54410001, |
| 51 | ATAG_SERIAL = 0x54410050, |
| 52 | ATAG_DDR_MEM = 0x54410052, |
| 53 | ATAG_MAX = 0x544100ff, |
| 54 | }; |
| 55 | |
| 56 | /* |
| 57 | * An ATAG contains the following data: |
| 58 | * - header |
| 59 | * u32 size // sizeof(header + tag data) / sizeof(u32) |
| 60 | * u32 magic |
| 61 | * - tag data |
| 62 | */ |
| 63 | |
| 64 | struct tag_header { |
| 65 | u32 size; |
| 66 | u32 magic; |
| 67 | } __packed; |
| 68 | |
| 69 | /* |
| 70 | * DDR_MEM tag bank is storing data this way: |
| 71 | * - address0 |
| 72 | * - address1 |
| 73 | * - [...] |
| 74 | * - addressX |
| 75 | * - size0 |
| 76 | * - size1 |
| 77 | * - [...] |
| 78 | * - sizeX |
| 79 | * |
| 80 | * with X being tag_ddr_mem.count - 1. |
| 81 | */ |
| 82 | struct tag_ddr_mem { |
| 83 | u32 count; |
| 84 | u32 version; |
| 85 | u64 bank[20]; |
| 86 | u32 flags; |
| 87 | u32 data[2]; |
| 88 | u32 hash; |
| 89 | } __packed; |
| 90 | |
| 91 | static u32 js_hash(const void *buf, u32 len) |
| 92 | { |
| 93 | u32 i, hash = 0x47C6A7E6; |
| 94 | |
| 95 | if (!buf || !len) |
| 96 | return hash; |
| 97 | |
| 98 | for (i = 0; i < len; i++) |
| 99 | hash ^= ((hash << 5) + ((const char *)buf)[i] + (hash >> 2)); |
| 100 | |
| 101 | return hash; |
| 102 | } |
| 103 | |
| 104 | static int rockchip_dram_init_banksize(void) |
| 105 | { |
| 106 | const struct tag_header *tag_h = NULL; |
| 107 | u32 *addr = (void *)ATAGS_PHYS_BASE; |
| 108 | struct tag_ddr_mem *ddr_info; |
| 109 | u32 calc_hash; |
| 110 | u8 i, j; |
| 111 | |
| 112 | if (!IS_ENABLED(CONFIG_ROCKCHIP_RK3588) && |
| 113 | !IS_ENABLED(CONFIG_ROCKCHIP_RK3568)) |
| 114 | return -ENOTSUPP; |
| 115 | |
| 116 | if (!IS_ENABLED(CONFIG_ROCKCHIP_EXTERNAL_TPL)) |
| 117 | return -ENOTSUPP; |
| 118 | |
| 119 | /* Find DDR_MEM tag */ |
| 120 | while (addr < (u32 *)ATAGS_PHYS_END) { |
| 121 | tag_h = (const struct tag_header *)addr; |
| 122 | |
| 123 | if (!tag_h->size) { |
| 124 | debug("End of ATAGS (0-size tag), no DDR_MEM found\n"); |
| 125 | return -ENODATA; |
| 126 | } |
| 127 | |
| 128 | if (tag_h->magic == ATAG_DDR_MEM) |
| 129 | break; |
| 130 | |
| 131 | switch (tag_h->magic) { |
| 132 | case ATAG_NONE: |
| 133 | case ATAG_CORE: |
| 134 | case ATAG_SERIAL ... ATAG_MAX: |
| 135 | addr += tag_h->size; |
| 136 | continue; |
| 137 | default: |
| 138 | debug("Invalid magic (0x%08x) for ATAG at 0x%p\n", |
| 139 | tag_h->magic, addr); |
| 140 | return -EINVAL; |
| 141 | } |
| 142 | } |
| 143 | |
| 144 | if (addr >= (u32 *)ATAGS_PHYS_END || |
| 145 | (tag_h && (addr + tag_h->size > (u32 *)ATAGS_PHYS_END))) { |
| 146 | debug("End of ATAGS, no DDR_MEM found\n"); |
| 147 | return -ENODATA; |
| 148 | } |
| 149 | |
| 150 | /* Data is right after the magic member of the tag_header struct */ |
| 151 | ddr_info = (struct tag_ddr_mem *)(&tag_h->magic + 1); |
| 152 | if (!ddr_info->count || ddr_info->count > CONFIG_NR_DRAM_BANKS) { |
| 153 | debug("Too many ATAG banks, got (%d) but max allowed (%d)\n", |
| 154 | ddr_info->count, CONFIG_NR_DRAM_BANKS); |
| 155 | return -ENOMEM; |
| 156 | } |
| 157 | |
| 158 | if (!ddr_info->hash) { |
| 159 | debug("No hash for tag (0x%08x)\n", tag_h->magic); |
| 160 | } else { |
| 161 | calc_hash = js_hash(addr, sizeof(u32) * (tag_h->size - 1)); |
| 162 | |
| 163 | if (calc_hash != ddr_info->hash) { |
| 164 | debug("Incorrect hash for tag (0x%08x), got (0x%08x) expected (0x%08x)\n", |
| 165 | tag_h->magic, ddr_info->hash, calc_hash); |
| 166 | return -EINVAL; |
| 167 | } |
| 168 | } |
| 169 | |
| 170 | /* |
| 171 | * Rockchip guaranteed DDR_MEM is ordered so no need to worry about |
| 172 | * bi_dram order. |
| 173 | */ |
| 174 | for (i = 0, j = 0; i < ddr_info->count; i++, j++) { |
| 175 | phys_size_t size = ddr_info->bank[(i + ddr_info->count)]; |
| 176 | phys_addr_t start_addr = ddr_info->bank[i]; |
| 177 | struct mm_region *tmp_mem_map = mem_map; |
| 178 | phys_addr_t end_addr; |
| 179 | |
| 180 | /* |
| 181 | * BL31 (TF-A) reserves the first 2MB but DDR_MEM tag may not |
| 182 | * have it, so force this space as reserved. |
| 183 | */ |
| 184 | if (start_addr < SZ_2M) { |
| 185 | size -= SZ_2M - start_addr; |
| 186 | start_addr = SZ_2M; |
| 187 | } |
| 188 | |
| 189 | /* |
| 190 | * Put holes for reserved memory areas from mem_map. |
| 191 | * |
| 192 | * Only check for at most one overlap with one reserved memory |
| 193 | * area. |
| 194 | */ |
| 195 | while (tmp_mem_map->size) { |
| 196 | const phys_addr_t rsrv_start = tmp_mem_map->phys; |
| 197 | const phys_size_t rsrv_size = tmp_mem_map->size; |
| 198 | const phys_addr_t rsrv_end = rsrv_start + rsrv_size; |
| 199 | |
| 200 | /* |
| 201 | * DRAM memories are expected by Arm to be marked as |
| 202 | * Normal Write-back cacheable, Inner shareable[1], so |
| 203 | * let's filter on that to put holes in non-DRAM areas. |
| 204 | * |
| 205 | * [1] https://developer.arm.com/documentation/102376/0200/Cacheability-and-shareability-attributes |
| 206 | */ |
| 207 | const u64 dram_attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | |
| 208 | PTE_BLOCK_INNER_SHARE; |
| 209 | /* |
| 210 | * (AttrIndx | SH) in Lower Attributes of Block |
| 211 | * Descriptor[2]. |
| 212 | * [2] https://developer.arm.com/documentation/102376/0200/Describing-memory-in-AArch64 |
| 213 | */ |
| 214 | const u64 attrs_mask = PMD_ATTRINDX_MASK | GENMASK(9, 8); |
| 215 | |
| 216 | if ((tmp_mem_map->attrs & attrs_mask) == dram_attrs) { |
| 217 | tmp_mem_map++; |
| 218 | continue; |
| 219 | } |
| 220 | |
| 221 | /* |
| 222 | * If the start of the DDR_MEM tag is in a reserved |
| 223 | * memory area, move start address and resize. |
| 224 | */ |
| 225 | if (start_addr >= rsrv_start && start_addr < rsrv_end) { |
| 226 | if (rsrv_end - start_addr > size) { |
| 227 | debug("Would be negative memory size\n"); |
| 228 | return -EINVAL; |
| 229 | } |
| 230 | |
| 231 | size -= rsrv_end - start_addr; |
| 232 | start_addr = rsrv_end; |
| 233 | break; |
| 234 | } |
| 235 | |
| 236 | if (start_addr < rsrv_start) { |
| 237 | end_addr = start_addr + size; |
| 238 | |
| 239 | if (end_addr <= rsrv_start) { |
| 240 | tmp_mem_map++; |
| 241 | continue; |
| 242 | } |
| 243 | |
| 244 | /* |
| 245 | * If the memory area overlaps a reserved memory |
| 246 | * area with start address outside of reserved |
| 247 | * memory area and... |
| 248 | * |
| 249 | * ... ends in the middle of reserved memory |
| 250 | * area, resize. |
| 251 | */ |
| 252 | if (end_addr <= rsrv_end) { |
| 253 | size = rsrv_start - start_addr; |
| 254 | break; |
| 255 | } |
| 256 | |
| 257 | /* |
| 258 | * ... ends after the reserved memory area, |
| 259 | * split the region in two, one for before the |
| 260 | * reserved memory area and one for after. |
| 261 | */ |
| 262 | gd->bd->bi_dram[j].start = start_addr; |
| 263 | gd->bd->bi_dram[j].size = rsrv_start - start_addr; |
| 264 | |
| 265 | j++; |
| 266 | |
| 267 | size = end_addr - rsrv_end; |
| 268 | start_addr = rsrv_end; |
| 269 | |
| 270 | break; |
| 271 | } |
| 272 | |
| 273 | tmp_mem_map++; |
| 274 | } |
| 275 | |
| 276 | if (j > CONFIG_NR_DRAM_BANKS) { |
| 277 | debug("Too many banks, max allowed (%d)\n", |
| 278 | CONFIG_NR_DRAM_BANKS); |
| 279 | return -ENOMEM; |
| 280 | } |
| 281 | |
| 282 | gd->bd->bi_dram[j].start = start_addr; |
| 283 | gd->bd->bi_dram[j].size = size; |
| 284 | } |
| 285 | |
| 286 | return 0; |
| 287 | } |
| 288 | #endif |
| 289 | |
Kever Yang | dfc8a7d | 2019-07-22 20:02:02 +0800 | [diff] [blame] | 290 | int dram_init_banksize(void) |
| 291 | { |
Jonas Karlman | dd4d16f | 2023-02-07 17:27:11 +0000 | [diff] [blame] | 292 | size_t ram_top = (unsigned long)(gd->ram_size + CFG_SYS_SDRAM_BASE); |
| 293 | size_t top = min((unsigned long)ram_top, (unsigned long)(gd->ram_top)); |
Kever Yang | dfc8a7d | 2019-07-22 20:02:02 +0800 | [diff] [blame] | 294 | |
| 295 | #ifdef CONFIG_ARM64 |
Quentin Schulz | 6ba0686 | 2024-04-25 12:46:24 +0200 | [diff] [blame] | 296 | int ret = rockchip_dram_init_banksize(); |
| 297 | |
| 298 | if (!ret) |
| 299 | return ret; |
| 300 | |
| 301 | debug("Couldn't use ATAG (%d) to detect DDR layout, falling back...\n", |
| 302 | ret); |
| 303 | |
Kever Yang | dfc8a7d | 2019-07-22 20:02:02 +0800 | [diff] [blame] | 304 | /* Reserve 0x200000 for ATF bl31 */ |
| 305 | gd->bd->bi_dram[0].start = 0x200000; |
| 306 | gd->bd->bi_dram[0].size = top - gd->bd->bi_dram[0].start; |
Jonas Karlman | dd4d16f | 2023-02-07 17:27:11 +0000 | [diff] [blame] | 307 | |
| 308 | /* Add usable memory beyond the blob of space for peripheral near 4GB */ |
| 309 | if (ram_top > SZ_4G && top < SZ_4G) { |
| 310 | gd->bd->bi_dram[1].start = SZ_4G; |
| 311 | gd->bd->bi_dram[1].size = ram_top - gd->bd->bi_dram[1].start; |
| 312 | } |
Kever Yang | dfc8a7d | 2019-07-22 20:02:02 +0800 | [diff] [blame] | 313 | #else |
Patrick Delaunay | a7ca480 | 2021-09-02 11:56:16 +0200 | [diff] [blame] | 314 | #ifdef CONFIG_SPL_OPTEE_IMAGE |
Kever Yang | dfc8a7d | 2019-07-22 20:02:02 +0800 | [diff] [blame] | 315 | struct tos_parameter_t *tos_parameter; |
| 316 | |
Tom Rini | bb4dd96 | 2022-11-16 13:10:37 -0500 | [diff] [blame] | 317 | tos_parameter = (struct tos_parameter_t *)(CFG_SYS_SDRAM_BASE + |
Kever Yang | dfc8a7d | 2019-07-22 20:02:02 +0800 | [diff] [blame] | 318 | TRUST_PARAMETER_OFFSET); |
| 319 | |
| 320 | if (tos_parameter->tee_mem.flags == 1) { |
Tom Rini | bb4dd96 | 2022-11-16 13:10:37 -0500 | [diff] [blame] | 321 | gd->bd->bi_dram[0].start = CFG_SYS_SDRAM_BASE; |
Kever Yang | dfc8a7d | 2019-07-22 20:02:02 +0800 | [diff] [blame] | 322 | gd->bd->bi_dram[0].size = tos_parameter->tee_mem.phy_addr |
Tom Rini | bb4dd96 | 2022-11-16 13:10:37 -0500 | [diff] [blame] | 323 | - CFG_SYS_SDRAM_BASE; |
Kever Yang | dfc8a7d | 2019-07-22 20:02:02 +0800 | [diff] [blame] | 324 | gd->bd->bi_dram[1].start = tos_parameter->tee_mem.phy_addr + |
| 325 | tos_parameter->tee_mem.size; |
Alex Bee | e3a3494 | 2020-07-15 01:03:31 +0200 | [diff] [blame] | 326 | gd->bd->bi_dram[1].size = top - gd->bd->bi_dram[1].start; |
Kever Yang | dfc8a7d | 2019-07-22 20:02:02 +0800 | [diff] [blame] | 327 | } else { |
Tom Rini | bb4dd96 | 2022-11-16 13:10:37 -0500 | [diff] [blame] | 328 | gd->bd->bi_dram[0].start = CFG_SYS_SDRAM_BASE; |
Kever Yang | dfc8a7d | 2019-07-22 20:02:02 +0800 | [diff] [blame] | 329 | gd->bd->bi_dram[0].size = 0x8400000; |
| 330 | /* Reserve 32M for OPTEE with TA */ |
Tom Rini | bb4dd96 | 2022-11-16 13:10:37 -0500 | [diff] [blame] | 331 | gd->bd->bi_dram[1].start = CFG_SYS_SDRAM_BASE |
Kever Yang | dfc8a7d | 2019-07-22 20:02:02 +0800 | [diff] [blame] | 332 | + gd->bd->bi_dram[0].size + 0x2000000; |
Alex Bee | e3a3494 | 2020-07-15 01:03:31 +0200 | [diff] [blame] | 333 | gd->bd->bi_dram[1].size = top - gd->bd->bi_dram[1].start; |
Kever Yang | dfc8a7d | 2019-07-22 20:02:02 +0800 | [diff] [blame] | 334 | } |
| 335 | #else |
Tom Rini | bb4dd96 | 2022-11-16 13:10:37 -0500 | [diff] [blame] | 336 | gd->bd->bi_dram[0].start = CFG_SYS_SDRAM_BASE; |
Kever Yang | dfc8a7d | 2019-07-22 20:02:02 +0800 | [diff] [blame] | 337 | gd->bd->bi_dram[0].size = top - gd->bd->bi_dram[0].start; |
| 338 | #endif |
| 339 | #endif |
| 340 | |
| 341 | return 0; |
| 342 | } |
| 343 | |
Kever Yang | 5db9e67 | 2017-06-23 16:11:05 +0800 | [diff] [blame] | 344 | size_t rockchip_sdram_size(phys_addr_t reg) |
| 345 | { |
Kever Yang | 117585a | 2019-11-15 11:04:35 +0800 | [diff] [blame] | 346 | u32 rank, cs0_col, bk, cs0_row, cs1_row, bw, row_3_4; |
Kever Yang | 5db9e67 | 2017-06-23 16:11:05 +0800 | [diff] [blame] | 347 | size_t chipsize_mb = 0; |
| 348 | size_t size_mb = 0; |
| 349 | u32 ch; |
Kever Yang | 117585a | 2019-11-15 11:04:35 +0800 | [diff] [blame] | 350 | u32 cs1_col = 0; |
| 351 | u32 bg = 0; |
| 352 | u32 dbw, dram_type; |
Kever Yang | 4c0c6e4 | 2019-11-15 11:04:36 +0800 | [diff] [blame] | 353 | u32 sys_reg2 = readl(reg); |
Kever Yang | 117585a | 2019-11-15 11:04:35 +0800 | [diff] [blame] | 354 | u32 sys_reg3 = readl(reg + 4); |
Kever Yang | 4c0c6e4 | 2019-11-15 11:04:36 +0800 | [diff] [blame] | 355 | u32 ch_num = 1 + ((sys_reg2 >> SYS_REG_NUM_CH_SHIFT) |
Kever Yang | 5db9e67 | 2017-06-23 16:11:05 +0800 | [diff] [blame] | 356 | & SYS_REG_NUM_CH_MASK); |
Jonas Karlman | f570c25 | 2023-02-07 17:27:10 +0000 | [diff] [blame] | 357 | u32 version = (sys_reg3 >> SYS_REG_VERSION_SHIFT) & |
| 358 | SYS_REG_VERSION_MASK; |
Kever Yang | 5db9e67 | 2017-06-23 16:11:05 +0800 | [diff] [blame] | 359 | |
Kever Yang | 4c0c6e4 | 2019-11-15 11:04:36 +0800 | [diff] [blame] | 360 | dram_type = (sys_reg2 >> SYS_REG_DDRTYPE_SHIFT) & SYS_REG_DDRTYPE_MASK; |
Jonas Karlman | f570c25 | 2023-02-07 17:27:10 +0000 | [diff] [blame] | 361 | if (version >= 3) |
| 362 | dram_type |= ((sys_reg3 >> SYS_REG_EXTEND_DDRTYPE_SHIFT) & |
| 363 | SYS_REG_EXTEND_DDRTYPE_MASK) << 3; |
Kever Yang | 4c0c6e4 | 2019-11-15 11:04:36 +0800 | [diff] [blame] | 364 | debug("%s %x %x\n", __func__, (u32)reg, sys_reg2); |
Jonas Karlman | f570c25 | 2023-02-07 17:27:10 +0000 | [diff] [blame] | 365 | debug("%s %x %x\n", __func__, (u32)reg + 4, sys_reg3); |
Kever Yang | 5db9e67 | 2017-06-23 16:11:05 +0800 | [diff] [blame] | 366 | for (ch = 0; ch < ch_num; ch++) { |
Kever Yang | 4c0c6e4 | 2019-11-15 11:04:36 +0800 | [diff] [blame] | 367 | rank = 1 + (sys_reg2 >> SYS_REG_RANK_SHIFT(ch) & |
Kever Yang | 5db9e67 | 2017-06-23 16:11:05 +0800 | [diff] [blame] | 368 | SYS_REG_RANK_MASK); |
Kever Yang | 4c0c6e4 | 2019-11-15 11:04:36 +0800 | [diff] [blame] | 369 | cs0_col = 9 + (sys_reg2 >> SYS_REG_COL_SHIFT(ch) & |
Kever Yang | 117585a | 2019-11-15 11:04:35 +0800 | [diff] [blame] | 370 | SYS_REG_COL_MASK); |
| 371 | cs1_col = cs0_col; |
YouMin Chen | 618bddb | 2023-12-12 15:56:41 +0800 | [diff] [blame] | 372 | if (dram_type == LPDDR5) |
| 373 | /* LPDDR5: 0:8bank(bk=3), 1:16bank(bk=4) */ |
| 374 | bk = 3 + ((sys_reg2 >> SYS_REG_BK_SHIFT(ch)) & |
| 375 | SYS_REG_BK_MASK); |
| 376 | else |
| 377 | /* Other: 0:8bank(bk=3), 1:4bank(bk=2) */ |
| 378 | bk = 3 - ((sys_reg2 >> SYS_REG_BK_SHIFT(ch)) & |
| 379 | SYS_REG_BK_MASK); |
Jonas Karlman | f570c25 | 2023-02-07 17:27:10 +0000 | [diff] [blame] | 380 | if (version >= 2) { |
Kever Yang | 117585a | 2019-11-15 11:04:35 +0800 | [diff] [blame] | 381 | cs1_col = 9 + (sys_reg3 >> SYS_REG_CS1_COL_SHIFT(ch) & |
| 382 | SYS_REG_CS1_COL_MASK); |
| 383 | if (((sys_reg3 >> SYS_REG_EXTEND_CS0_ROW_SHIFT(ch) & |
Kever Yang | 4c0c6e4 | 2019-11-15 11:04:36 +0800 | [diff] [blame] | 384 | SYS_REG_EXTEND_CS0_ROW_MASK) << 2) + (sys_reg2 >> |
Kever Yang | 117585a | 2019-11-15 11:04:35 +0800 | [diff] [blame] | 385 | SYS_REG_CS0_ROW_SHIFT(ch) & |
| 386 | SYS_REG_CS0_ROW_MASK) == 7) |
| 387 | cs0_row = 12; |
| 388 | else |
Kever Yang | 4c0c6e4 | 2019-11-15 11:04:36 +0800 | [diff] [blame] | 389 | cs0_row = 13 + (sys_reg2 >> |
Kever Yang | 117585a | 2019-11-15 11:04:35 +0800 | [diff] [blame] | 390 | SYS_REG_CS0_ROW_SHIFT(ch) & |
| 391 | SYS_REG_CS0_ROW_MASK) + |
| 392 | ((sys_reg3 >> |
| 393 | SYS_REG_EXTEND_CS0_ROW_SHIFT(ch) & |
| 394 | SYS_REG_EXTEND_CS0_ROW_MASK) << 2); |
| 395 | if (((sys_reg3 >> SYS_REG_EXTEND_CS1_ROW_SHIFT(ch) & |
Kever Yang | 4c0c6e4 | 2019-11-15 11:04:36 +0800 | [diff] [blame] | 396 | SYS_REG_EXTEND_CS1_ROW_MASK) << 2) + (sys_reg2 >> |
Kever Yang | 117585a | 2019-11-15 11:04:35 +0800 | [diff] [blame] | 397 | SYS_REG_CS1_ROW_SHIFT(ch) & |
| 398 | SYS_REG_CS1_ROW_MASK) == 7) |
| 399 | cs1_row = 12; |
| 400 | else |
Kever Yang | 4c0c6e4 | 2019-11-15 11:04:36 +0800 | [diff] [blame] | 401 | cs1_row = 13 + (sys_reg2 >> |
Kever Yang | 117585a | 2019-11-15 11:04:35 +0800 | [diff] [blame] | 402 | SYS_REG_CS1_ROW_SHIFT(ch) & |
| 403 | SYS_REG_CS1_ROW_MASK) + |
| 404 | ((sys_reg3 >> |
| 405 | SYS_REG_EXTEND_CS1_ROW_SHIFT(ch) & |
| 406 | SYS_REG_EXTEND_CS1_ROW_MASK) << 2); |
| 407 | } else { |
Kever Yang | 4c0c6e4 | 2019-11-15 11:04:36 +0800 | [diff] [blame] | 408 | cs0_row = 13 + (sys_reg2 >> SYS_REG_CS0_ROW_SHIFT(ch) & |
Kever Yang | 5db9e67 | 2017-06-23 16:11:05 +0800 | [diff] [blame] | 409 | SYS_REG_CS0_ROW_MASK); |
Kever Yang | 4c0c6e4 | 2019-11-15 11:04:36 +0800 | [diff] [blame] | 410 | cs1_row = 13 + (sys_reg2 >> SYS_REG_CS1_ROW_SHIFT(ch) & |
Kever Yang | 5db9e67 | 2017-06-23 16:11:05 +0800 | [diff] [blame] | 411 | SYS_REG_CS1_ROW_MASK); |
Kever Yang | 117585a | 2019-11-15 11:04:35 +0800 | [diff] [blame] | 412 | } |
Kever Yang | 4c0c6e4 | 2019-11-15 11:04:36 +0800 | [diff] [blame] | 413 | bw = (2 >> ((sys_reg2 >> SYS_REG_BW_SHIFT(ch)) & |
Kever Yang | 5db9e67 | 2017-06-23 16:11:05 +0800 | [diff] [blame] | 414 | SYS_REG_BW_MASK)); |
Kever Yang | 4c0c6e4 | 2019-11-15 11:04:36 +0800 | [diff] [blame] | 415 | row_3_4 = sys_reg2 >> SYS_REG_ROW_3_4_SHIFT(ch) & |
Kever Yang | 5db9e67 | 2017-06-23 16:11:05 +0800 | [diff] [blame] | 416 | SYS_REG_ROW_3_4_MASK; |
Kever Yang | 117585a | 2019-11-15 11:04:35 +0800 | [diff] [blame] | 417 | if (dram_type == DDR4) { |
Kever Yang | 4c0c6e4 | 2019-11-15 11:04:36 +0800 | [diff] [blame] | 418 | dbw = (sys_reg2 >> SYS_REG_DBW_SHIFT(ch)) & |
Kever Yang | 117585a | 2019-11-15 11:04:35 +0800 | [diff] [blame] | 419 | SYS_REG_DBW_MASK; |
| 420 | bg = (dbw == 2) ? 2 : 1; |
| 421 | } |
| 422 | chipsize_mb = (1 << (cs0_row + cs0_col + bk + bg + bw - 20)); |
Kever Yang | 5db9e67 | 2017-06-23 16:11:05 +0800 | [diff] [blame] | 423 | |
| 424 | if (rank > 1) |
Kever Yang | 117585a | 2019-11-15 11:04:35 +0800 | [diff] [blame] | 425 | chipsize_mb += chipsize_mb >> ((cs0_row - cs1_row) + |
| 426 | (cs0_col - cs1_col)); |
Kever Yang | 5db9e67 | 2017-06-23 16:11:05 +0800 | [diff] [blame] | 427 | if (row_3_4) |
| 428 | chipsize_mb = chipsize_mb * 3 / 4; |
| 429 | size_mb += chipsize_mb; |
Kever Yang | 117585a | 2019-11-15 11:04:35 +0800 | [diff] [blame] | 430 | if (rank > 1) |
| 431 | debug("rank %d cs0_col %d cs1_col %d bk %d cs0_row %d\ |
| 432 | cs1_row %d bw %d row_3_4 %d\n", |
| 433 | rank, cs0_col, cs1_col, bk, cs0_row, |
| 434 | cs1_row, bw, row_3_4); |
| 435 | else |
| 436 | debug("rank %d cs0_col %d bk %d cs0_row %d\ |
| 437 | bw %d row_3_4 %d\n", |
| 438 | rank, cs0_col, bk, cs0_row, |
| 439 | bw, row_3_4); |
Kever Yang | 5db9e67 | 2017-06-23 16:11:05 +0800 | [diff] [blame] | 440 | } |
| 441 | |
Kever Yang | e10e906 | 2018-12-28 09:56:48 +0800 | [diff] [blame] | 442 | /* |
| 443 | * This is workaround for issue we can't get correct size for 4GB ram |
| 444 | * in 32bit system and available before we really need ram space |
| 445 | * out of 4GB, eg.enable ARM LAPE(rk3288 supports 8GB ram). |
| 446 | * The size of 4GB is '0x1 00000000', and this value will be truncated |
| 447 | * to 0 in 32bit system, and system can not get correct ram size. |
| 448 | * Rockchip SoCs reserve a blob of space for peripheral near 4GB, |
| 449 | * and we are now setting SDRAM_MAX_SIZE as max available space for |
| 450 | * ram in 4GB, so we can use this directly to workaround the issue. |
| 451 | * TODO: |
| 452 | * 1. update correct value for SDRAM_MAX_SIZE as what dram |
| 453 | * controller sees. |
| 454 | * 2. update board_get_usable_ram_top() and dram_init_banksize() |
| 455 | * to reserve memory for peripheral space after previous update. |
| 456 | */ |
Jonas Karlman | dd4d16f | 2023-02-07 17:27:11 +0000 | [diff] [blame] | 457 | if (!IS_ENABLED(CONFIG_ARM64) && size_mb > (SDRAM_MAX_SIZE >> 20)) |
Kever Yang | e10e906 | 2018-12-28 09:56:48 +0800 | [diff] [blame] | 458 | size_mb = (SDRAM_MAX_SIZE >> 20); |
| 459 | |
Kever Yang | 5db9e67 | 2017-06-23 16:11:05 +0800 | [diff] [blame] | 460 | return (size_t)size_mb << 20; |
| 461 | } |
| 462 | |
| 463 | int dram_init(void) |
| 464 | { |
| 465 | struct ram_info ram; |
| 466 | struct udevice *dev; |
| 467 | int ret; |
| 468 | |
| 469 | ret = uclass_get_device(UCLASS_RAM, 0, &dev); |
| 470 | if (ret) { |
| 471 | debug("DRAM init failed: %d\n", ret); |
| 472 | return ret; |
| 473 | } |
| 474 | ret = ram_get_info(dev, &ram); |
| 475 | if (ret) { |
| 476 | debug("Cannot get DRAM size: %d\n", ret); |
| 477 | return ret; |
| 478 | } |
| 479 | gd->ram_size = ram.size; |
| 480 | debug("SDRAM base=%lx, size=%lx\n", |
| 481 | (unsigned long)ram.base, (unsigned long)ram.size); |
| 482 | |
| 483 | return 0; |
| 484 | } |
| 485 | |
Heinrich Schuchardt | 51a9aac | 2023-08-12 20:16:58 +0200 | [diff] [blame] | 486 | phys_addr_t board_get_usable_ram_top(phys_size_t total_size) |
Kever Yang | 5db9e67 | 2017-06-23 16:11:05 +0800 | [diff] [blame] | 487 | { |
Tom Rini | bb4dd96 | 2022-11-16 13:10:37 -0500 | [diff] [blame] | 488 | unsigned long top = CFG_SYS_SDRAM_BASE + SDRAM_MAX_SIZE; |
Kever Yang | 5db9e67 | 2017-06-23 16:11:05 +0800 | [diff] [blame] | 489 | |
| 490 | return (gd->ram_top > top) ? top : gd->ram_top; |
| 491 | } |