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>
10*1d21e1b9SMasahiro Yamada #include <fdt_support.h>
117b3a032dSMasahiro Yamada #include <fdtdec.h>
120f4ec05bSMasahiro Yamada #include <linux/errno.h>
133e9952beSMasahiro Yamada #include <linux/sizes.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++) {
2053e9952beSMasahiro Yamada
20604cd4e72SMasahiro Yamada if (!dram_map[i].size)
2073e9952beSMasahiro Yamada break;
2083e9952beSMasahiro Yamada
2093e9952beSMasahiro Yamada /*
2103e9952beSMasahiro Yamada * U-Boot relocates itself to the tail of the memory region,
2113e9952beSMasahiro Yamada * but it does not expect sparse memory. We use the first
2123e9952beSMasahiro Yamada * contiguous chunk here.
2133e9952beSMasahiro Yamada */
21404cd4e72SMasahiro Yamada if (i > 0 && dram_map[i - 1].base + dram_map[i - 1].size <
21504cd4e72SMasahiro Yamada dram_map[i].base)
2163e9952beSMasahiro Yamada break;
2173e9952beSMasahiro Yamada
21804cd4e72SMasahiro Yamada gd->ram_size += dram_map[i].size;
219ac2a1030SMasahiro Yamada }
220ac2a1030SMasahiro Yamada
2214c425570SMasahiro Yamada return 0;
2224c425570SMasahiro Yamada }
223cf88affaSMasahiro Yamada
dram_init_banksize(void)22476b00acaSSimon Glass int dram_init_banksize(void)
225cf88affaSMasahiro Yamada {
22604cd4e72SMasahiro Yamada struct uniphier_dram_map dram_map[3] = {};
2273e9952beSMasahiro Yamada int i;
228cf88affaSMasahiro Yamada
22904cd4e72SMasahiro Yamada uniphier_memconf_decode(dram_map);
230cf88affaSMasahiro Yamada
23104cd4e72SMasahiro Yamada for (i = 0; i < ARRAY_SIZE(dram_map); i++) {
2323e9952beSMasahiro Yamada if (i >= ARRAY_SIZE(gd->bd->bi_dram))
2333e9952beSMasahiro Yamada break;
234cf88affaSMasahiro Yamada
23504cd4e72SMasahiro Yamada gd->bd->bi_dram[i].start = dram_map[i].base;
23604cd4e72SMasahiro Yamada gd->bd->bi_dram[i].size = dram_map[i].size;
237cf88affaSMasahiro Yamada }
23876b00acaSSimon Glass
23976b00acaSSimon Glass return 0;
240cf88affaSMasahiro Yamada }
24151ea5a06SMasahiro Yamada
24251ea5a06SMasahiro Yamada #ifdef CONFIG_OF_BOARD_SETUP
24351ea5a06SMasahiro Yamada /*
24451ea5a06SMasahiro Yamada * The DRAM PHY requires 64 byte scratch area in each DRAM channel
24551ea5a06SMasahiro Yamada * for its dynamic PHY training feature.
24651ea5a06SMasahiro Yamada */
ft_board_setup(void * fdt,bd_t * bd)24751ea5a06SMasahiro Yamada int ft_board_setup(void *fdt, bd_t *bd)
24851ea5a06SMasahiro Yamada {
24951ea5a06SMasahiro Yamada unsigned long rsv_addr;
25051ea5a06SMasahiro Yamada const unsigned long rsv_size = 64;
251c995f3a3SMasahiro Yamada int i, ret;
25251ea5a06SMasahiro Yamada
253e27d6c7dSMasahiro Yamada if (uniphier_get_soc_id() != UNIPHIER_LD20_ID)
25451ea5a06SMasahiro Yamada return 0;
25551ea5a06SMasahiro Yamada
256c995f3a3SMasahiro Yamada for (i = 0; i < ARRAY_SIZE(gd->bd->bi_dram); i++) {
25787c3308cSMasahiro Yamada if (!gd->bd->bi_dram[i].size)
25887c3308cSMasahiro Yamada continue;
25987c3308cSMasahiro Yamada
260c995f3a3SMasahiro Yamada rsv_addr = gd->bd->bi_dram[i].start + gd->bd->bi_dram[i].size;
26151ea5a06SMasahiro Yamada rsv_addr -= rsv_size;
26251ea5a06SMasahiro Yamada
26351ea5a06SMasahiro Yamada ret = fdt_add_mem_rsv(fdt, rsv_addr, rsv_size);
26451ea5a06SMasahiro Yamada if (ret)
26551ea5a06SMasahiro Yamada return -ENOSPC;
26651ea5a06SMasahiro Yamada
26751ea5a06SMasahiro Yamada printf(" Reserved memory region for DRAM PHY training: addr=%lx size=%lx\n",
26851ea5a06SMasahiro Yamada rsv_addr, rsv_size);
26951ea5a06SMasahiro Yamada }
27051ea5a06SMasahiro Yamada
27151ea5a06SMasahiro Yamada return 0;
27251ea5a06SMasahiro Yamada }
27351ea5a06SMasahiro Yamada #endif
274