1 /* 2 * Copyright (C) 2012-2015 Panasonic Corporation 3 * Copyright (C) 2015-2017 Socionext Inc. 4 * Author: Masahiro Yamada <yamada.masahiro@socionext.com> 5 * 6 * SPDX-License-Identifier: GPL-2.0+ 7 */ 8 9 #include <common.h> 10 #include <fdt_support.h> 11 #include <fdtdec.h> 12 #include <linux/errno.h> 13 #include <linux/sizes.h> 14 15 #include "sg-regs.h" 16 #include "soc-info.h" 17 18 #define pr_warn(fmt, args...) printf(fmt, ##args) 19 #define pr_err(fmt, args...) printf(fmt, ##args) 20 21 DECLARE_GLOBAL_DATA_PTR; 22 23 struct uniphier_memif_data { 24 unsigned int soc_id; 25 unsigned long sparse_ch1_base; 26 int have_ch2; 27 }; 28 29 static const struct uniphier_memif_data uniphier_memif_data[] = { 30 { 31 .soc_id = UNIPHIER_SLD3_ID, 32 .sparse_ch1_base = 0xc0000000, 33 /* 34 * In fact, SLD3 has DRAM ch2, but the memory regions for ch1 35 * and ch2 overlap, and host cannot get access to them at the 36 * same time. Hide the ch2 from U-Boot. 37 */ 38 }, 39 { 40 .soc_id = UNIPHIER_LD4_ID, 41 .sparse_ch1_base = 0xc0000000, 42 }, 43 { 44 .soc_id = UNIPHIER_PRO4_ID, 45 .sparse_ch1_base = 0xa0000000, 46 }, 47 { 48 .soc_id = UNIPHIER_SLD8_ID, 49 .sparse_ch1_base = 0xc0000000, 50 }, 51 { 52 .soc_id = UNIPHIER_PRO5_ID, 53 .sparse_ch1_base = 0xc0000000, 54 }, 55 { 56 .soc_id = UNIPHIER_PXS2_ID, 57 .sparse_ch1_base = 0xc0000000, 58 .have_ch2 = 1, 59 }, 60 { 61 .soc_id = UNIPHIER_LD6B_ID, 62 .sparse_ch1_base = 0xc0000000, 63 .have_ch2 = 1, 64 }, 65 { 66 .soc_id = UNIPHIER_LD11_ID, 67 .sparse_ch1_base = 0xc0000000, 68 }, 69 { 70 .soc_id = UNIPHIER_LD20_ID, 71 .sparse_ch1_base = 0xc0000000, 72 .have_ch2 = 1, 73 }, 74 { 75 .soc_id = UNIPHIER_PXS3_ID, 76 .sparse_ch1_base = 0xc0000000, 77 .have_ch2 = 1, 78 }, 79 }; 80 UNIPHIER_DEFINE_SOCDATA_FUNC(uniphier_get_memif_data, uniphier_memif_data) 81 82 struct uniphier_dram_map { 83 unsigned long base; 84 unsigned long size; 85 }; 86 87 static int uniphier_memconf_decode(struct uniphier_dram_map *dram_map) 88 { 89 const struct uniphier_memif_data *data; 90 unsigned long size; 91 u32 val; 92 93 data = uniphier_get_memif_data(); 94 if (!data) { 95 pr_err("unsupported SoC\n"); 96 return -EINVAL; 97 } 98 99 val = readl(SG_MEMCONF); 100 101 /* set up ch0 */ 102 dram_map[0].base = CONFIG_SYS_SDRAM_BASE; 103 104 switch (val & SG_MEMCONF_CH0_SZ_MASK) { 105 case SG_MEMCONF_CH0_SZ_64M: 106 size = SZ_64M; 107 break; 108 case SG_MEMCONF_CH0_SZ_128M: 109 size = SZ_128M; 110 break; 111 case SG_MEMCONF_CH0_SZ_256M: 112 size = SZ_256M; 113 break; 114 case SG_MEMCONF_CH0_SZ_512M: 115 size = SZ_512M; 116 break; 117 case SG_MEMCONF_CH0_SZ_1G: 118 size = SZ_1G; 119 break; 120 default: 121 pr_err("error: invalid value is set to MEMCONF ch0 size\n"); 122 return -EINVAL; 123 } 124 125 if ((val & SG_MEMCONF_CH0_NUM_MASK) == SG_MEMCONF_CH0_NUM_2) 126 size *= 2; 127 128 dram_map[0].size = size; 129 130 /* set up ch1 */ 131 dram_map[1].base = dram_map[0].base + size; 132 133 if (val & SG_MEMCONF_SPARSEMEM) { 134 if (dram_map[1].base > data->sparse_ch1_base) { 135 pr_warn("Sparse mem is enabled, but ch0 and ch1 overlap\n"); 136 pr_warn("Only ch0 is available\n"); 137 dram_map[1].base = 0; 138 return 0; 139 } 140 141 dram_map[1].base = data->sparse_ch1_base; 142 } 143 144 switch (val & SG_MEMCONF_CH1_SZ_MASK) { 145 case SG_MEMCONF_CH1_SZ_64M: 146 size = SZ_64M; 147 break; 148 case SG_MEMCONF_CH1_SZ_128M: 149 size = SZ_128M; 150 break; 151 case SG_MEMCONF_CH1_SZ_256M: 152 size = SZ_256M; 153 break; 154 case SG_MEMCONF_CH1_SZ_512M: 155 size = SZ_512M; 156 break; 157 case SG_MEMCONF_CH1_SZ_1G: 158 size = SZ_1G; 159 break; 160 default: 161 pr_err("error: invalid value is set to MEMCONF ch1 size\n"); 162 return -EINVAL; 163 } 164 165 if ((val & SG_MEMCONF_CH1_NUM_MASK) == SG_MEMCONF_CH1_NUM_2) 166 size *= 2; 167 168 dram_map[1].size = size; 169 170 if (!data->have_ch2 || val & SG_MEMCONF_CH2_DISABLE) 171 return 0; 172 173 /* set up ch2 */ 174 dram_map[2].base = dram_map[1].base + size; 175 176 switch (val & SG_MEMCONF_CH2_SZ_MASK) { 177 case SG_MEMCONF_CH2_SZ_64M: 178 size = SZ_64M; 179 break; 180 case SG_MEMCONF_CH2_SZ_128M: 181 size = SZ_128M; 182 break; 183 case SG_MEMCONF_CH2_SZ_256M: 184 size = SZ_256M; 185 break; 186 case SG_MEMCONF_CH2_SZ_512M: 187 size = SZ_512M; 188 break; 189 case SG_MEMCONF_CH2_SZ_1G: 190 size = SZ_1G; 191 break; 192 default: 193 pr_err("error: invalid value is set to MEMCONF ch2 size\n"); 194 return -EINVAL; 195 } 196 197 if ((val & SG_MEMCONF_CH2_NUM_MASK) == SG_MEMCONF_CH2_NUM_2) 198 size *= 2; 199 200 dram_map[2].size = size; 201 202 return 0; 203 } 204 205 int dram_init(void) 206 { 207 struct uniphier_dram_map dram_map[3] = {}; 208 int ret, i; 209 210 gd->ram_size = 0; 211 212 ret = uniphier_memconf_decode(dram_map); 213 if (ret) 214 return ret; 215 216 for (i = 0; i < ARRAY_SIZE(dram_map); i++) { 217 218 if (!dram_map[i].size) 219 break; 220 221 /* 222 * U-Boot relocates itself to the tail of the memory region, 223 * but it does not expect sparse memory. We use the first 224 * contiguous chunk here. 225 */ 226 if (i > 0 && dram_map[i - 1].base + dram_map[i - 1].size < 227 dram_map[i].base) 228 break; 229 230 gd->ram_size += dram_map[i].size; 231 } 232 233 return 0; 234 } 235 236 int dram_init_banksize(void) 237 { 238 struct uniphier_dram_map dram_map[3] = {}; 239 int i; 240 241 uniphier_memconf_decode(dram_map); 242 243 for (i = 0; i < ARRAY_SIZE(dram_map); i++) { 244 if (i >= ARRAY_SIZE(gd->bd->bi_dram)) 245 break; 246 247 gd->bd->bi_dram[i].start = dram_map[i].base; 248 gd->bd->bi_dram[i].size = dram_map[i].size; 249 } 250 251 return 0; 252 } 253 254 #ifdef CONFIG_OF_BOARD_SETUP 255 /* 256 * The DRAM PHY requires 64 byte scratch area in each DRAM channel 257 * for its dynamic PHY training feature. 258 */ 259 int ft_board_setup(void *fdt, bd_t *bd) 260 { 261 unsigned long rsv_addr; 262 const unsigned long rsv_size = 64; 263 int i, ret; 264 265 if (uniphier_get_soc_id() != UNIPHIER_LD20_ID) 266 return 0; 267 268 for (i = 0; i < ARRAY_SIZE(gd->bd->bi_dram); i++) { 269 if (!gd->bd->bi_dram[i].size) 270 continue; 271 272 rsv_addr = gd->bd->bi_dram[i].start + gd->bd->bi_dram[i].size; 273 rsv_addr -= rsv_size; 274 275 ret = fdt_add_mem_rsv(fdt, rsv_addr, rsv_size); 276 if (ret) 277 return -ENOSPC; 278 279 printf(" Reserved memory region for DRAM PHY training: addr=%lx size=%lx\n", 280 rsv_addr, rsv_size); 281 } 282 283 return 0; 284 } 285 #endif 286