diff --git a/hw/ppc4xx.h b/hw/ppc4xx.h index 3b986624c5..7832cd9f30 100644 --- a/hw/ppc4xx.h +++ b/hw/ppc4xx.h @@ -48,6 +48,11 @@ enum { qemu_irq *ppcuic_init (CPUState *env, qemu_irq *irqs, uint32_t dcr_base, int has_ssr, int has_vr); +ram_addr_t ppc4xx_sdram_adjust(ram_addr_t ram_size, int nr_banks, + target_phys_addr_t ram_bases[], + target_phys_addr_t ram_sizes[], + const unsigned int sdram_bank_sizes[]); + void ppc4xx_sdram_init (CPUState *env, qemu_irq irq, int nbanks, target_phys_addr_t *ram_bases, target_phys_addr_t *ram_sizes, diff --git a/hw/ppc4xx_devs.c b/hw/ppc4xx_devs.c index 2d27e23ca9..939e0669e2 100644 --- a/hw/ppc4xx_devs.c +++ b/hw/ppc4xx_devs.c @@ -873,3 +873,45 @@ void ppc4xx_sdram_init (CPUState *env, qemu_irq irq, int nbanks, sdram_map_bcr(sdram); } } + +/* Fill in consecutive SDRAM banks with 'ram_size' bytes of memory. + * + * sdram_bank_sizes[] must be 0-terminated. + * + * The 4xx SDRAM controller supports a small number of banks, and each bank + * must be one of a small set of sizes. The number of banks and the supported + * sizes varies by SoC. */ +ram_addr_t ppc4xx_sdram_adjust(ram_addr_t ram_size, int nr_banks, + target_phys_addr_t ram_bases[], + target_phys_addr_t ram_sizes[], + const unsigned int sdram_bank_sizes[]) +{ + ram_addr_t ram_end = 0; + int i; + int j; + + for (i = 0; i < nr_banks; i++) { + for (j = 0; sdram_bank_sizes[j] != 0; j++) { + unsigned int bank_size = sdram_bank_sizes[j]; + + if (bank_size <= ram_size) { + ram_bases[i] = ram_end; + ram_sizes[i] = bank_size; + ram_end += bank_size; + ram_size -= bank_size; + break; + } + } + + if (!ram_size) { + /* No need to use the remaining banks. */ + break; + } + } + + if (ram_size) + printf("Truncating memory to %d MiB to fit SDRAM controller limits.\n", + (int)(ram_end >> 20)); + + return ram_end; +}