| /* |
| * Copyright (C) 2018 Marvell International Ltd. |
| * |
| * SPDX-License-Identifier: BSD-3-Clause |
| * https://spdx.org/licenses |
| */ |
| |
| #include <platform_def.h> |
| |
| #include <common/debug.h> |
| #include <lib/mmio.h> |
| |
| #include <ddr_info.h> |
| |
| #define DRAM_CH0_MMAP_LOW_REG(iface, cs, base) \ |
| (base + DRAM_CH0_MMAP_LOW_OFFSET + (iface) * 0x10000 + (cs) * 0x8) |
| #define DRAM_CH0_MMAP_HIGH_REG(iface, cs, base) \ |
| (DRAM_CH0_MMAP_LOW_REG(iface, cs, base) + 4) |
| #define DRAM_CS_VALID_ENABLED_MASK 0x1 |
| #define DRAM_AREA_LENGTH_OFFS 16 |
| #define DRAM_AREA_LENGTH_MASK (0x1f << DRAM_AREA_LENGTH_OFFS) |
| #define DRAM_START_ADDRESS_L_OFFS 23 |
| #define DRAM_START_ADDRESS_L_MASK \ |
| (0x1ff << DRAM_START_ADDRESS_L_OFFS) |
| #define DRAM_START_ADDR_HTOL_OFFS 32 |
| |
| #define DRAM_MAX_CS_NUM 2 |
| |
| #define DRAM_CS_ENABLED(iface, cs, base) \ |
| (mmio_read_32(DRAM_CH0_MMAP_LOW_REG(iface, cs, base)) & \ |
| DRAM_CS_VALID_ENABLED_MASK) |
| #define GET_DRAM_REGION_SIZE_CODE(iface, cs, base) \ |
| (mmio_read_32(DRAM_CH0_MMAP_LOW_REG(iface, cs, base)) & \ |
| DRAM_AREA_LENGTH_MASK) >> DRAM_AREA_LENGTH_OFFS |
| |
| /* Mapping between DDR area length and real DDR size is specific and looks like |
| * below: |
| * 0 => 384 MB |
| * 1 => 768 MB |
| * 2 => 1536 MB |
| * 3 => 3 GB |
| * 4 => 6 GB |
| * |
| * 7 => 8 MB |
| * 8 => 16 MB |
| * 9 => 32 MB |
| * 10 => 64 MB |
| * 11 => 128 MB |
| * 12 => 256 MB |
| * 13 => 512 MB |
| * 14 => 1 GB |
| * 15 => 2 GB |
| * 16 => 4 GB |
| * 17 => 8 GB |
| * 18 => 16 GB |
| * 19 => 32 GB |
| * 20 => 64 GB |
| * 21 => 128 GB |
| * 22 => 256 GB |
| * 23 => 512 GB |
| * 24 => 1 TB |
| * 25 => 2 TB |
| * 26 => 4 TB |
| * |
| * to calculate real size we need to use two different formulas: |
| * -- GET_DRAM_REGION_SIZE_ODD for values 0-4 (DRAM_REGION_SIZE_ODD) |
| * -- GET_DRAM_REGION_SIZE_EVEN for values 7-26 (DRAM_REGION_SIZE_EVEN) |
| * using mentioned formulas we cover whole mapping between "Area length" value |
| * and real size (see above mapping). |
| */ |
| #define DRAM_REGION_SIZE_EVEN(C) (((C) >= 7) && ((C) <= 26)) |
| #define GET_DRAM_REGION_SIZE_EVEN(C) ((uint64_t)1 << ((C) + 16)) |
| #define DRAM_REGION_SIZE_ODD(C) ((C) <= 4) |
| #define GET_DRAM_REGION_SIZE_ODD(C) ((uint64_t)0x18000000 << (C)) |
| |
| |
| uint64_t mvebu_get_dram_size(uint64_t ap_base_addr) |
| { |
| uint64_t mem_size = 0; |
| uint8_t region_code; |
| uint8_t cs, iface; |
| |
| for (iface = 0; iface < DRAM_MAX_IFACE; iface++) { |
| for (cs = 0; cs < DRAM_MAX_CS_NUM; cs++) { |
| |
| /* Exit loop on first disabled DRAM CS */ |
| if (!DRAM_CS_ENABLED(iface, cs, ap_base_addr)) |
| break; |
| |
| /* Decode area length for current CS |
| * from register value |
| */ |
| region_code = |
| GET_DRAM_REGION_SIZE_CODE(iface, cs, |
| ap_base_addr); |
| |
| if (DRAM_REGION_SIZE_EVEN(region_code)) { |
| mem_size += |
| GET_DRAM_REGION_SIZE_EVEN(region_code); |
| } else if (DRAM_REGION_SIZE_ODD(region_code)) { |
| mem_size += |
| GET_DRAM_REGION_SIZE_ODD(region_code); |
| } else { |
| WARN("%s: Invalid mem region (0x%x) CS#%d\n", |
| __func__, region_code, cs); |
| return 0; |
| } |
| } |
| } |
| |
| return mem_size; |
| } |