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