[PATCH v1 u-boot-marvell 2/5] arm64: mvebu: a37xx: improve code determining memory info structures
Stefan Roese
sr at denx.de
Tue Apr 14 10:02:32 CEST 2020
On 08.04.20 19:25, Marek Behún wrote:
> Currently on Armada-37xx the mem_map structure is statically defined to
> map first 2 GB of memory as RAM region, and system registers and PCIe
> region device region.
>
> This is insufficient for when there is more RAM or when for example the
> PCIe windows is mapped to another address by the CPU Address Decoder.
> In the case when the board has 4 GB RAM, on some boards the ARM Trusted
> Firmware can move the PCIe window to another address, in order to
> maximize possible usable RAM.
>
> Also the dram_init and dram_init_banksize looks for information in
> device-tree, and therefore different device trees are needed for boards
> with different RAM sizes.
>
> Therefore we add code that looks at how the ARM Trusted Firmware has
> configured the CPU Address Decoder windows, and then we update the
> mem_map structure and compute gd->ram_size and gd->bd->bi_dram bank
> base addresses and sizes accordingly.
>
> Signed-off-by: Marek Behún <marek.behun at nic.cz>
Reviewed-by: Stefan Roese <sr at denx.de>
Thanks,
Stefan
> ---
> arch/arm/mach-mvebu/arm64-common.c | 5 +
> arch/arm/mach-mvebu/armada3700/cpu.c | 252 ++++++++++++++++++++++---
> arch/arm/mach-mvebu/include/mach/cpu.h | 4 +
> 3 files changed, 235 insertions(+), 26 deletions(-)
>
> diff --git a/arch/arm/mach-mvebu/arm64-common.c b/arch/arm/mach-mvebu/arm64-common.c
> index 244ea49d8a..34cc0479a8 100644
> --- a/arch/arm/mach-mvebu/arm64-common.c
> +++ b/arch/arm/mach-mvebu/arm64-common.c
> @@ -49,6 +49,8 @@ __weak int dram_init_banksize(void)
> {
> if (CONFIG_IS_ENABLED(ARMADA_8K))
> return a8k_dram_init_banksize();
> + else if (CONFIG_IS_ENABLED(ARMADA_3700))
> + return a3700_dram_init_banksize();
> else
> return fdtdec_setup_memory_banksize();
> }
> @@ -61,6 +63,9 @@ __weak int dram_init(void)
> return 0;
> }
>
> + if (CONFIG_IS_ENABLED(ARMADA_3700))
> + return a3700_dram_init();
> +
> if (fdtdec_setup_mem_size_base() != 0)
> return -EINVAL;
>
> diff --git a/arch/arm/mach-mvebu/armada3700/cpu.c b/arch/arm/mach-mvebu/armada3700/cpu.c
> index c83268181b..959a909d8a 100644
> --- a/arch/arm/mach-mvebu/armada3700/cpu.c
> +++ b/arch/arm/mach-mvebu/armada3700/cpu.c
> @@ -1,6 +1,7 @@
> // SPDX-License-Identifier: GPL-2.0+
> /*
> * Copyright (C) 2016 Stefan Roese <sr at denx.de>
> + * Copyright (C) 2020 Marek Behun <marek.behun at nic.cz>
> */
>
> #include <common.h>
> @@ -13,6 +14,7 @@
> #include <asm/arch/cpu.h>
> #include <asm/arch/soc.h>
> #include <asm/armv8/mmu.h>
> +#include <sort.h>
>
> /* Armada 3700 */
> #define MVEBU_GPIO_NB_REG_BASE (MVEBU_REGISTER(0x13800))
> @@ -26,39 +28,237 @@
> #define MVEBU_NB_WARM_RST_REG (MVEBU_GPIO_NB_REG_BASE + 0x40)
> #define MVEBU_NB_WARM_RST_MAGIC_NUM 0x1d1e
>
> -static struct mm_region mvebu_mem_map[] = {
> - {
> - /* RAM */
> - .phys = 0x0UL,
> - .virt = 0x0UL,
> - .size = 0x80000000UL,
> - .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
> - PTE_BLOCK_INNER_SHARE
> - },
> +/* Armada 3700 CPU Address Decoder registers */
> +#define MVEBU_CPU_DEC_WIN_REG_BASE (size_t)(MVEBU_REGISTER(0xcf00))
> +#define MVEBU_CPU_DEC_WIN_CTRL(w) \
> + (MVEBU_CPU_DEC_WIN_REG_BASE + ((w) << 4))
> +#define MVEBU_CPU_DEC_WIN_CTRL_EN BIT(0)
> +#define MVEBU_CPU_DEC_WIN_CTRL_TGT_MASK 0xf
> +#define MVEBU_CPU_DEC_WIN_CTRL_TGT_OFFS 4
> +#define MVEBU_CPU_DEC_WIN_CTRL_TGT_DRAM 0
> +#define MVEBU_CPU_DEC_WIN_CTRL_TGT_PCIE 2
> +#define MVEBU_CPU_DEC_WIN_SIZE(w) (MVEBU_CPU_DEC_WIN_CTRL(w) + 0x4)
> +#define MVEBU_CPU_DEC_WIN_BASE(w) (MVEBU_CPU_DEC_WIN_CTRL(w) + 0x8)
> +#define MVEBU_CPU_DEC_WIN_REMAP(w) (MVEBU_CPU_DEC_WIN_CTRL(w) + 0xc)
> +#define MVEBU_CPU_DEC_WIN_GRANULARITY 16
> +#define MVEBU_CPU_DEC_WINS 5
> +
> +#define MAX_MEM_MAP_REGIONS (MVEBU_CPU_DEC_WINS + 2)
> +
> +#define A3700_PTE_BLOCK_NORMAL \
> + (PTE_BLOCK_MEMTYPE(MT_NORMAL) | PTE_BLOCK_INNER_SHARE)
> +#define A3700_PTE_BLOCK_DEVICE \
> + (PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | PTE_BLOCK_NON_SHARE)
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +static struct mm_region mvebu_mem_map[MAX_MEM_MAP_REGIONS] = {
> {
> - /* SRAM, MMIO regions */
> - .phys = 0xd0000000UL,
> - .virt = 0xd0000000UL,
> + /*
> + * SRAM, MMIO regions
> + * Don't remove this, a3700_build_mem_map needs it.
> + */
> + .phys = SOC_REGS_PHY_BASE,
> + .virt = SOC_REGS_PHY_BASE,
> .size = 0x02000000UL, /* 32MiB internal registers */
> - .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
> - PTE_BLOCK_NON_SHARE
> - },
> - {
> - /* PCI regions */
> - .phys = 0xe8000000UL,
> - .virt = 0xe8000000UL,
> - .size = 0x02000000UL, /* 32MiB master PCI space */
> - .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
> - PTE_BLOCK_NON_SHARE
> + .attrs = A3700_PTE_BLOCK_DEVICE
> },
> - {
> - /* List terminator */
> - 0,
> - }
> };
>
> struct mm_region *mem_map = mvebu_mem_map;
>
> +static int get_cpu_dec_win(int win, u32 *tgt, u32 *base, u32 *size)
> +{
> + u32 reg;
> +
> + reg = readl(MVEBU_CPU_DEC_WIN_CTRL(win));
> + if (!(reg & MVEBU_CPU_DEC_WIN_CTRL_EN))
> + return -1;
> +
> + if (tgt) {
> + reg >>= MVEBU_CPU_DEC_WIN_CTRL_TGT_OFFS;
> + reg &= MVEBU_CPU_DEC_WIN_CTRL_TGT_MASK;
> + *tgt = reg;
> + }
> +
> + if (base) {
> + reg = readl(MVEBU_CPU_DEC_WIN_BASE(win));
> + *base = reg << MVEBU_CPU_DEC_WIN_GRANULARITY;
> + }
> +
> + if (size) {
> + /*
> + * Window size is encoded as the number of 1s from LSB to MSB,
> + * followed by 0s. The number of 1s specifies the size in 64 KiB
> + * granularity.
> + */
> + reg = readl(MVEBU_CPU_DEC_WIN_SIZE(win));
> + *size = ((reg + 1) << MVEBU_CPU_DEC_WIN_GRANULARITY);
> + }
> +
> + return 0;
> +}
> +
> +/*
> + * Builds mem_map according to CPU Address Decoder settings, which were set by
> + * the TIMH image on the Cortex-M3 secure processor, or by ARM Trusted Firmware
> + */
> +static void build_mem_map(void)
> +{
> + int win, region;
> +
> + region = 1;
> + for (win = 0; win < MVEBU_CPU_DEC_WINS; ++win) {
> + u32 base, tgt, size;
> + u64 attrs;
> +
> + /* skip disabled windows */
> + if (get_cpu_dec_win(win, &tgt, &base, &size))
> + continue;
> +
> + if (tgt == MVEBU_CPU_DEC_WIN_CTRL_TGT_DRAM)
> + attrs = A3700_PTE_BLOCK_NORMAL;
> + else if (tgt == MVEBU_CPU_DEC_WIN_CTRL_TGT_PCIE)
> + attrs = A3700_PTE_BLOCK_DEVICE;
> + else
> + /* skip windows with other targets */
> + continue;
> +
> + mvebu_mem_map[region].phys = base;
> + mvebu_mem_map[region].virt = base;
> + mvebu_mem_map[region].size = size;
> + mvebu_mem_map[region].attrs = attrs;
> + ++region;
> + }
> +
> + /* add list terminator */
> + mvebu_mem_map[region].size = 0;
> + mvebu_mem_map[region].attrs = 0;
> +}
> +
> +void enable_caches(void)
> +{
> + build_mem_map();
> +
> + icache_enable();
> + dcache_enable();
> +}
> +
> +int a3700_dram_init(void)
> +{
> + int win;
> +
> + gd->ram_size = 0;
> + for (win = 0; win < MVEBU_CPU_DEC_WINS; ++win) {
> + u32 base, tgt, size;
> +
> + /* skip disabled windows */
> + if (get_cpu_dec_win(win, &tgt, &base, &size))
> + continue;
> +
> + /* skip non-DRAM windows */
> + if (tgt != MVEBU_CPU_DEC_WIN_CTRL_TGT_DRAM)
> + continue;
> +
> + /*
> + * It is possible that one image was built for boards with
> + * different RAM sizes, for example 512 MiB and 1 GiB.
> + * We therefore try to determine the actual RAM size in the
> + * window with get_ram_size.
> + */
> + gd->ram_size += get_ram_size((void *)(size_t)base, size);
> + }
> +
> + return 0;
> +}
> +
> +struct a3700_dram_window {
> + size_t base, size;
> +};
> +
> +static int dram_win_cmp(const void *a, const void *b)
> +{
> + size_t ab, bb;
> +
> + ab = ((const struct a3700_dram_window *)a)->base;
> + bb = ((const struct a3700_dram_window *)b)->base;
> +
> + if (ab < bb)
> + return -1;
> + else if (ab > bb)
> + return 1;
> + else
> + return 0;
> +}
> +
> +int a3700_dram_init_banksize(void)
> +{
> + struct a3700_dram_window dram_wins[MVEBU_CPU_DEC_WINS];
> + int bank, win, ndram_wins;
> + u32 last_end;
> + size_t size;
> +
> + ndram_wins = 0;
> + for (win = 0; win < MVEBU_CPU_DEC_WINS; ++win) {
> + u32 base, tgt, size;
> +
> + /* skip disabled windows */
> + if (get_cpu_dec_win(win, &tgt, &base, &size))
> + continue;
> +
> + /* skip non-DRAM windows */
> + if (tgt != MVEBU_CPU_DEC_WIN_CTRL_TGT_DRAM)
> + continue;
> +
> + dram_wins[win].base = base;
> + dram_wins[win].size = size;
> + ++ndram_wins;
> + }
> +
> + qsort(dram_wins, ndram_wins, sizeof(dram_wins[0]), dram_win_cmp);
> +
> + bank = 0;
> + last_end = -1;
> +
> + for (win = 0; win < ndram_wins; ++win) {
> + /* again determining actual RAM size as in a3700_dram_init */
> + size = get_ram_size((void *)dram_wins[win].base,
> + dram_wins[win].size);
> +
> + /*
> + * Check if previous window ends as the current starts. If yes,
> + * merge these windows into one "bank". This is possible by this
> + * simple check thanks to mem_map regions being qsorted in
> + * build_mem_map.
> + */
> + if (last_end == dram_wins[win].base) {
> + gd->bd->bi_dram[bank - 1].size += size;
> + last_end += size;
> + } else {
> + if (bank == CONFIG_NR_DRAM_BANKS) {
> + printf("Need more CONFIG_NR_DRAM_BANKS\n");
> + return -ENOBUFS;
> + }
> +
> + gd->bd->bi_dram[bank].start = dram_wins[win].base;
> + gd->bd->bi_dram[bank].size = size;
> + last_end = dram_wins[win].base + size;
> + ++bank;
> + }
> + }
> +
> + /*
> + * If there is more place for DRAM BANKS definitions than needed, fill
> + * the rest with zeros.
> + */
> + for (; bank < CONFIG_NR_DRAM_BANKS; ++bank) {
> + gd->bd->bi_dram[bank].start = 0;
> + gd->bd->bi_dram[bank].size = 0;
> + }
> +
> + return 0;
> +}
> +
> void reset_cpu(ulong ignored)
> {
> /*
> diff --git a/arch/arm/mach-mvebu/include/mach/cpu.h b/arch/arm/mach-mvebu/include/mach/cpu.h
> index 7af8e5d09f..2a53329420 100644
> --- a/arch/arm/mach-mvebu/include/mach/cpu.h
> +++ b/arch/arm/mach-mvebu/include/mach/cpu.h
> @@ -174,6 +174,10 @@ static inline void mv_avs_init(void) {}
> u64 a8k_dram_scan_ap_sz(void);
> int a8k_dram_init_banksize(void);
>
> +/* A3700 dram functions */
> +int a3700_dram_init(void);
> +int a3700_dram_init_banksize(void);
> +
> /*
> * get_ref_clk
> *
>
Viele Grüße,
Stefan
--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-51 Fax: (+49)-8142-66989-80 Email: sr at denx.de
More information about the U-Boot
mailing list