From mboxrd@z Thu Jan 1 00:00:00 1970 From: Stefan Roese Date: Tue, 14 Apr 2020 10:02:32 +0200 Subject: [PATCH v1 u-boot-marvell 2/5] arm64: mvebu: a37xx: improve code determining memory info structures In-Reply-To: <20200408172522.18941-3-marek.behun@nic.cz> References: <20200408172522.18941-1-marek.behun@nic.cz> <20200408172522.18941-3-marek.behun@nic.cz> Message-ID: <89872376-e54f-920d-4e0e-9772d6102516@denx.de> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de 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 Reviewed-by: Stefan Roese 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 > + * Copyright (C) 2020 Marek Behun > */ > > #include > @@ -13,6 +14,7 @@ > #include > #include > #include > +#include > > /* 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