X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=arch%2Farm%2Fmach-uniphier%2Fdram_init.c;h=7f2753190c233372e21c9f9da81ee9fc1b6a6453;hb=60c7facfc965af6ff8ea14ee26c9d49cd2d0ec22;hp=ef0e2e8f54c5ca89cc0d101ca229a4b9a5df8b3f;hpb=9f69ab86d0592d528a0372f01fa23684291243fa;p=oweals%2Fu-boot.git diff --git a/arch/arm/mach-uniphier/dram_init.c b/arch/arm/mach-uniphier/dram_init.c index ef0e2e8f54..7f2753190c 100644 --- a/arch/arm/mach-uniphier/dram_init.c +++ b/arch/arm/mach-uniphier/dram_init.c @@ -1,83 +1,304 @@ +// SPDX-License-Identifier: GPL-2.0+ /* - * Copyright (C) 2012-2015 Masahiro Yamada - * - * SPDX-License-Identifier: GPL-2.0+ + * Copyright (C) 2012-2015 Panasonic Corporation + * Copyright (C) 2015-2017 Socionext Inc. + * Author: Masahiro Yamada */ -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "init.h" +#include "sg-regs.h" +#include "soc-info.h" DECLARE_GLOBAL_DATA_PTR; -static const void *get_memory_reg_prop(const void *fdt, int *lenp) +struct uniphier_dram_map { + unsigned long base; + unsigned long size; +}; + +static int uniphier_memconf_decode(struct uniphier_dram_map *dram_map, + unsigned long sparse_ch1_base, bool have_ch2) { - int offset; + unsigned long size; + u32 val; - offset = fdt_path_offset(fdt, "/memory"); - if (offset < 0) - return NULL; + val = readl(sg_base + SG_MEMCONF); - return fdt_getprop(fdt, offset, "reg", lenp); -} + /* set up ch0 */ + dram_map[0].base = 0x80000000; -int dram_init(void) -{ - const void *fdt = gd->fdt_blob; - const fdt32_t *val; - int ac, sc, len; - - ac = fdt_address_cells(fdt, 0); - sc = fdt_size_cells(fdt, 0); - if (ac < 0 || sc < 1 || sc > 2) { - printf("invalid address/size cells\n"); + switch (val & SG_MEMCONF_CH0_SZ_MASK) { + case SG_MEMCONF_CH0_SZ_64M: + size = SZ_64M; + break; + case SG_MEMCONF_CH0_SZ_128M: + size = SZ_128M; + break; + case SG_MEMCONF_CH0_SZ_256M: + size = SZ_256M; + break; + case SG_MEMCONF_CH0_SZ_512M: + size = SZ_512M; + break; + case SG_MEMCONF_CH0_SZ_1G: + size = SZ_1G; + break; + default: + pr_err("error: invalid value is set to MEMCONF ch0 size\n"); return -EINVAL; } - val = get_memory_reg_prop(fdt, &len); - if (len / sizeof(*val) < ac + sc) + if ((val & SG_MEMCONF_CH0_NUM_MASK) == SG_MEMCONF_CH0_NUM_2) + size *= 2; + + dram_map[0].size = size; + + /* set up ch1 */ + dram_map[1].base = dram_map[0].base + size; + + if (val & SG_MEMCONF_SPARSEMEM) { + if (dram_map[1].base > sparse_ch1_base) { + pr_warn("Sparse mem is enabled, but ch0 and ch1 overlap\n"); + pr_warn("Only ch0 is available\n"); + dram_map[1].base = 0; + return 0; + } + + dram_map[1].base = sparse_ch1_base; + } + + switch (val & SG_MEMCONF_CH1_SZ_MASK) { + case SG_MEMCONF_CH1_SZ_64M: + size = SZ_64M; + break; + case SG_MEMCONF_CH1_SZ_128M: + size = SZ_128M; + break; + case SG_MEMCONF_CH1_SZ_256M: + size = SZ_256M; + break; + case SG_MEMCONF_CH1_SZ_512M: + size = SZ_512M; + break; + case SG_MEMCONF_CH1_SZ_1G: + size = SZ_1G; + break; + default: + pr_err("error: invalid value is set to MEMCONF ch1 size\n"); return -EINVAL; + } - val += ac; + if ((val & SG_MEMCONF_CH1_NUM_MASK) == SG_MEMCONF_CH1_NUM_2) + size *= 2; - gd->ram_size = fdtdec_get_number(val, sc); + dram_map[1].size = size; - debug("DRAM size = %08lx\n", (unsigned long)gd->ram_size); + if (!have_ch2 || val & SG_MEMCONF_CH2_DISABLE) + return 0; + + /* set up ch2 */ + dram_map[2].base = dram_map[1].base + size; + + switch (val & SG_MEMCONF_CH2_SZ_MASK) { + case SG_MEMCONF_CH2_SZ_64M: + size = SZ_64M; + break; + case SG_MEMCONF_CH2_SZ_128M: + size = SZ_128M; + break; + case SG_MEMCONF_CH2_SZ_256M: + size = SZ_256M; + break; + case SG_MEMCONF_CH2_SZ_512M: + size = SZ_512M; + break; + case SG_MEMCONF_CH2_SZ_1G: + size = SZ_1G; + break; + default: + pr_err("error: invalid value is set to MEMCONF ch2 size\n"); + return -EINVAL; + } + + if ((val & SG_MEMCONF_CH2_NUM_MASK) == SG_MEMCONF_CH2_NUM_2) + size *= 2; + + dram_map[2].size = size; return 0; } -void dram_init_banksize(void) +static int uniphier_ld4_dram_map_get(struct uniphier_dram_map dram_map[]) +{ + return uniphier_memconf_decode(dram_map, 0xc0000000, false); +} + +static int uniphier_pro4_dram_map_get(struct uniphier_dram_map dram_map[]) +{ + return uniphier_memconf_decode(dram_map, 0xa0000000, false); +} + +static int uniphier_pxs2_dram_map_get(struct uniphier_dram_map dram_map[]) +{ + return uniphier_memconf_decode(dram_map, 0xc0000000, true); +} + +struct uniphier_dram_init_data { + unsigned int soc_id; + int (*dram_map_get)(struct uniphier_dram_map dram_map[]); +}; + +static const struct uniphier_dram_init_data uniphier_dram_init_data[] = { + { + .soc_id = UNIPHIER_LD4_ID, + .dram_map_get = uniphier_ld4_dram_map_get, + }, + { + .soc_id = UNIPHIER_PRO4_ID, + .dram_map_get = uniphier_pro4_dram_map_get, + }, + { + .soc_id = UNIPHIER_SLD8_ID, + .dram_map_get = uniphier_ld4_dram_map_get, + }, + { + .soc_id = UNIPHIER_PRO5_ID, + .dram_map_get = uniphier_ld4_dram_map_get, + }, + { + .soc_id = UNIPHIER_PXS2_ID, + .dram_map_get = uniphier_pxs2_dram_map_get, + }, + { + .soc_id = UNIPHIER_LD6B_ID, + .dram_map_get = uniphier_pxs2_dram_map_get, + }, + { + .soc_id = UNIPHIER_LD11_ID, + .dram_map_get = uniphier_ld4_dram_map_get, + }, + { + .soc_id = UNIPHIER_LD20_ID, + .dram_map_get = uniphier_pxs2_dram_map_get, + }, + { + .soc_id = UNIPHIER_PXS3_ID, + .dram_map_get = uniphier_pxs2_dram_map_get, + }, +}; +UNIPHIER_DEFINE_SOCDATA_FUNC(uniphier_get_dram_init_data, + uniphier_dram_init_data) + +static int uniphier_dram_map_get(struct uniphier_dram_map *dram_map) { - const void *fdt = gd->fdt_blob; - const fdt32_t *val; - int ac, sc, cells, len, i; - - val = get_memory_reg_prop(fdt, &len); - if (len < 0) - return; - - ac = fdt_address_cells(fdt, 0); - sc = fdt_size_cells(fdt, 0); - if (ac < 1 || sc > 2 || sc < 1 || sc > 2) { - printf("invalid address/size cells\n"); - return; + const struct uniphier_dram_init_data *data; + + data = uniphier_get_dram_init_data(); + if (!data) { + pr_err("unsupported SoC\n"); + return -ENOTSUPP; + } + + return data->dram_map_get(dram_map); +} + +int dram_init(void) +{ + struct uniphier_dram_map dram_map[3] = {}; + bool valid_bank_found = false; + unsigned long prev_top; + int ret, i; + + gd->ram_size = 0; + + ret = uniphier_dram_map_get(dram_map); + if (ret) + return ret; + + for (i = 0; i < ARRAY_SIZE(dram_map); i++) { + unsigned long max_size; + + if (!dram_map[i].size) + continue; + + /* + * U-Boot relocates itself to the tail of the memory region, + * but it does not expect sparse memory. We use the first + * contiguous chunk here. + */ + if (valid_bank_found && prev_top < dram_map[i].base) + break; + + /* + * Do not use memory that exceeds 32bit address range. U-Boot + * relocates itself to the end of the effectively available RAM. + * This could be a problem for DMA engines that do not support + * 64bit address (SDMA of SDHCI, UniPhier AV-ether, etc.) + */ + if (dram_map[i].base >= 1ULL << 32) + break; + + max_size = (1ULL << 32) - dram_map[i].base; + + gd->ram_size = min(dram_map[i].size, max_size); + + if (!valid_bank_found) + gd->ram_base = dram_map[i].base; + + prev_top = dram_map[i].base + dram_map[i].size; + valid_bank_found = true; } - cells = ac + sc; + /* + * LD20 uses the last 64 byte for each channel for dynamic + * DDR PHY training + */ + if (uniphier_get_soc_id() == UNIPHIER_LD20_ID) + gd->ram_size -= 64; + + return 0; +} + +int dram_init_banksize(void) +{ + struct uniphier_dram_map dram_map[3] = {}; + unsigned long base, top; + bool valid_bank_found = false; + int ret, i; + + ret = uniphier_dram_map_get(dram_map); + if (ret) + return ret; - len /= sizeof(*val); + for (i = 0; i < ARRAY_SIZE(dram_map); i++) { + if (i < ARRAY_SIZE(gd->bd->bi_dram)) { + gd->bd->bi_dram[i].start = dram_map[i].base; + gd->bd->bi_dram[i].size = dram_map[i].size; + } - for (i = 0; i < CONFIG_NR_DRAM_BANKS && len >= cells; - i++, len -= cells) { - gd->bd->bi_dram[i].start = fdtdec_get_number(val, ac); - val += ac; - gd->bd->bi_dram[i].size = fdtdec_get_number(val, sc); - val += sc; + if (!dram_map[i].size) + continue; - debug("DRAM bank %d: start = %08lx, size = %08lx\n", - i, (unsigned long)gd->bd->bi_dram[i].start, - (unsigned long)gd->bd->bi_dram[i].size); + if (!valid_bank_found) + base = dram_map[i].base; + top = dram_map[i].base + dram_map[i].size; + valid_bank_found = true; } + + if (!valid_bank_found) + return -EINVAL; + + /* map all the DRAM regions */ + uniphier_mem_map_init(base, top - base); + + return 0; }