1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
24c425570SMasahiro Yamada /*
33e9952beSMasahiro Yamada  * Copyright (C) 2012-2015 Panasonic Corporation
43e9952beSMasahiro Yamada  * Copyright (C) 2015-2017 Socionext Inc.
53e9952beSMasahiro Yamada  *   Author: Masahiro Yamada <yamada.masahiro@socionext.com>
64c425570SMasahiro Yamada  */
74c425570SMasahiro Yamada 
84c425570SMasahiro Yamada #include <common.h>
90f4ec05bSMasahiro Yamada #include <linux/errno.h>
10dd74b945SMasahiro Yamada #include <linux/kernel.h>
11dd74b945SMasahiro Yamada #include <linux/printk.h>
123e9952beSMasahiro Yamada #include <linux/sizes.h>
13dd74b945SMasahiro Yamada #include <asm/global_data.h>
14cf88affaSMasahiro Yamada 
153e9952beSMasahiro Yamada #include "sg-regs.h"
1651ea5a06SMasahiro Yamada #include "soc-info.h"
1751ea5a06SMasahiro Yamada 
18cf88affaSMasahiro Yamada DECLARE_GLOBAL_DATA_PTR;
19cf88affaSMasahiro Yamada 
203e9952beSMasahiro Yamada struct uniphier_memif_data {
213e9952beSMasahiro Yamada 	unsigned int soc_id;
223e9952beSMasahiro Yamada 	unsigned long sparse_ch1_base;
233e9952beSMasahiro Yamada 	int have_ch2;
243e9952beSMasahiro Yamada };
253e9952beSMasahiro Yamada 
263e9952beSMasahiro Yamada static const struct uniphier_memif_data uniphier_memif_data[] = {
27cf88affaSMasahiro Yamada 	{
283e9952beSMasahiro Yamada 		.soc_id = UNIPHIER_LD4_ID,
293e9952beSMasahiro Yamada 		.sparse_ch1_base = 0xc0000000,
303e9952beSMasahiro Yamada 	},
313e9952beSMasahiro Yamada 	{
323e9952beSMasahiro Yamada 		.soc_id = UNIPHIER_PRO4_ID,
333e9952beSMasahiro Yamada 		.sparse_ch1_base = 0xa0000000,
343e9952beSMasahiro Yamada 	},
353e9952beSMasahiro Yamada 	{
363e9952beSMasahiro Yamada 		.soc_id = UNIPHIER_SLD8_ID,
373e9952beSMasahiro Yamada 		.sparse_ch1_base = 0xc0000000,
383e9952beSMasahiro Yamada 	},
393e9952beSMasahiro Yamada 	{
403e9952beSMasahiro Yamada 		.soc_id = UNIPHIER_PRO5_ID,
413e9952beSMasahiro Yamada 		.sparse_ch1_base = 0xc0000000,
423e9952beSMasahiro Yamada 	},
433e9952beSMasahiro Yamada 	{
443e9952beSMasahiro Yamada 		.soc_id = UNIPHIER_PXS2_ID,
453e9952beSMasahiro Yamada 		.sparse_ch1_base = 0xc0000000,
463e9952beSMasahiro Yamada 		.have_ch2 = 1,
473e9952beSMasahiro Yamada 	},
483e9952beSMasahiro Yamada 	{
493e9952beSMasahiro Yamada 		.soc_id = UNIPHIER_LD6B_ID,
503e9952beSMasahiro Yamada 		.sparse_ch1_base = 0xc0000000,
513e9952beSMasahiro Yamada 		.have_ch2 = 1,
523e9952beSMasahiro Yamada 	},
533e9952beSMasahiro Yamada 	{
543e9952beSMasahiro Yamada 		.soc_id = UNIPHIER_LD11_ID,
553e9952beSMasahiro Yamada 		.sparse_ch1_base = 0xc0000000,
563e9952beSMasahiro Yamada 	},
573e9952beSMasahiro Yamada 	{
583e9952beSMasahiro Yamada 		.soc_id = UNIPHIER_LD20_ID,
593e9952beSMasahiro Yamada 		.sparse_ch1_base = 0xc0000000,
603e9952beSMasahiro Yamada 		.have_ch2 = 1,
613e9952beSMasahiro Yamada 	},
623e9952beSMasahiro Yamada 	{
633e9952beSMasahiro Yamada 		.soc_id = UNIPHIER_PXS3_ID,
643e9952beSMasahiro Yamada 		.sparse_ch1_base = 0xc0000000,
653e9952beSMasahiro Yamada 		.have_ch2 = 1,
663e9952beSMasahiro Yamada 	},
673e9952beSMasahiro Yamada };
683e9952beSMasahiro Yamada UNIPHIER_DEFINE_SOCDATA_FUNC(uniphier_get_memif_data, uniphier_memif_data)
69cf88affaSMasahiro Yamada 
7004cd4e72SMasahiro Yamada struct uniphier_dram_map {
7104cd4e72SMasahiro Yamada 	unsigned long base;
7204cd4e72SMasahiro Yamada 	unsigned long size;
7304cd4e72SMasahiro Yamada };
7404cd4e72SMasahiro Yamada 
uniphier_memconf_decode(struct uniphier_dram_map * dram_map)7504cd4e72SMasahiro Yamada static int uniphier_memconf_decode(struct uniphier_dram_map *dram_map)
763e9952beSMasahiro Yamada {
773e9952beSMasahiro Yamada 	const struct uniphier_memif_data *data;
783e9952beSMasahiro Yamada 	unsigned long size;
793e9952beSMasahiro Yamada 	u32 val;
80cf88affaSMasahiro Yamada 
813e9952beSMasahiro Yamada 	data = uniphier_get_memif_data();
823e9952beSMasahiro Yamada 	if (!data) {
833e9952beSMasahiro Yamada 		pr_err("unsupported SoC\n");
843e9952beSMasahiro Yamada 		return -EINVAL;
853e9952beSMasahiro Yamada 	}
863e9952beSMasahiro Yamada 
873e9952beSMasahiro Yamada 	val = readl(SG_MEMCONF);
883e9952beSMasahiro Yamada 
893e9952beSMasahiro Yamada 	/* set up ch0 */
9004cd4e72SMasahiro Yamada 	dram_map[0].base = CONFIG_SYS_SDRAM_BASE;
913e9952beSMasahiro Yamada 
923e9952beSMasahiro Yamada 	switch (val & SG_MEMCONF_CH0_SZ_MASK) {
933e9952beSMasahiro Yamada 	case SG_MEMCONF_CH0_SZ_64M:
943e9952beSMasahiro Yamada 		size = SZ_64M;
953e9952beSMasahiro Yamada 		break;
963e9952beSMasahiro Yamada 	case SG_MEMCONF_CH0_SZ_128M:
973e9952beSMasahiro Yamada 		size = SZ_128M;
983e9952beSMasahiro Yamada 		break;
993e9952beSMasahiro Yamada 	case SG_MEMCONF_CH0_SZ_256M:
1003e9952beSMasahiro Yamada 		size = SZ_256M;
1013e9952beSMasahiro Yamada 		break;
1023e9952beSMasahiro Yamada 	case SG_MEMCONF_CH0_SZ_512M:
1033e9952beSMasahiro Yamada 		size = SZ_512M;
1043e9952beSMasahiro Yamada 		break;
1053e9952beSMasahiro Yamada 	case SG_MEMCONF_CH0_SZ_1G:
1063e9952beSMasahiro Yamada 		size = SZ_1G;
1073e9952beSMasahiro Yamada 		break;
1083e9952beSMasahiro Yamada 	default:
1090f5bf09cSMasahiro Yamada 		pr_err("error: invalid value is set to MEMCONF ch0 size\n");
1103e9952beSMasahiro Yamada 		return -EINVAL;
1113e9952beSMasahiro Yamada 	}
1123e9952beSMasahiro Yamada 
1133e9952beSMasahiro Yamada 	if ((val & SG_MEMCONF_CH0_NUM_MASK) == SG_MEMCONF_CH0_NUM_2)
1143e9952beSMasahiro Yamada 		size *= 2;
1153e9952beSMasahiro Yamada 
11604cd4e72SMasahiro Yamada 	dram_map[0].size = size;
1173e9952beSMasahiro Yamada 
1183e9952beSMasahiro Yamada 	/* set up ch1 */
11904cd4e72SMasahiro Yamada 	dram_map[1].base = dram_map[0].base + size;
1203e9952beSMasahiro Yamada 
1213e9952beSMasahiro Yamada 	if (val & SG_MEMCONF_SPARSEMEM) {
12204cd4e72SMasahiro Yamada 		if (dram_map[1].base > data->sparse_ch1_base) {
1233e9952beSMasahiro Yamada 			pr_warn("Sparse mem is enabled, but ch0 and ch1 overlap\n");
1243e9952beSMasahiro Yamada 			pr_warn("Only ch0 is available\n");
12504cd4e72SMasahiro Yamada 			dram_map[1].base = 0;
1263e9952beSMasahiro Yamada 			return 0;
1273e9952beSMasahiro Yamada 		}
1283e9952beSMasahiro Yamada 
12904cd4e72SMasahiro Yamada 		dram_map[1].base = data->sparse_ch1_base;
1303e9952beSMasahiro Yamada 	}
1313e9952beSMasahiro Yamada 
1323e9952beSMasahiro Yamada 	switch (val & SG_MEMCONF_CH1_SZ_MASK) {
1333e9952beSMasahiro Yamada 	case SG_MEMCONF_CH1_SZ_64M:
1343e9952beSMasahiro Yamada 		size = SZ_64M;
1353e9952beSMasahiro Yamada 		break;
1363e9952beSMasahiro Yamada 	case SG_MEMCONF_CH1_SZ_128M:
1373e9952beSMasahiro Yamada 		size = SZ_128M;
1383e9952beSMasahiro Yamada 		break;
1393e9952beSMasahiro Yamada 	case SG_MEMCONF_CH1_SZ_256M:
1403e9952beSMasahiro Yamada 		size = SZ_256M;
1413e9952beSMasahiro Yamada 		break;
1423e9952beSMasahiro Yamada 	case SG_MEMCONF_CH1_SZ_512M:
1433e9952beSMasahiro Yamada 		size = SZ_512M;
1443e9952beSMasahiro Yamada 		break;
1453e9952beSMasahiro Yamada 	case SG_MEMCONF_CH1_SZ_1G:
1463e9952beSMasahiro Yamada 		size = SZ_1G;
1473e9952beSMasahiro Yamada 		break;
1483e9952beSMasahiro Yamada 	default:
1490f5bf09cSMasahiro Yamada 		pr_err("error: invalid value is set to MEMCONF ch1 size\n");
1503e9952beSMasahiro Yamada 		return -EINVAL;
1513e9952beSMasahiro Yamada 	}
1523e9952beSMasahiro Yamada 
1533e9952beSMasahiro Yamada 	if ((val & SG_MEMCONF_CH1_NUM_MASK) == SG_MEMCONF_CH1_NUM_2)
1543e9952beSMasahiro Yamada 		size *= 2;
1553e9952beSMasahiro Yamada 
15604cd4e72SMasahiro Yamada 	dram_map[1].size = size;
1573e9952beSMasahiro Yamada 
158bed1624dSMasahiro Yamada 	if (!data->have_ch2 || val & SG_MEMCONF_CH2_DISABLE)
1593e9952beSMasahiro Yamada 		return 0;
1603e9952beSMasahiro Yamada 
1613e9952beSMasahiro Yamada 	/* set up ch2 */
16204cd4e72SMasahiro Yamada 	dram_map[2].base = dram_map[1].base + size;
1633e9952beSMasahiro Yamada 
1643e9952beSMasahiro Yamada 	switch (val & SG_MEMCONF_CH2_SZ_MASK) {
1653e9952beSMasahiro Yamada 	case SG_MEMCONF_CH2_SZ_64M:
1663e9952beSMasahiro Yamada 		size = SZ_64M;
1673e9952beSMasahiro Yamada 		break;
1683e9952beSMasahiro Yamada 	case SG_MEMCONF_CH2_SZ_128M:
1693e9952beSMasahiro Yamada 		size = SZ_128M;
1703e9952beSMasahiro Yamada 		break;
1713e9952beSMasahiro Yamada 	case SG_MEMCONF_CH2_SZ_256M:
1723e9952beSMasahiro Yamada 		size = SZ_256M;
1733e9952beSMasahiro Yamada 		break;
1743e9952beSMasahiro Yamada 	case SG_MEMCONF_CH2_SZ_512M:
1753e9952beSMasahiro Yamada 		size = SZ_512M;
1763e9952beSMasahiro Yamada 		break;
1773e9952beSMasahiro Yamada 	case SG_MEMCONF_CH2_SZ_1G:
1783e9952beSMasahiro Yamada 		size = SZ_1G;
1793e9952beSMasahiro Yamada 		break;
1803e9952beSMasahiro Yamada 	default:
1810f5bf09cSMasahiro Yamada 		pr_err("error: invalid value is set to MEMCONF ch2 size\n");
1823e9952beSMasahiro Yamada 		return -EINVAL;
1833e9952beSMasahiro Yamada 	}
1843e9952beSMasahiro Yamada 
1853e9952beSMasahiro Yamada 	if ((val & SG_MEMCONF_CH2_NUM_MASK) == SG_MEMCONF_CH2_NUM_2)
1863e9952beSMasahiro Yamada 		size *= 2;
1873e9952beSMasahiro Yamada 
18804cd4e72SMasahiro Yamada 	dram_map[2].size = size;
1893e9952beSMasahiro Yamada 
1903e9952beSMasahiro Yamada 	return 0;
191cf88affaSMasahiro Yamada }
1924c425570SMasahiro Yamada 
dram_init(void)1934c425570SMasahiro Yamada int dram_init(void)
1944c425570SMasahiro Yamada {
19504cd4e72SMasahiro Yamada 	struct uniphier_dram_map dram_map[3] = {};
1963e9952beSMasahiro Yamada 	int ret, i;
197cf88affaSMasahiro Yamada 
1983e9952beSMasahiro Yamada 	gd->ram_size = 0;
1993e9952beSMasahiro Yamada 
20004cd4e72SMasahiro Yamada 	ret = uniphier_memconf_decode(dram_map);
2013e9952beSMasahiro Yamada 	if (ret)
2023e9952beSMasahiro Yamada 		return ret;
2033e9952beSMasahiro Yamada 
20404cd4e72SMasahiro Yamada 	for (i = 0; i < ARRAY_SIZE(dram_map); i++) {
205be893a5cSMasahiro Yamada 		unsigned long max_size;
2063e9952beSMasahiro Yamada 
20704cd4e72SMasahiro Yamada 		if (!dram_map[i].size)
2083e9952beSMasahiro Yamada 			break;
2093e9952beSMasahiro Yamada 
2103e9952beSMasahiro Yamada 		/*
2113e9952beSMasahiro Yamada 		 * U-Boot relocates itself to the tail of the memory region,
2123e9952beSMasahiro Yamada 		 * but it does not expect sparse memory.  We use the first
2133e9952beSMasahiro Yamada 		 * contiguous chunk here.
2143e9952beSMasahiro Yamada 		 */
21504cd4e72SMasahiro Yamada 		if (i > 0 && dram_map[i - 1].base + dram_map[i - 1].size <
21604cd4e72SMasahiro Yamada 							dram_map[i].base)
2173e9952beSMasahiro Yamada 			break;
2183e9952beSMasahiro Yamada 
219be893a5cSMasahiro Yamada 		/*
220be893a5cSMasahiro Yamada 		 * Do not use memory that exceeds 32bit address range.  U-Boot
221be893a5cSMasahiro Yamada 		 * relocates itself to the end of the effectively available RAM.
222be893a5cSMasahiro Yamada 		 * This could be a problem for DMA engines that do not support
223be893a5cSMasahiro Yamada 		 * 64bit address (SDMA of SDHCI, UniPhier AV-ether, etc.)
224be893a5cSMasahiro Yamada 		 */
225be893a5cSMasahiro Yamada 		if (dram_map[i].base >= 1ULL << 32)
226be893a5cSMasahiro Yamada 			break;
227be893a5cSMasahiro Yamada 
228be893a5cSMasahiro Yamada 		max_size = (1ULL << 32) - dram_map[i].base;
229be893a5cSMasahiro Yamada 
230be893a5cSMasahiro Yamada 		if (dram_map[i].size > max_size) {
231be893a5cSMasahiro Yamada 			gd->ram_size += max_size;
232be893a5cSMasahiro Yamada 			break;
233be893a5cSMasahiro Yamada 		}
234be893a5cSMasahiro Yamada 
23504cd4e72SMasahiro Yamada 		gd->ram_size += dram_map[i].size;
236ac2a1030SMasahiro Yamada 	}
237ac2a1030SMasahiro Yamada 
238a322eb9fSMasahiro Yamada 	/*
239a322eb9fSMasahiro Yamada 	 * LD20 uses the last 64 byte for each channel for dynamic
240a322eb9fSMasahiro Yamada 	 * DDR PHY training
241a322eb9fSMasahiro Yamada 	 */
242a322eb9fSMasahiro Yamada 	if (uniphier_get_soc_id() == UNIPHIER_LD20_ID)
243a322eb9fSMasahiro Yamada 		gd->ram_size -= 64;
244a322eb9fSMasahiro Yamada 
2454c425570SMasahiro Yamada 	return 0;
2464c425570SMasahiro Yamada }
247cf88affaSMasahiro Yamada 
dram_init_banksize(void)24876b00acaSSimon Glass int dram_init_banksize(void)
249cf88affaSMasahiro Yamada {
25004cd4e72SMasahiro Yamada 	struct uniphier_dram_map dram_map[3] = {};
2513e9952beSMasahiro Yamada 	int i;
252cf88affaSMasahiro Yamada 
25304cd4e72SMasahiro Yamada 	uniphier_memconf_decode(dram_map);
254cf88affaSMasahiro Yamada 
25504cd4e72SMasahiro Yamada 	for (i = 0; i < ARRAY_SIZE(dram_map); i++) {
2563e9952beSMasahiro Yamada 		if (i >= ARRAY_SIZE(gd->bd->bi_dram))
2573e9952beSMasahiro Yamada 			break;
258cf88affaSMasahiro Yamada 
25904cd4e72SMasahiro Yamada 		gd->bd->bi_dram[i].start = dram_map[i].base;
26004cd4e72SMasahiro Yamada 		gd->bd->bi_dram[i].size = dram_map[i].size;
261cf88affaSMasahiro Yamada 	}
26276b00acaSSimon Glass 
26376b00acaSSimon Glass 	return 0;
264cf88affaSMasahiro Yamada }
265