Hi Chris and Quentin,

On 2024-03-27 11:51, Quentin Schulz wrote:
> Hi Chris,
> 
> On 3/26/24 21:49, Chris Morgan wrote:
>> From: Chris Morgan <macromor...@hotmail.com>
>>
>> Add support for defining the usable RAM from ATAGs provided by the
>> Rockchip binary TPL loader. This allows us to automatically account
>> for necessary memory holes on RK3588 devices with 16GB of RAM or
>> more, as well as ensure we can use the full amount of RAM available.
>>
>> In the event we can't cleanly read the ATAG values from RAM or are
>> not running an RK3588 board, simply fall back to the old method of
>> detecting the RAM.
>>
>> Tested on Indiedroid Nova with 4GB and 16GB of RAM.
>>
>> Signed-off-by: Chris Morgan <macromor...@hotmail.com>
>> ---
>>   arch/arm/mach-rockchip/sdram.c | 58 ++++++++++++++++++++++++++++++++++
>>   1 file changed, 58 insertions(+)
>>
>> diff --git a/arch/arm/mach-rockchip/sdram.c b/arch/arm/mach-rockchip/sdram.c
>> index 0d9a0aef6f..58b78466b0 100644
>> --- a/arch/arm/mach-rockchip/sdram.c
>> +++ b/arch/arm/mach-rockchip/sdram.c
>> @@ -10,6 +10,7 @@
>>   #include <ram.h>
>>   #include <asm/global_data.h>
>>   #include <asm/io.h>
>> +#include <asm/arch-rockchip/atags.h>
>>   #include <asm/arch-rockchip/sdram.h>
>>   #include <dm/uclass-internal.h>
>>   
>> @@ -35,12 +36,69 @@ struct tos_parameter_t {
>>      s64 reserve[8];
>>   };
>>   
>> +/*
>> + * Read the ATAGs to identify all the memory banks. If we can't do it
>> + * cleanly return 1 to note an unsuccessful attempt, otherwise return
>> + * 0 for a successful attempt.
> 
> Return a valid error code instead? Negative if possible?
> 
>> + */
>> +int rockchip_atag_ram_banks(void)
>> +{
>> +    struct tag *t;
>> +    int bank_cnt;
>> +    size_t tmp;
>> +
>> +    if (!CONFIG_IS_ENABLED(ARM64) && !CONFIG_IS_ENABLED(ROCKCHIP_RK3588))

CONFIG_IS_ENABLED should only be used if there is an xPL variant of the
config symbol, IS_ENABLED should probably be used here. Also I would
possible check for !IS_ENABLED(CONFIG_ROCKCHIP_EXTERNAL_TPL) instead.

>> +            return 1;
>> +
>> +    t = atags_get_tag(ATAG_DDR_MEM);
> 
> I believe this will not compile for non RK3588 because this function is 
> not defined.
> 
> There are a few ways to handle this:
> - always compile atags.c but have ifdefs there with inline functions 
> returning -ENOTSUPP or something like that.
> 
>> +    if (!t)
>> +            return 1;
>> +
> 
> -ENOENT? -ENOXIO?
> 
>> +    bank_cnt = t->u.ddr_mem.count;
>> +
>> +    /*
>> +     * Check to make sure the first bank ends at 0xf0000000, if it
> 
> Explain what 0xf0000000 represents here.

You should use SDRAM_MAX_SIZE instead of 0xf0000000.

> 
>> +     * does not fall back to the other methods of RAM bank
>> +     * detection.
> 
> Do we really need the first bank to ends exactly at 0xf0000000? Or 
> should we rather make sure that it doesn't go into that space? (so 
> anything below that would be fine?). I assume this is the result of some 
> experiments, what did you learn from those boards?

The Rockchip TPL will report differently depending on model/build.

Some report regions that can be used as-is, other report actual memory.
So we must handle the case where first bank is reported for
0 - SDRAM_MAX_SIZE and the other case when full memory, 0 - 8 GiB, is
reported and skips the SDRAM_MAX_SIZE - 4GiB hw regs space.

Here are dumps of ddr_mem atag on RK3568/RK3588:

RK3588: https://gist.github.com/Kwiboo/1c020d37e3adbc9d0d79dc003d921977
RK3568: https://gist.github.com/Kwiboo/6d983693c79365b43c330eb3191cbace

  count = number of banks
  bank[x] = start addr
  bank[x + count] = size

> 
>> +     */
>> +    if (t->u.ddr_mem.bank[t->u.ddr_mem.count] != 0xf0000000)
>> +            return 1;
>> +
> 
> -EINVAL?
> 
>> +    /*
>> +     * Iterate over the RAM banks. If the start address of bank 0
>> +     * is less than or equal to 0x200000, set it to 0x200000 to
>> +     * reserve room for A-TF. Make sure the size of bank 0 doesn't
>> +     * bleed into the address space for hardware (starting at
>> +     * 0xf0000000). Banks 1 and on can be defined as-is.
>> +     */
>> +    for (int i = 0; i < (t->u.ddr_mem.count); i++) {
> 
> This may result in out-of-bounds access. Indeed gd->bd->bi_dram is a 
> build-time allocated array of size CONFIG_NR_DRAM_BANKS.
> 
> So I would recommend printing an error message if t->u.ddr_mem.count is 
> bigger than CONFIG_NR_DRAM_BANKS. I assume we may want to still boot but 
> with less RAM in that case? If we do, then only loop for the min between 
> t->u.ddr_mem.count and CONFIG_NR_DRAM_BANKS.
> 
>> +            if (i == 0) {
>> +                    if (t->u.ddr_mem.bank[i] <= 0x200000)
>> +                            gd->bd->bi_dram[i].start = 0x200000;
>> +                    else
>> +                            gd->bd->bi_dram[i].start = t->u.ddr_mem.bank[i];
>> +                    tmp = gd->bd->bi_dram[i].start + 
>> t->u.ddr_mem.bank[(bank_cnt + i)];
> 
> This is incorrect, it may be offsetting up to 0x200000. If it's offset, 
> you need to remove it from the address size.
> 
> """
> if (t->u.ddr_mem.bank[i] <= 0x200000)
>      tmp -= 0x200000;
> """
> 
>> +                    if (tmp > 0xf0000000)
>> +                            gd->bd->bi_dram[i].size = 0xf0000000 - 
>> gd->bd->bi_dram[i].start;
> 
> Shouldn't we do this check for all declared address spaces, not only the 
> first one?
> 
>> +                    else
>> +                            gd->bd->bi_dram[i].size = 
>> t->u.ddr_mem.bank[(bank_cnt + i)];
> 
> You may need to remove the 0x200000 offset here as well, e.g. with
> 
> """
> 
> if (tmp > 0xf0000000)
>      tmp = 0xf0000000;
> 
> gd->bd->bi_dram[i].size = tmp - gd->bd->bi_dram[i].start;
> """
> 
> Renaming tmp into end would probably also help figure out what it's 
> supposed to contain.
> 
>> +            } else {
>> +                    gd->bd->bi_dram[i].start = t->u.ddr_mem.bank[i];
>> +                    gd->bd->bi_dram[i].size = t->u.ddr_mem.bank[(bank_cnt + 
>> i)];
>> +            }
>> +    };
>> +
> 
> You can make this for-loop logic a bit more readable (well, to me :) ) with:
> 
> """
> /* Iterate over the RAM banks. */
> /* If the start address of bank 0
>   * is less than or equal to 0x200000, set it to 0x200000 to
>   * reserve room for A-TF. Make sure the size of bank 0 doesn't
>   * bleed into the address space for hardware (starting at
>   * 0xf0000000).
>   */
> if (t->u.ddr_mem.bank[0] <= 0x200000)
>      gd->bd->bi_dram[0].start = 0x200000;
> else
>      gd->bd->bi_dram[0].start = t->u.ddr_mem.bank[0];
> 
> tmp = gd->bd->bi_dram[0].start + t->u.ddr_mem.bank[bank_cnt];
> 
> if (tmp > 0xf0000000)
>      gd->bd->bi_dram[0].size = 0xf0000000 - gd->bd->bi_dram[0].start;
> else
>      gd->bd->bi_dram[0].size = t->u.ddr_mem.bank[bank_cnt];
> 
> for (int i = 1; i < (t->u.ddr_mem.count); i++) {
>      gd->bd->bi_dram[i].start = t->u.ddr_mem.bank[i];
>      gd->bd->bi_dram[i].size = t->u.ddr_mem.bank[(bank_cnt + i)];
> }
> """
> 
> Side question, do gd->bd->bi_dram have to store banks in a specific 
> order (e.g. from lowest (0) to highest (0xfffffff) location in memory) 
> or can it be random? If the former, is Rockchip guaranteeing us that the 
> ATAGS will always be ordered properly or should we order them at runtime 
> too?

Based on dumps of multiple different versions and models, the banks have
always been reported in correct order.

Regards,
Jonas

> 
> Cheers,
> Quentin

Reply via email to