On Tue, Apr 02, 2024 at 06:38:59PM +0200, Quentin Schulz wrote: > Hi Chris, > > On 4/1/24 20:14, Chris Morgan wrote: > > From: Chris Morgan <macromor...@hotmail.com> > > > > Allow RK3568 and RK3588 based boards to get the RAM bank configuration > > from the ROCKCHIP_TPL stage instead of the current logic. This fixes > > both an issue where 256MB of RAM is blocked for devices with >= 4GB > > of RAM and where memory holes need to be defined for devices with > > > = 16GB of RAM. In the event that neither SOC is used and the > > ROCKCHIP_TPL stage is not used, fall back to existing logic. > > > > Signed-off-by: Chris Morgan <macromor...@hotmail.com> > > --- > > arch/arm/mach-rockchip/sdram.c | 100 +++++++++++++++++++++++++++++++++ > > 1 file changed, 100 insertions(+) > > > > diff --git a/arch/arm/mach-rockchip/sdram.c b/arch/arm/mach-rockchip/sdram.c > > index 0d9a0aef6f..e02fb03c5f 100644 > > --- a/arch/arm/mach-rockchip/sdram.c > > +++ b/arch/arm/mach-rockchip/sdram.c > > @@ -12,6 +12,7 @@ > > #include <asm/io.h> > > #include <asm/arch-rockchip/sdram.h> > > #include <dm/uclass-internal.h> > > +#include <linux/errno.h> > > DECLARE_GLOBAL_DATA_PTR; > > @@ -35,11 +36,110 @@ struct tos_parameter_t { > > s64 reserve[8]; > > }; > > +/* Tag magic */ > > +#define ATAGS_CORE_MAGIC 0x54410001 > > +#define ATAGS_DDR_MEM_MAGIC 0x54410052 > > + > > +/* Tag size and offset */ > > +#define ATAGS_SIZE SZ_8K > > +#define ATAGS_OFFSET (SZ_2M - ATAGS_SIZE) > > +#define ATAGS_PHYS_BASE (CFG_SYS_SDRAM_BASE + ATAGS_OFFSET) > > + > > +/* ATAGS memory structure. */ > > +struct tag_ddr_mem { > > + u32 count; > > + u32 version; > > + u64 bank[20]; > > + u32 flags; > > + u32 data[2]; > > + u32 hash; > > +} __packed; > > + > > +/** > > + * rockchip_dram_init_banksize() - Get RAM banks from Rockchip TPL > > + * > > + * Iterate through the defined ATAGS memory location to first find a > > + * valid core header, then find a valid ddr_info header. Sanity check > > + * the number of banks found. Then, iterate through the data to add > > + * each individual memory bank. Perform fixups on memory banks that > > + * overlap with a reserved space. If an error condition is received, > > + * it is expected that memory bank setup will fall back on existing > > + * logic. If ROCKCHIP_EXTERNAL_TPL is false then immediately return, > > + * and if neither ROCKCHIP_RK3588 or ROCKCHIP_RK3568 is enabled > > + * immediately return. > > + * > > + * Return number of banks found on success or negative on error. > > + */ > > +__weak int rockchip_dram_init_banksize(void) > > +{ > > + struct tag_ddr_mem *ddr_info; > > + size_t val; > > + size_t addr = ATAGS_PHYS_BASE; > > I think this should be phys_addr_t instead of size_t? > > size_t is an unsigned long on aarch64 and phys_addr_t is an unsigned long > long so 4B vs 8B. > > This however would likely prevent us from reusing this code on aarch32 > machines, but maybe it's a problem for the people who'll look into > supporting this :) (also, aarch32 and >= 3.75GiB may be a bit optimistic :) > ).
Could I just specify a size and not worry about it? A u32 should be more than enough to hold the maximum RAM address of an RK3588 board (32GB). That would allow this to work on both 32 and 64 right? Otherwise I could further restrict this code to the AARCH64 ifdef. > > > + int i; > > + > > u8 is plenty enough here :) I use it as a return value where there are negative numbers (though obviously this should never be negative since it's an increment counter). Does that matter? > > > + if (!IS_ENABLED(CONFIG_ROCKCHIP_EXTERNAL_TPL)) > > + return 0; > > + if (!IS_ENABLED(CONFIG_ROCKCHIP_RK3588) && > > + !IS_ENABLED(CONFIG_ROCKCHIP_RK3568)) > > + return 0; > > + > > + if (!IS_ENABLED(CONFIG_ROCKCHIP_EXTERNAL_TPL)) > > + return -EPERM; > > + > > I think testing once is enough :) > > Also, you probably want to use -ENOTSUPP instead? Acknowledged. > > > + while (addr < (ATAGS_PHYS_BASE + ATAGS_SIZE)) { > > + val = readl(addr); > > + if (val == ATAGS_CORE_MAGIC) > > Save a variable by not saving the result of readl and just check against > ATAGS_CORE_MAGIC. Acknowledged. > > > + break; > > + addr += 4; > > This is an incorrect step size, addr is 4B, so this will result in 16B > increments, which may be too much. Additionally, we shouldn't read every 4B > as the tag is only ever guaranteed to be 4B aligned, not that we would have > a tag every 4B. This also means that it's possible somehow the content of a > tag at a 4B-aligned offset has the CORE_MAGIC for some reason, but we > shouldn't match on it. > I'm not quite sure I follow. Are you saying I need to increment every 4 * the value of size in the tag_header? The value I show is 0x5 in my header meaning increment every 0x14? > I recommend to follow what Rockchip does downstream: > > """ > struct tag_header { > u32 size; /* size in units of 4B */ > u32 magic; > }; > """ > > if magic != CORE_MAGIC, then we should increment addr by size * 4B and check > again. > > > + } > > + if (addr >= (ATAGS_PHYS_BASE + ATAGS_SIZE)) > > + return -ENODATA; > > I think it'd be nice to have debug messages here and there :) > Will do. > > + > > + while (addr < (ATAGS_PHYS_BASE + ATAGS_SIZE)) { > > + val = readl(addr); > > + if (val == ATAGS_DDR_MEM_MAGIC) > > + break; > > + addr += 4; > > Same remarks here. > > > + } > > + if (addr >= (ATAGS_PHYS_BASE + ATAGS_SIZE)) > > + return -ENODATA; > > + > > + ddr_info = (void *)addr + 4; > > It seems that arithmetic operations on void pointers is illegal in the C > standard. This also quite obfuscate what you want to do here. > > Considering that in this patch you're iterating for each 4B until you get > the MAGIC, the next 4B are data for that header of that magic. > > If you go for the tag_header I suggested above, I would recommend to do the > following instead: > > """ > ddr_info = (u8*)addr + sizeof(addr); > """ > > This is a bit more explicit wrt to what's expected, we want to have the > address of the data right after the tag_header we point to currently. (and > in-code comments also do not hurt :) ). > Should I use a (u8*) though? While that works for now, if the ATAGS get put at a higher offset wouldn't something like a u32 make more sense? > > > + if (!ddr_info->count || ddr_info->count > CONFIG_NR_DRAM_BANKS) > > + return -ENODATA; > > + > > + for (i = 0; i < (ddr_info->count); i++) { > > + size_t start_addr = ddr_info->bank[i]; > > This should be phys_addr_t since it represents an address in physical > memory? Most likely, yes. > > > + size_t size = ddr_info->bank[(i + ddr_info->count)]; > > + size_t tmp; > > + > > Please add a comment here to explain everything about those first 2M :) > (reserved for TF-A but sometimes the ATAGS don't have it reserved) > Will do. My original code had comments inline, but I replaced it with a function description at the top. I think I'll try to do a simple description at the top with inline comments in the next version. > > + if (start_addr < SZ_2M) { > > + tmp = SZ_2M - start_addr; > > + start_addr = SZ_2M; > > + size = size - tmp; > > + } > > + > > Same here, a small comment to explain the check below would be nice. > > > + if (start_addr >= SDRAM_MAX_SIZE && start_addr < SZ_4G) > > + start_addr = SZ_4G; > > + > > Why are we not changing the size here as well? Mistake on my part, will correct. Thank you. > > Same here, a small comment to explain the check below would be nice. > > > + tmp = start_addr + size; > > + if (tmp > SDRAM_MAX_SIZE && tmp < SZ_4G) > > + size = SDRAM_MAX_SIZE - start_addr; > > + > + gd->bd->bi_dram[i].start = start_addr; > > + gd->bd->bi_dram[i].size = size; > > + } > > + > > + return i; > > +} > > + > > Cheers, > Quentin Thank you for your feedback. I'll work on all this and resubmit within a few days. Chris