blob: 734099652fd7b3a285fe5317f12ed00bc8484fae [file] [log] [blame]
Konstantin Porotchkinf69ec582018-06-07 18:31:14 +03001/*
2 * Copyright (C) 2018 Marvell International Ltd.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 * https://spdx.org/licenses
6 */
7
Konstantin Porotchkinf69ec582018-06-07 18:31:14 +03008#include <platform_def.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +00009
10#include <common/debug.h>
11#include <lib/mmio.h>
12
Konstantin Porotchkinf69ec582018-06-07 18:31:14 +030013#include <ddr_info.h>
Konstantin Porotchkinf69ec582018-06-07 18:31:14 +030014
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
37 * bellow:
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
77uint64_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}