[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