soc/qualcomm/common: Add MMU configuration for fragmented DRAM regions

Stating with Qualcomm X1P42100 SoC generation, the DRAM memory map is
not expected to be contiguous (unlike previous generations) therefore,
the memory map could be something like this.

1. Assume hardware design has 4GB of DRAM then the memory map would
look like:
  - DDR_SPACE (2 GB) :  0x80000000 - 0x100000000
  - DDR_SPACE_1 (2 GB) : 0x880000000 - 0x900000000

2. Assume hardware design has 16GB of DRAM then the memory map would
look like:
  - DDR_SPACE (2 GB) :  0x80000000 - 0x100000000
  - DDR_SPACE_1 (14 GB) : 0x880000000 - 0x400000000

3. Assume hardware design has 64GB of DRAM then the memory map would
look like:
  - DDR_SPACE (2 GB) :  0x80000000 - 0x100000000
  - DDR_SPACE_1 (30 GB) : 0x880000000 - 0x1000000000
  - DDR_SPACE_2 (32 GB) : 0x8800000000 - 0x9000000000

This commit introduces logic to handle systems with fragmented DRAM
configurations. Previously, the Memory Management Unit (MMU) was
configured assuming a single, contiguous block of DRAM.

This change extends the MMU setup to properly configure multiple,
non-contiguous DRAM regions.

The changes include:

- Declaring dram_space_1 and dram_space_2 as optional regions, allowing
the dynamic allocation for these DRAM ranges based on DRAM capacity of
the platform.

- Introduce `qc_get_soc_dram_space_config` function that takes care of
DRAM based resource splitting as per `_dram`, `_dram_space_1` and
`_dram_space_2` region limit.

- Modifying qc_mmu_dram_config_post_dram_init() to check for these
optional regions and configure them individually. This ensures all
available DRAM is correctly mapped and accessible to the system.

This approach improves flexibility and allows coreboot to support a
wider range of Qualcomm platforms with different memory layouts.

TEST=Able to boot google/quenbi to OS.

Change-Id: If3788f4c77535f9a5e47ad2034ab9a8e0fe85b51
Signed-off-by: Subrata Banik <subratabanik@google.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/88752
Reviewed-by: Kapil Porwal <kapilporwal@google.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
Subrata Banik 2025-08-12 22:02:41 +05:30
commit 276432faf7
3 changed files with 62 additions and 3 deletions

View file

@ -12,6 +12,7 @@
static struct region * const ddr_region = (struct region *)_ddr_information;
struct region *qc_get_soc_dram_space_config(size_t ddr_size, int *count);
void soc_mmu_dram_config_post_dram_init(void);
void qc_mmu_dram_config_post_dram_init(size_t ddr_size);
bool soc_modem_carve_out(void **start, void **end);

View file

@ -32,4 +32,12 @@ DECLARE_REGION(dram_modem)
DECLARE_REGION(dram_tz)
DECLARE_REGION(dram_tz_rem)
/*
* DDR_SPACE (2 GB) aka `_dram`: 0x80000000 - 0x100000000
* DDR_SPACE_1 (30 GB) aka `_dram_space_1`: 0x880000000 - 0x1000000000
* DDR_SPACE_2 (480 GB) aka `dram_space_2`: 0x8800000000 - 0x10000000000
*/
DECLARE_OPTIONAL_REGION(dram_space_1)
DECLARE_OPTIONAL_REGION(dram_space_2)
#endif // _SOC_QUALCOMM_SYMBOLS_COMMON_H_

View file

@ -1,22 +1,72 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <arch/mmu.h>
#include <console/console.h>
#include <soc/mmu.h>
#include <soc/mmu_common.h>
#include <soc/symbols_common.h>
/* DRAM region: DDR_SPACE, DDR_SPACE_1 and DDR_SPACE_2 */
#define MAX_DRAM_SPACE_INDEX 3
__weak bool soc_modem_carve_out(void **start, void **end) { return false; }
struct region *qc_get_soc_dram_space_config(size_t ddr_size, int *count)
{
static struct region config[MAX_DRAM_SPACE_INDEX];
static int populated_count = 0;
int i;
if (!populated_count) {
void *region_start[MAX_DRAM_SPACE_INDEX] = {
_dram,
_dram_space_1,
_dram_space_2
};
size_t size[MAX_DRAM_SPACE_INDEX] = {
REGION_SIZE(dram),
REGION_SIZE(dram_space_1),
REGION_SIZE(dram_space_2)
};
/* Handle the case where DDR space is contiguous */
if (!_edram)
size[0] = ddr_size;
for (i = 0; i < MAX_DRAM_SPACE_INDEX && ddr_size > 0; i++) {
config[i].offset = (size_t)region_start[i];
size_t to_map = MIN(ddr_size, size[i]);
config[i].size = to_map;
ddr_size -= to_map;
}
populated_count = i;
if (ddr_size)
printk(BIOS_CRIT, "Too much DRAM for available windows (%zu bytes left over)!\n",
ddr_size);
}
*count = populated_count;
return config;
}
void qc_mmu_dram_config_post_dram_init(size_t ddr_size)
{
void *start = NULL;
void *end = NULL;
if (!soc_modem_carve_out(&start, &end)) {
mmu_config_range((void *)_dram, ddr_size, CACHED_RAM);
} else {
if (soc_modem_carve_out(&start, &end)) {
if (_dram_space_1)
die("Using carve out together with DRAM windows not supported");
mmu_config_range((void *)_dram, start - (void *)_dram, CACHED_RAM);
mmu_config_range(end, (void *)_dram + ddr_size - end, CACHED_RAM);
} else {
int count;
struct region *config = qc_get_soc_dram_space_config(ddr_size, &count);
for (int i = 0; i < count; i++)
mmu_config_range((void *)config[i].offset, config[i].size, CACHED_RAM);
}
mmu_config_range((void *)_aop_code_ram, REGION_SIZE(aop_code_ram),