14c425570SMasahiro Yamada /*
23e9952beSMasahiro Yamada  * Copyright (C) 2012-2015 Panasonic Corporation
33e9952beSMasahiro Yamada  * Copyright (C) 2015-2017 Socionext Inc.
43e9952beSMasahiro Yamada  *   Author: Masahiro Yamada <yamada.masahiro@socionext.com>
54c425570SMasahiro Yamada  *
64c425570SMasahiro Yamada  * SPDX-License-Identifier:	GPL-2.0+
74c425570SMasahiro Yamada  */
84c425570SMasahiro Yamada 
94c425570SMasahiro Yamada #include <common.h>
107b3a032dSMasahiro Yamada #include <fdtdec.h>
110f4ec05bSMasahiro Yamada #include <linux/errno.h>
123e9952beSMasahiro Yamada #include <linux/sizes.h>
13cf88affaSMasahiro Yamada 
1451ea5a06SMasahiro Yamada #include "init.h"
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_SLD3_ID,
293e9952beSMasahiro Yamada 		.sparse_ch1_base = 0xc0000000,
303e9952beSMasahiro Yamada 		/*
313e9952beSMasahiro Yamada 		 * In fact, SLD3 has DRAM ch2, but the memory regions for ch1
323e9952beSMasahiro Yamada 		 * and ch2 overlap, and host cannot get access to them at the
333e9952beSMasahiro Yamada 		 * same time.  Hide the ch2 from U-Boot.
343e9952beSMasahiro Yamada 		 */
353e9952beSMasahiro Yamada 	},
363e9952beSMasahiro Yamada 	{
373e9952beSMasahiro Yamada 		.soc_id = UNIPHIER_LD4_ID,
383e9952beSMasahiro Yamada 		.sparse_ch1_base = 0xc0000000,
393e9952beSMasahiro Yamada 	},
403e9952beSMasahiro Yamada 	{
413e9952beSMasahiro Yamada 		.soc_id = UNIPHIER_PRO4_ID,
423e9952beSMasahiro Yamada 		.sparse_ch1_base = 0xa0000000,
433e9952beSMasahiro Yamada 	},
443e9952beSMasahiro Yamada 	{
453e9952beSMasahiro Yamada 		.soc_id = UNIPHIER_SLD8_ID,
463e9952beSMasahiro Yamada 		.sparse_ch1_base = 0xc0000000,
473e9952beSMasahiro Yamada 	},
483e9952beSMasahiro Yamada 	{
493e9952beSMasahiro Yamada 		.soc_id = UNIPHIER_PRO5_ID,
503e9952beSMasahiro Yamada 		.sparse_ch1_base = 0xc0000000,
513e9952beSMasahiro Yamada 	},
523e9952beSMasahiro Yamada 	{
533e9952beSMasahiro Yamada 		.soc_id = UNIPHIER_PXS2_ID,
543e9952beSMasahiro Yamada 		.sparse_ch1_base = 0xc0000000,
553e9952beSMasahiro Yamada 		.have_ch2 = 1,
563e9952beSMasahiro Yamada 	},
573e9952beSMasahiro Yamada 	{
583e9952beSMasahiro Yamada 		.soc_id = UNIPHIER_LD6B_ID,
593e9952beSMasahiro Yamada 		.sparse_ch1_base = 0xc0000000,
603e9952beSMasahiro Yamada 		.have_ch2 = 1,
613e9952beSMasahiro Yamada 	},
623e9952beSMasahiro Yamada 	{
633e9952beSMasahiro Yamada 		.soc_id = UNIPHIER_LD11_ID,
643e9952beSMasahiro Yamada 		.sparse_ch1_base = 0xc0000000,
653e9952beSMasahiro Yamada 	},
663e9952beSMasahiro Yamada 	{
673e9952beSMasahiro Yamada 		.soc_id = UNIPHIER_LD20_ID,
683e9952beSMasahiro Yamada 		.sparse_ch1_base = 0xc0000000,
693e9952beSMasahiro Yamada 		.have_ch2 = 1,
703e9952beSMasahiro Yamada 	},
713e9952beSMasahiro Yamada 	{
723e9952beSMasahiro Yamada 		.soc_id = UNIPHIER_PXS3_ID,
733e9952beSMasahiro Yamada 		.sparse_ch1_base = 0xc0000000,
743e9952beSMasahiro Yamada 		.have_ch2 = 1,
753e9952beSMasahiro Yamada 	},
763e9952beSMasahiro Yamada };
773e9952beSMasahiro Yamada UNIPHIER_DEFINE_SOCDATA_FUNC(uniphier_get_memif_data, uniphier_memif_data)
78cf88affaSMasahiro Yamada 
793e9952beSMasahiro Yamada static int uniphier_memconf_decode(struct uniphier_dram_ch *dram_ch)
803e9952beSMasahiro Yamada {
813e9952beSMasahiro Yamada 	const struct uniphier_memif_data *data;
823e9952beSMasahiro Yamada 	unsigned long size;
833e9952beSMasahiro Yamada 	u32 val;
84cf88affaSMasahiro Yamada 
853e9952beSMasahiro Yamada 	data = uniphier_get_memif_data();
863e9952beSMasahiro Yamada 	if (!data) {
873e9952beSMasahiro Yamada 		pr_err("unsupported SoC\n");
883e9952beSMasahiro Yamada 		return -EINVAL;
893e9952beSMasahiro Yamada 	}
903e9952beSMasahiro Yamada 
913e9952beSMasahiro Yamada 	val = readl(SG_MEMCONF);
923e9952beSMasahiro Yamada 
933e9952beSMasahiro Yamada 	/* set up ch0 */
943e9952beSMasahiro Yamada 	dram_ch[0].base = CONFIG_SYS_SDRAM_BASE;
953e9952beSMasahiro Yamada 
963e9952beSMasahiro Yamada 	switch (val & SG_MEMCONF_CH0_SZ_MASK) {
973e9952beSMasahiro Yamada 	case SG_MEMCONF_CH0_SZ_64M:
983e9952beSMasahiro Yamada 		size = SZ_64M;
993e9952beSMasahiro Yamada 		break;
1003e9952beSMasahiro Yamada 	case SG_MEMCONF_CH0_SZ_128M:
1013e9952beSMasahiro Yamada 		size = SZ_128M;
1023e9952beSMasahiro Yamada 		break;
1033e9952beSMasahiro Yamada 	case SG_MEMCONF_CH0_SZ_256M:
1043e9952beSMasahiro Yamada 		size = SZ_256M;
1053e9952beSMasahiro Yamada 		break;
1063e9952beSMasahiro Yamada 	case SG_MEMCONF_CH0_SZ_512M:
1073e9952beSMasahiro Yamada 		size = SZ_512M;
1083e9952beSMasahiro Yamada 		break;
1093e9952beSMasahiro Yamada 	case SG_MEMCONF_CH0_SZ_1G:
1103e9952beSMasahiro Yamada 		size = SZ_1G;
1113e9952beSMasahiro Yamada 		break;
1123e9952beSMasahiro Yamada 	default:
113*0f5bf09cSMasahiro Yamada 		pr_err("error: invalid value is set to MEMCONF ch0 size\n");
1143e9952beSMasahiro Yamada 		return -EINVAL;
1153e9952beSMasahiro Yamada 	}
1163e9952beSMasahiro Yamada 
1173e9952beSMasahiro Yamada 	if ((val & SG_MEMCONF_CH0_NUM_MASK) == SG_MEMCONF_CH0_NUM_2)
1183e9952beSMasahiro Yamada 		size *= 2;
1193e9952beSMasahiro Yamada 
1203e9952beSMasahiro Yamada 	dram_ch[0].size = size;
1213e9952beSMasahiro Yamada 
1223e9952beSMasahiro Yamada 	/* set up ch1 */
1233e9952beSMasahiro Yamada 	dram_ch[1].base = dram_ch[0].base + size;
1243e9952beSMasahiro Yamada 
1253e9952beSMasahiro Yamada 	if (val & SG_MEMCONF_SPARSEMEM) {
1263e9952beSMasahiro Yamada 		if (dram_ch[1].base > data->sparse_ch1_base) {
1273e9952beSMasahiro Yamada 			pr_warn("Sparse mem is enabled, but ch0 and ch1 overlap\n");
1283e9952beSMasahiro Yamada 			pr_warn("Only ch0 is available\n");
1293e9952beSMasahiro Yamada 			dram_ch[1].base = 0;
1303e9952beSMasahiro Yamada 			return 0;
1313e9952beSMasahiro Yamada 		}
1323e9952beSMasahiro Yamada 
1333e9952beSMasahiro Yamada 		dram_ch[1].base = data->sparse_ch1_base;
1343e9952beSMasahiro Yamada 	}
1353e9952beSMasahiro Yamada 
1363e9952beSMasahiro Yamada 	switch (val & SG_MEMCONF_CH1_SZ_MASK) {
1373e9952beSMasahiro Yamada 	case SG_MEMCONF_CH1_SZ_64M:
1383e9952beSMasahiro Yamada 		size = SZ_64M;
1393e9952beSMasahiro Yamada 		break;
1403e9952beSMasahiro Yamada 	case SG_MEMCONF_CH1_SZ_128M:
1413e9952beSMasahiro Yamada 		size = SZ_128M;
1423e9952beSMasahiro Yamada 		break;
1433e9952beSMasahiro Yamada 	case SG_MEMCONF_CH1_SZ_256M:
1443e9952beSMasahiro Yamada 		size = SZ_256M;
1453e9952beSMasahiro Yamada 		break;
1463e9952beSMasahiro Yamada 	case SG_MEMCONF_CH1_SZ_512M:
1473e9952beSMasahiro Yamada 		size = SZ_512M;
1483e9952beSMasahiro Yamada 		break;
1493e9952beSMasahiro Yamada 	case SG_MEMCONF_CH1_SZ_1G:
1503e9952beSMasahiro Yamada 		size = SZ_1G;
1513e9952beSMasahiro Yamada 		break;
1523e9952beSMasahiro Yamada 	default:
153*0f5bf09cSMasahiro Yamada 		pr_err("error: invalid value is set to MEMCONF ch1 size\n");
1543e9952beSMasahiro Yamada 		return -EINVAL;
1553e9952beSMasahiro Yamada 	}
1563e9952beSMasahiro Yamada 
1573e9952beSMasahiro Yamada 	if ((val & SG_MEMCONF_CH1_NUM_MASK) == SG_MEMCONF_CH1_NUM_2)
1583e9952beSMasahiro Yamada 		size *= 2;
1593e9952beSMasahiro Yamada 
1603e9952beSMasahiro Yamada 	dram_ch[1].size = size;
1613e9952beSMasahiro Yamada 
162bed1624dSMasahiro Yamada 	if (!data->have_ch2 || val & SG_MEMCONF_CH2_DISABLE)
1633e9952beSMasahiro Yamada 		return 0;
1643e9952beSMasahiro Yamada 
1653e9952beSMasahiro Yamada 	/* set up ch2 */
1663e9952beSMasahiro Yamada 	dram_ch[2].base = dram_ch[1].base + size;
1673e9952beSMasahiro Yamada 
1683e9952beSMasahiro Yamada 	switch (val & SG_MEMCONF_CH2_SZ_MASK) {
1693e9952beSMasahiro Yamada 	case SG_MEMCONF_CH2_SZ_64M:
1703e9952beSMasahiro Yamada 		size = SZ_64M;
1713e9952beSMasahiro Yamada 		break;
1723e9952beSMasahiro Yamada 	case SG_MEMCONF_CH2_SZ_128M:
1733e9952beSMasahiro Yamada 		size = SZ_128M;
1743e9952beSMasahiro Yamada 		break;
1753e9952beSMasahiro Yamada 	case SG_MEMCONF_CH2_SZ_256M:
1763e9952beSMasahiro Yamada 		size = SZ_256M;
1773e9952beSMasahiro Yamada 		break;
1783e9952beSMasahiro Yamada 	case SG_MEMCONF_CH2_SZ_512M:
1793e9952beSMasahiro Yamada 		size = SZ_512M;
1803e9952beSMasahiro Yamada 		break;
1813e9952beSMasahiro Yamada 	case SG_MEMCONF_CH2_SZ_1G:
1823e9952beSMasahiro Yamada 		size = SZ_1G;
1833e9952beSMasahiro Yamada 		break;
1843e9952beSMasahiro Yamada 	default:
185*0f5bf09cSMasahiro Yamada 		pr_err("error: invalid value is set to MEMCONF ch2 size\n");
1863e9952beSMasahiro Yamada 		return -EINVAL;
1873e9952beSMasahiro Yamada 	}
1883e9952beSMasahiro Yamada 
1893e9952beSMasahiro Yamada 	if ((val & SG_MEMCONF_CH2_NUM_MASK) == SG_MEMCONF_CH2_NUM_2)
1903e9952beSMasahiro Yamada 		size *= 2;
1913e9952beSMasahiro Yamada 
1923e9952beSMasahiro Yamada 	dram_ch[2].size = size;
1933e9952beSMasahiro Yamada 
1943e9952beSMasahiro Yamada 	return 0;
195cf88affaSMasahiro Yamada }
1964c425570SMasahiro Yamada 
1974c425570SMasahiro Yamada int dram_init(void)
1984c425570SMasahiro Yamada {
1993e9952beSMasahiro Yamada 	struct uniphier_dram_ch dram_ch[UNIPHIER_MAX_NR_DRAM_CH] = {};
2003e9952beSMasahiro Yamada 	int ret, i;
201cf88affaSMasahiro Yamada 
2023e9952beSMasahiro Yamada 	gd->ram_size = 0;
2033e9952beSMasahiro Yamada 
2043e9952beSMasahiro Yamada 	ret = uniphier_memconf_decode(dram_ch);
2053e9952beSMasahiro Yamada 	if (ret)
2063e9952beSMasahiro Yamada 		return ret;
2073e9952beSMasahiro Yamada 
2083e9952beSMasahiro Yamada 	for (i = 0; i < ARRAY_SIZE(dram_ch); i++) {
2093e9952beSMasahiro Yamada 
2103e9952beSMasahiro Yamada 		if (!dram_ch[i].size)
2113e9952beSMasahiro Yamada 			break;
2123e9952beSMasahiro Yamada 
2133e9952beSMasahiro Yamada 		/*
2143e9952beSMasahiro Yamada 		 * U-Boot relocates itself to the tail of the memory region,
2153e9952beSMasahiro Yamada 		 * but it does not expect sparse memory.  We use the first
2163e9952beSMasahiro Yamada 		 * contiguous chunk here.
2173e9952beSMasahiro Yamada 		 */
2183e9952beSMasahiro Yamada 		if (i > 0 &&
2193e9952beSMasahiro Yamada 		    dram_ch[i - 1].base + dram_ch[i - 1].size < dram_ch[i].base)
2203e9952beSMasahiro Yamada 			break;
2213e9952beSMasahiro Yamada 
2223e9952beSMasahiro Yamada 		gd->ram_size += dram_ch[i].size;
223ac2a1030SMasahiro Yamada 	}
224ac2a1030SMasahiro Yamada 
2254c425570SMasahiro Yamada 	return 0;
2264c425570SMasahiro Yamada }
227cf88affaSMasahiro Yamada 
228cf88affaSMasahiro Yamada void dram_init_banksize(void)
229cf88affaSMasahiro Yamada {
2303e9952beSMasahiro Yamada 	struct uniphier_dram_ch dram_ch[UNIPHIER_MAX_NR_DRAM_CH] = {};
2313e9952beSMasahiro Yamada 	int i;
232cf88affaSMasahiro Yamada 
2333e9952beSMasahiro Yamada 	uniphier_memconf_decode(dram_ch);
234cf88affaSMasahiro Yamada 
2353e9952beSMasahiro Yamada 	for (i = 0; i < ARRAY_SIZE(dram_ch); i++) {
2363e9952beSMasahiro Yamada 		if (i >= ARRAY_SIZE(gd->bd->bi_dram))
2373e9952beSMasahiro Yamada 			break;
238cf88affaSMasahiro Yamada 
2393e9952beSMasahiro Yamada 		gd->bd->bi_dram[i].start = dram_ch[i].base;
2403e9952beSMasahiro Yamada 		gd->bd->bi_dram[i].size = dram_ch[i].size;
241cf88affaSMasahiro Yamada 	}
242cf88affaSMasahiro Yamada }
24351ea5a06SMasahiro Yamada 
24451ea5a06SMasahiro Yamada #ifdef CONFIG_OF_BOARD_SETUP
24551ea5a06SMasahiro Yamada /*
24651ea5a06SMasahiro Yamada  * The DRAM PHY requires 64 byte scratch area in each DRAM channel
24751ea5a06SMasahiro Yamada  * for its dynamic PHY training feature.
24851ea5a06SMasahiro Yamada  */
24951ea5a06SMasahiro Yamada int ft_board_setup(void *fdt, bd_t *bd)
25051ea5a06SMasahiro Yamada {
25151ea5a06SMasahiro Yamada 	unsigned long rsv_addr;
25251ea5a06SMasahiro Yamada 	const unsigned long rsv_size = 64;
253c995f3a3SMasahiro Yamada 	int i, ret;
25451ea5a06SMasahiro Yamada 
255e27d6c7dSMasahiro Yamada 	if (uniphier_get_soc_id() != UNIPHIER_LD20_ID)
25651ea5a06SMasahiro Yamada 		return 0;
25751ea5a06SMasahiro Yamada 
258c995f3a3SMasahiro Yamada 	for (i = 0; i < ARRAY_SIZE(gd->bd->bi_dram); i++) {
259c995f3a3SMasahiro Yamada 		rsv_addr = gd->bd->bi_dram[i].start + gd->bd->bi_dram[i].size;
26051ea5a06SMasahiro Yamada 		rsv_addr -= rsv_size;
26151ea5a06SMasahiro Yamada 
26251ea5a06SMasahiro Yamada 		ret = fdt_add_mem_rsv(fdt, rsv_addr, rsv_size);
26351ea5a06SMasahiro Yamada 		if (ret)
26451ea5a06SMasahiro Yamada 			return -ENOSPC;
26551ea5a06SMasahiro Yamada 
26651ea5a06SMasahiro Yamada 		printf("   Reserved memory region for DRAM PHY training: addr=%lx size=%lx\n",
26751ea5a06SMasahiro Yamada 		       rsv_addr, rsv_size);
26851ea5a06SMasahiro Yamada 	}
26951ea5a06SMasahiro Yamada 
27051ea5a06SMasahiro Yamada 	return 0;
27151ea5a06SMasahiro Yamada }
27251ea5a06SMasahiro Yamada #endif
273