Konstantin Porotchkin | f69ec58 | 2018-06-07 18:31:14 +0300 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2018 Marvell International Ltd. |
| 3 | * |
| 4 | * SPDX-License-Identifier: BSD-3-Clause |
| 5 | * https://spdx.org/licenses |
| 6 | */ |
| 7 | |
Konstantin Porotchkin | f69ec58 | 2018-06-07 18:31:14 +0300 | [diff] [blame] | 8 | #include <platform_def.h> |
Antonio Nino Diaz | e0f9063 | 2018-12-14 00:18:21 +0000 | [diff] [blame] | 9 | |
| 10 | #include <common/debug.h> |
| 11 | #include <lib/mmio.h> |
| 12 | |
Konstantin Porotchkin | f69ec58 | 2018-06-07 18:31:14 +0300 | [diff] [blame] | 13 | #include <ddr_info.h> |
Konstantin Porotchkin | f69ec58 | 2018-06-07 18:31:14 +0300 | [diff] [blame] | 14 | |
| 15 | #define DRAM_CH0_MMAP_LOW_REG(iface, cs, base) \ |
| 16 | (base + DRAM_CH0_MMAP_LOW_OFFSET + (iface) * 0x10000 + (cs) * 0x8) |
| 17 | #define DRAM_CH0_MMAP_HIGH_REG(iface, cs, base) \ |
| 18 | (DRAM_CH0_MMAP_LOW_REG(iface, cs, base) + 4) |
| 19 | #define DRAM_CS_VALID_ENABLED_MASK 0x1 |
| 20 | #define DRAM_AREA_LENGTH_OFFS 16 |
| 21 | #define DRAM_AREA_LENGTH_MASK (0x1f << DRAM_AREA_LENGTH_OFFS) |
| 22 | #define DRAM_START_ADDRESS_L_OFFS 23 |
| 23 | #define DRAM_START_ADDRESS_L_MASK \ |
| 24 | (0x1ff << DRAM_START_ADDRESS_L_OFFS) |
| 25 | #define DRAM_START_ADDR_HTOL_OFFS 32 |
| 26 | |
| 27 | #define DRAM_MAX_CS_NUM 2 |
| 28 | |
| 29 | #define DRAM_CS_ENABLED(iface, cs, base) \ |
| 30 | (mmio_read_32(DRAM_CH0_MMAP_LOW_REG(iface, cs, base)) & \ |
| 31 | DRAM_CS_VALID_ENABLED_MASK) |
| 32 | #define GET_DRAM_REGION_SIZE_CODE(iface, cs, base) \ |
| 33 | (mmio_read_32(DRAM_CH0_MMAP_LOW_REG(iface, cs, base)) & \ |
| 34 | DRAM_AREA_LENGTH_MASK) >> DRAM_AREA_LENGTH_OFFS |
| 35 | |
| 36 | /* Mapping between DDR area length and real DDR size is specific and looks like |
Elyes Haouas | 2be03c0 | 2023-02-13 09:14:48 +0100 | [diff] [blame^] | 37 | * below: |
Konstantin Porotchkin | f69ec58 | 2018-06-07 18:31:14 +0300 | [diff] [blame] | 38 | * 0 => 384 MB |
| 39 | * 1 => 768 MB |
| 40 | * 2 => 1536 MB |
| 41 | * 3 => 3 GB |
| 42 | * 4 => 6 GB |
| 43 | * |
| 44 | * 7 => 8 MB |
| 45 | * 8 => 16 MB |
| 46 | * 9 => 32 MB |
| 47 | * 10 => 64 MB |
| 48 | * 11 => 128 MB |
| 49 | * 12 => 256 MB |
| 50 | * 13 => 512 MB |
| 51 | * 14 => 1 GB |
| 52 | * 15 => 2 GB |
| 53 | * 16 => 4 GB |
| 54 | * 17 => 8 GB |
| 55 | * 18 => 16 GB |
| 56 | * 19 => 32 GB |
| 57 | * 20 => 64 GB |
| 58 | * 21 => 128 GB |
| 59 | * 22 => 256 GB |
| 60 | * 23 => 512 GB |
| 61 | * 24 => 1 TB |
| 62 | * 25 => 2 TB |
| 63 | * 26 => 4 TB |
| 64 | * |
| 65 | * to calculate real size we need to use two different formulas: |
| 66 | * -- GET_DRAM_REGION_SIZE_ODD for values 0-4 (DRAM_REGION_SIZE_ODD) |
| 67 | * -- GET_DRAM_REGION_SIZE_EVEN for values 7-26 (DRAM_REGION_SIZE_EVEN) |
| 68 | * using mentioned formulas we cover whole mapping between "Area length" value |
| 69 | * and real size (see above mapping). |
| 70 | */ |
| 71 | #define DRAM_REGION_SIZE_EVEN(C) (((C) >= 7) && ((C) <= 26)) |
| 72 | #define GET_DRAM_REGION_SIZE_EVEN(C) ((uint64_t)1 << ((C) + 16)) |
| 73 | #define DRAM_REGION_SIZE_ODD(C) ((C) <= 4) |
| 74 | #define GET_DRAM_REGION_SIZE_ODD(C) ((uint64_t)0x18000000 << (C)) |
| 75 | |
| 76 | |
| 77 | uint64_t mvebu_get_dram_size(uint64_t ap_base_addr) |
| 78 | { |
| 79 | uint64_t mem_size = 0; |
| 80 | uint8_t region_code; |
| 81 | uint8_t cs, iface; |
| 82 | |
| 83 | for (iface = 0; iface < DRAM_MAX_IFACE; iface++) { |
| 84 | for (cs = 0; cs < DRAM_MAX_CS_NUM; cs++) { |
| 85 | |
| 86 | /* Exit loop on first disabled DRAM CS */ |
| 87 | if (!DRAM_CS_ENABLED(iface, cs, ap_base_addr)) |
| 88 | break; |
| 89 | |
| 90 | /* Decode area length for current CS |
| 91 | * from register value |
| 92 | */ |
| 93 | region_code = |
| 94 | GET_DRAM_REGION_SIZE_CODE(iface, cs, |
| 95 | ap_base_addr); |
| 96 | |
| 97 | if (DRAM_REGION_SIZE_EVEN(region_code)) { |
| 98 | mem_size += |
| 99 | GET_DRAM_REGION_SIZE_EVEN(region_code); |
| 100 | } else if (DRAM_REGION_SIZE_ODD(region_code)) { |
| 101 | mem_size += |
| 102 | GET_DRAM_REGION_SIZE_ODD(region_code); |
| 103 | } else { |
| 104 | WARN("%s: Invalid mem region (0x%x) CS#%d\n", |
| 105 | __func__, region_code, cs); |
| 106 | return 0; |
| 107 | } |
| 108 | } |
| 109 | } |
| 110 | |
| 111 | return mem_size; |
| 112 | } |