Commit 3e9952be23e1fdc8b576dfeed80e442d3045cd87

Authored by Masahiro Yamada
1 parent 773f5f63dc

ARM: uniphier: detect RAM size by decoding HW register instead of DT

U-Boot needs to set up available memory area(s) in dram_init() and
dram_init_banksize().  It is platform-dependent how to detect the
memory banks.  Currently, UniPhier adopts the memory banks _alleged_
by DT.  This is based on the assumption that users bind a correct DT
in their build process.

Come to think of it, the DRAM controller has already been set up
before U-Boot is entered (because U-Boot runs on DRAM).  So, the
DRAM controller setup register seems a more reliable source of any
information about DRAM stuff.  The DRAM banks are initialized by
preliminary firmware (SPL, ARM Trusted Firmware BL2, or whatever),
so this means the source of the reliability is shifted from Device
Tree to such early-stage firmware.  However, if the DRAM controller
is wrongly configured, the system will crash.  If your system is
running, the DRAM setup register is very likely to provide the
correct DRAM mapping.

Decode the SG_MEMCONF register to get the available DRAM banks.
The dram_init() and dram_init_banksize() need similar decoding.
It would be nice if dram_init_banksize() could reuse the outcome
of dram_init(), but global variables are unavailable at this stage
because the .bss section is available only after the relocation.
As a result, SG_MEMCONF must be checked twice, but a new helper
uniphier_memconf_decode() will help to avoid code duplication.

Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>

Showing 3 changed files with 207 additions and 50 deletions Side-by-side Diff

arch/arm/mach-uniphier/dram_init.c
1 1 /*
2   - * Copyright (C) 2012-2015 Masahiro Yamada <yamada.masahiro@socionext.com>
  2 + * Copyright (C) 2012-2015 Panasonic Corporation
  3 + * Copyright (C) 2015-2017 Socionext Inc.
  4 + * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
3 5 *
4 6 * SPDX-License-Identifier: GPL-2.0+
5 7 */
6 8  
7 9 #include <common.h>
8   -#include <libfdt.h>
9 10 #include <fdtdec.h>
10 11 #include <linux/errno.h>
  12 +#include <linux/sizes.h>
11 13  
12 14 #include "init.h"
  15 +#include "sg-regs.h"
13 16 #include "soc-info.h"
14 17  
15 18 DECLARE_GLOBAL_DATA_PTR;
16 19  
17   -static const void *get_memory_reg_prop(const void *fdt, int *lenp)
  20 +struct uniphier_memif_data {
  21 + unsigned int soc_id;
  22 + unsigned long sparse_ch1_base;
  23 + int have_ch2;
  24 +};
  25 +
  26 +static const struct uniphier_memif_data uniphier_memif_data[] = {
  27 + {
  28 + .soc_id = UNIPHIER_SLD3_ID,
  29 + .sparse_ch1_base = 0xc0000000,
  30 + /*
  31 + * In fact, SLD3 has DRAM ch2, but the memory regions for ch1
  32 + * and ch2 overlap, and host cannot get access to them at the
  33 + * same time. Hide the ch2 from U-Boot.
  34 + */
  35 + },
  36 + {
  37 + .soc_id = UNIPHIER_LD4_ID,
  38 + .sparse_ch1_base = 0xc0000000,
  39 + },
  40 + {
  41 + .soc_id = UNIPHIER_PRO4_ID,
  42 + .sparse_ch1_base = 0xa0000000,
  43 + },
  44 + {
  45 + .soc_id = UNIPHIER_SLD8_ID,
  46 + .sparse_ch1_base = 0xc0000000,
  47 + },
  48 + {
  49 + .soc_id = UNIPHIER_PRO5_ID,
  50 + .sparse_ch1_base = 0xc0000000,
  51 + },
  52 + {
  53 + .soc_id = UNIPHIER_PXS2_ID,
  54 + .sparse_ch1_base = 0xc0000000,
  55 + .have_ch2 = 1,
  56 + },
  57 + {
  58 + .soc_id = UNIPHIER_LD6B_ID,
  59 + .sparse_ch1_base = 0xc0000000,
  60 + .have_ch2 = 1,
  61 + },
  62 + {
  63 + .soc_id = UNIPHIER_LD11_ID,
  64 + .sparse_ch1_base = 0xc0000000,
  65 + },
  66 + {
  67 + .soc_id = UNIPHIER_LD20_ID,
  68 + .sparse_ch1_base = 0xc0000000,
  69 + .have_ch2 = 1,
  70 + },
  71 + {
  72 + .soc_id = UNIPHIER_PXS3_ID,
  73 + .sparse_ch1_base = 0xc0000000,
  74 + .have_ch2 = 1,
  75 + },
  76 +};
  77 +UNIPHIER_DEFINE_SOCDATA_FUNC(uniphier_get_memif_data, uniphier_memif_data)
  78 +
  79 +static int uniphier_memconf_decode(struct uniphier_dram_ch *dram_ch)
18 80 {
19   - int offset;
  81 + const struct uniphier_memif_data *data;
  82 + unsigned long size;
  83 + u32 val;
20 84  
21   - offset = fdt_path_offset(fdt, "/memory");
22   - if (offset < 0)
23   - return NULL;
  85 + data = uniphier_get_memif_data();
  86 + if (!data) {
  87 + pr_err("unsupported SoC\n");
  88 + return -EINVAL;
  89 + }
24 90  
25   - return fdt_getprop(fdt, offset, "reg", lenp);
26   -}
  91 + val = readl(SG_MEMCONF);
27 92  
28   -int dram_init(void)
29   -{
30   - const void *fdt = gd->fdt_blob;
31   - const fdt32_t *val;
32   - int ac, sc, len;
  93 + /* set up ch0 */
  94 + dram_ch[0].base = CONFIG_SYS_SDRAM_BASE;
33 95  
34   - ac = fdt_address_cells(fdt, 0);
35   - sc = fdt_size_cells(fdt, 0);
36   - if (ac < 0 || sc < 1 || sc > 2) {
37   - printf("invalid address/size cells\n");
  96 + switch (val & SG_MEMCONF_CH0_SZ_MASK) {
  97 + case SG_MEMCONF_CH0_SZ_64M:
  98 + size = SZ_64M;
  99 + break;
  100 + case SG_MEMCONF_CH0_SZ_128M:
  101 + size = SZ_128M;
  102 + break;
  103 + case SG_MEMCONF_CH0_SZ_256M:
  104 + size = SZ_256M;
  105 + break;
  106 + case SG_MEMCONF_CH0_SZ_512M:
  107 + size = SZ_512M;
  108 + break;
  109 + case SG_MEMCONF_CH0_SZ_1G:
  110 + size = SZ_1G;
  111 + break;
  112 + default:
  113 + pr_err("error: invald value is set to MEMCONF ch0 size\n");
38 114 return -EINVAL;
39 115 }
40 116  
41   - val = get_memory_reg_prop(fdt, &len);
42   - if (len / sizeof(*val) < ac + sc)
  117 + if ((val & SG_MEMCONF_CH0_NUM_MASK) == SG_MEMCONF_CH0_NUM_2)
  118 + size *= 2;
  119 +
  120 + dram_ch[0].size = size;
  121 +
  122 + /* set up ch1 */
  123 + dram_ch[1].base = dram_ch[0].base + size;
  124 +
  125 + if (val & SG_MEMCONF_SPARSEMEM) {
  126 + if (dram_ch[1].base > data->sparse_ch1_base) {
  127 + pr_warn("Sparse mem is enabled, but ch0 and ch1 overlap\n");
  128 + pr_warn("Only ch0 is available\n");
  129 + dram_ch[1].base = 0;
  130 + return 0;
  131 + }
  132 +
  133 + dram_ch[1].base = data->sparse_ch1_base;
  134 + }
  135 +
  136 + switch (val & SG_MEMCONF_CH1_SZ_MASK) {
  137 + case SG_MEMCONF_CH1_SZ_64M:
  138 + size = SZ_64M;
  139 + break;
  140 + case SG_MEMCONF_CH1_SZ_128M:
  141 + size = SZ_128M;
  142 + break;
  143 + case SG_MEMCONF_CH1_SZ_256M:
  144 + size = SZ_256M;
  145 + break;
  146 + case SG_MEMCONF_CH1_SZ_512M:
  147 + size = SZ_512M;
  148 + break;
  149 + case SG_MEMCONF_CH1_SZ_1G:
  150 + size = SZ_1G;
  151 + break;
  152 + default:
  153 + pr_err("error: invald value is set to MEMCONF ch1 size\n");
43 154 return -EINVAL;
  155 + }
44 156  
45   - val += ac;
  157 + if ((val & SG_MEMCONF_CH1_NUM_MASK) == SG_MEMCONF_CH1_NUM_2)
  158 + size *= 2;
46 159  
47   - gd->ram_size = fdtdec_get_number(val, sc);
  160 + dram_ch[1].size = size;
48 161  
49   - debug("DRAM size = %08lx\n", (unsigned long)gd->ram_size);
  162 + if (!data->have_ch2)
  163 + return 0;
50 164  
  165 + /* set up ch2 */
  166 + dram_ch[2].base = dram_ch[1].base + size;
  167 +
  168 + switch (val & SG_MEMCONF_CH2_SZ_MASK) {
  169 + case SG_MEMCONF_CH2_SZ_64M:
  170 + size = SZ_64M;
  171 + break;
  172 + case SG_MEMCONF_CH2_SZ_128M:
  173 + size = SZ_128M;
  174 + break;
  175 + case SG_MEMCONF_CH2_SZ_256M:
  176 + size = SZ_256M;
  177 + break;
  178 + case SG_MEMCONF_CH2_SZ_512M:
  179 + size = SZ_512M;
  180 + break;
  181 + case SG_MEMCONF_CH2_SZ_1G:
  182 + size = SZ_1G;
  183 + break;
  184 + default:
  185 + pr_err("error: invald value is set to MEMCONF ch2 size\n");
  186 + return -EINVAL;
  187 + }
  188 +
  189 + if ((val & SG_MEMCONF_CH2_NUM_MASK) == SG_MEMCONF_CH2_NUM_2)
  190 + size *= 2;
  191 +
  192 + dram_ch[2].size = size;
  193 +
51 194 return 0;
52 195 }
53 196  
54   -void dram_init_banksize(void)
  197 +int dram_init(void)
55 198 {
56   - const void *fdt = gd->fdt_blob;
57   - const fdt32_t *val;
58   - int ac, sc, cells, len, i;
  199 + struct uniphier_dram_ch dram_ch[UNIPHIER_MAX_NR_DRAM_CH] = {};
  200 + int ret, i;
59 201  
60   - val = get_memory_reg_prop(fdt, &len);
61   - if (len < 0)
62   - return;
  202 + gd->ram_size = 0;
63 203  
64   - ac = fdt_address_cells(fdt, 0);
65   - sc = fdt_size_cells(fdt, 0);
66   - if (ac < 1 || sc > 2 || sc < 1 || sc > 2) {
67   - printf("invalid address/size cells\n");
68   - return;
  204 + ret = uniphier_memconf_decode(dram_ch);
  205 + if (ret)
  206 + return ret;
  207 +
  208 + for (i = 0; i < ARRAY_SIZE(dram_ch); i++) {
  209 +
  210 + if (!dram_ch[i].size)
  211 + break;
  212 +
  213 + /*
  214 + * U-Boot relocates itself to the tail of the memory region,
  215 + * but it does not expect sparse memory. We use the first
  216 + * contiguous chunk here.
  217 + */
  218 + if (i > 0 &&
  219 + dram_ch[i - 1].base + dram_ch[i - 1].size < dram_ch[i].base)
  220 + break;
  221 +
  222 + gd->ram_size += dram_ch[i].size;
69 223 }
70 224  
71   - cells = ac + sc;
  225 + return 0;
  226 +}
72 227  
73   - len /= sizeof(*val);
  228 +void dram_init_banksize(void)
  229 +{
  230 + struct uniphier_dram_ch dram_ch[UNIPHIER_MAX_NR_DRAM_CH] = {};
  231 + int i;
74 232  
75   - for (i = 0; i < CONFIG_NR_DRAM_BANKS && len >= cells;
76   - i++, len -= cells) {
77   - gd->bd->bi_dram[i].start = fdtdec_get_number(val, ac);
78   - val += ac;
79   - gd->bd->bi_dram[i].size = fdtdec_get_number(val, sc);
80   - val += sc;
  233 + uniphier_memconf_decode(dram_ch);
81 234  
82   - debug("DRAM bank %d: start = %08lx, size = %08lx\n",
83   - i, (unsigned long)gd->bd->bi_dram[i].start,
84   - (unsigned long)gd->bd->bi_dram[i].size);
  235 + for (i = 0; i < ARRAY_SIZE(dram_ch); i++) {
  236 + if (i >= ARRAY_SIZE(gd->bd->bi_dram))
  237 + break;
  238 +
  239 + gd->bd->bi_dram[i].start = dram_ch[i].base;
  240 + gd->bd->bi_dram[i].size = dram_ch[i].size;
85 241 }
86 242 }
87 243  
arch/arm/mach-uniphier/init.h
... ... @@ -124,6 +124,7 @@
124 124 void uniphier_smp_kick_all_cpus(void);
125 125 void cci500_init(int nr_slaves);
126 126  
  127 +#define pr_warn(fmt, args...) printf(fmt, ##args)
127 128 #define pr_err(fmt, args...) printf(fmt, ##args)
128 129  
129 130 #endif /* __MACH_INIT_H */
include/configs/uniphier.h
... ... @@ -236,7 +236,7 @@
236 236 #define CONFIG_SYS_BOOTMAPSZ 0x20000000
237 237  
238 238 #define CONFIG_SYS_SDRAM_BASE 0x80000000
239   -#define CONFIG_NR_DRAM_BANKS 2
  239 +#define CONFIG_NR_DRAM_BANKS 3
240 240 /* for LD20; the last 64 byte is used for dynamic DDR PHY training */
241 241 #define CONFIG_SYS_MEM_TOP_HIDE 64
242 242