/* * QEMU PowerPC 4xx embedded processors SDRAM controller emulation * * DDR SDRAM controller: * Copyright (c) 2007 Jocelyn Mayer * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * * DDR2 SDRAM controller: * Copyright (c) 2012 François Revol * Copyright (c) 2016-2019 BALATON Zoltan * * This work is licensed under the GNU GPL license version 2 or later. */ #include "qemu/osdep.h" #include "qemu/units.h" #include "qapi/error.h" #include "qemu/log.h" #include "qemu/error-report.h" #include "exec/address-spaces.h" /* get_system_memory() */ #include "hw/irq.h" #include "hw/qdev-properties.h" #include "hw/ppc/ppc4xx.h" #include "trace.h" /*****************************************************************************/ /* Shared functions */ /* * Split RAM between SDRAM banks. * * sdram_bank_sizes[] must be in descending order, that is sizes[i] > sizes[i+1] * and 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. */ static bool ppc4xx_sdram_banks(MemoryRegion *ram, int nr_banks, Ppc4xxSdramBank ram_banks[], const ram_addr_t sdram_bank_sizes[], Error **errp) { ERRP_GUARD(); ram_addr_t size_left = memory_region_size(ram); ram_addr_t base = 0; ram_addr_t bank_size; int i; int j; for (i = 0; i < nr_banks; i++) { for (j = 0; sdram_bank_sizes[j] != 0; j++) { bank_size = sdram_bank_sizes[j]; if (bank_size <= size_left) { char name[32]; ram_banks[i].base = base; ram_banks[i].size = bank_size; base += bank_size; size_left -= bank_size; snprintf(name, sizeof(name), "ppc4xx.sdram%d", i); memory_region_init_alias(&ram_banks[i].ram, NULL, name, ram, ram_banks[i].base, ram_banks[i].size); break; } } if (!size_left) { /* No need to use the remaining banks. */ break; } } if (size_left) { ram_addr_t used_size = memory_region_size(ram) - size_left; GString *s = g_string_new(NULL); for (i = 0; sdram_bank_sizes[i]; i++) { g_string_append_printf(s, "%" PRIi64 "%s", sdram_bank_sizes[i] / MiB, sdram_bank_sizes[i + 1] ? ", " : ""); } error_setg(errp, "Invalid SDRAM banks"); error_append_hint(errp, "at most %d bank%s of %s MiB each supported\n", nr_banks, nr_banks == 1 ? "" : "s", s->str); error_append_hint(errp, "Possible valid RAM size: %" PRIi64 " MiB\n", used_size ? used_size / MiB : sdram_bank_sizes[i - 1] / MiB); g_string_free(s, true); return false; } return true; } static void sdram_bank_map(Ppc4xxSdramBank *bank) { trace_ppc4xx_sdram_map(bank->base, bank->size); memory_region_init(&bank->container, NULL, "sdram-container", bank->size); memory_region_add_subregion(&bank->container, 0, &bank->ram); memory_region_add_subregion(get_system_memory(), bank->base, &bank->container); } static void sdram_bank_unmap(Ppc4xxSdramBank *bank) { trace_ppc4xx_sdram_unmap(bank->base, bank->size); memory_region_del_subregion(get_system_memory(), &bank->container); memory_region_del_subregion(&bank->container, &bank->ram); object_unparent(OBJECT(&bank->container)); } static void sdram_bank_set_bcr(Ppc4xxSdramBank *bank, uint32_t bcr, hwaddr base, hwaddr size, int enabled) { if (memory_region_is_mapped(&bank->container)) { sdram_bank_unmap(bank); } bank->bcr = bcr; bank->base = base; bank->size = size; if (enabled && (bcr & 1)) { sdram_bank_map(bank); } } enum { SDRAM0_CFGADDR = 0x010, SDRAM0_CFGDATA = 0x011, }; /*****************************************************************************/ /* DDR SDRAM controller */ #define SDRAM_DDR_BCR_MASK 0xFFDEE001 static uint32_t sdram_ddr_bcr(hwaddr ram_base, hwaddr ram_size) { uint32_t bcr; switch (ram_size) { case 4 * MiB: bcr = 0; break; case 8 * MiB: bcr = 0x20000; break; case 16 * MiB: bcr = 0x40000; break; case 32 * MiB: bcr = 0x60000; break; case 64 * MiB: bcr = 0x80000; break; case 128 * MiB: bcr = 0xA0000; break; case 256 * MiB: bcr = 0xC0000; break; default: qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid RAM size 0x%" HWADDR_PRIx "\n", __func__, ram_size); return 0; } bcr |= ram_base & 0xFF800000; bcr |= 1; return bcr; } static inline hwaddr sdram_ddr_base(uint32_t bcr) { return bcr & 0xFF800000; } static hwaddr sdram_ddr_size(uint32_t bcr) { int sh = (bcr >> 17) & 0x7; if (sh == 7) { return -1; } return (4 * MiB) << sh; } static uint32_t sdram_ddr_dcr_read(void *opaque, int dcrn) { Ppc4xxSdramDdrState *s = opaque; uint32_t ret; switch (dcrn) { case SDRAM0_CFGADDR: ret = s->addr; break; case SDRAM0_CFGDATA: switch (s->addr) { case 0x00: /* SDRAM_BESR0 */ ret = s->besr0; break; case 0x08: /* SDRAM_BESR1 */ ret = s->besr1; break; case 0x10: /* SDRAM_BEAR */ ret = s->bear; break; case 0x20: /* SDRAM_CFG */ ret = s->cfg; break; case 0x24: /* SDRAM_STATUS */ ret = s->status; break; case 0x30: /* SDRAM_RTR */ ret = s->rtr; break; case 0x34: /* SDRAM_PMIT */ ret = s->pmit; break; case 0x40: /* SDRAM_B0CR */ ret = s->bank[0].bcr; break; case 0x44: /* SDRAM_B1CR */ ret = s->bank[1].bcr; break; case 0x48: /* SDRAM_B2CR */ ret = s->bank[2].bcr; break; case 0x4C: /* SDRAM_B3CR */ ret = s->bank[3].bcr; break; case 0x80: /* SDRAM_TR */ ret = -1; /* ? */ break; case 0x94: /* SDRAM_ECCCFG */ ret = s->ecccfg; break; case 0x98: /* SDRAM_ECCESR */ ret = s->eccesr; break; default: /* Error */ ret = -1; break; } break; default: /* Avoid gcc warning */ ret = 0; break; } return ret; } static void sdram_ddr_dcr_write(void *opaque, int dcrn, uint32_t val) { Ppc4xxSdramDdrState *s = opaque; int i; switch (dcrn) { case SDRAM0_CFGADDR: s->addr = val; break; case SDRAM0_CFGDATA: switch (s->addr) { case 0x00: /* SDRAM_BESR0 */ s->besr0 &= ~val; break; case 0x08: /* SDRAM_BESR1 */ s->besr1 &= ~val; break; case 0x10: /* SDRAM_BEAR */ s->bear = val; break; case 0x20: /* SDRAM_CFG */ val &= 0xFFE00000; if (!(s->cfg & 0x80000000) && (val & 0x80000000)) { trace_ppc4xx_sdram_enable("enable"); /* validate all RAM mappings */ for (i = 0; i < s->nbanks; i++) { if (s->bank[i].size) { sdram_bank_set_bcr(&s->bank[i], s->bank[i].bcr, s->bank[i].base, s->bank[i].size, 1); } } s->status &= ~0x80000000; } else if ((s->cfg & 0x80000000) && !(val & 0x80000000)) { trace_ppc4xx_sdram_enable("disable"); /* invalidate all RAM mappings */ for (i = 0; i < s->nbanks; i++) { if (s->bank[i].size) { sdram_bank_set_bcr(&s->bank[i], s->bank[i].bcr, s->bank[i].base, s->bank[i].size, 0); } } s->status |= 0x80000000; } if (!(s->cfg & 0x40000000) && (val & 0x40000000)) { s->status |= 0x40000000; } else if ((s->cfg & 0x40000000) && !(val & 0x40000000)) { s->status &= ~0x40000000; } s->cfg = val; break; case 0x24: /* SDRAM_STATUS */ /* Read-only register */ break; case 0x30: /* SDRAM_RTR */ s->rtr = val & 0x3FF80000; break; case 0x34: /* SDRAM_PMIT */ s->pmit = (val & 0xF8000000) | 0x07C00000; break; case 0x40: /* SDRAM_B0CR */ case 0x44: /* SDRAM_B1CR */ case 0x48: /* SDRAM_B2CR */ case 0x4C: /* SDRAM_B3CR */ i = (s->addr - 0x40) / 4; val &= SDRAM_DDR_BCR_MASK; if (s->bank[i].size) { sdram_bank_set_bcr(&s->bank[i], val, sdram_ddr_base(val), sdram_ddr_size(val), s->cfg & 0x80000000); } break; case 0x80: /* SDRAM_TR */ s->tr = val & 0x018FC01F; break; case 0x94: /* SDRAM_ECCCFG */ s->ecccfg = val & 0x00F00000; break; case 0x98: /* SDRAM_ECCESR */ val &= 0xFFF0F000; if (s->eccesr == 0 && val != 0) { qemu_irq_raise(s->irq); } else if (s->eccesr != 0 && val == 0) { qemu_irq_lower(s->irq); } s->eccesr = val; break; default: /* Error */ break; } break; } } static void ppc4xx_sdram_ddr_reset(DeviceState *dev) { Ppc4xxSdramDdrState *s = PPC4xx_SDRAM_DDR(dev); s->addr = 0; s->bear = 0; s->besr0 = 0; /* No error */ s->besr1 = 0; /* No error */ s->cfg = 0; s->ecccfg = 0; /* No ECC */ s->eccesr = 0; /* No error */ s->pmit = 0x07C00000; s->rtr = 0x05F00000; s->tr = 0x00854009; /* We pre-initialize RAM banks */ s->status = 0; s->cfg = 0x00800000; } static void ppc4xx_sdram_ddr_realize(DeviceState *dev, Error **errp) { Ppc4xxSdramDdrState *s = PPC4xx_SDRAM_DDR(dev); Ppc4xxDcrDeviceState *dcr = PPC4xx_DCR_DEVICE(dev); const ram_addr_t valid_bank_sizes[] = { 256 * MiB, 128 * MiB, 64 * MiB, 32 * MiB, 16 * MiB, 8 * MiB, 4 * MiB, 0 }; int i; if (s->nbanks < 1 || s->nbanks > 4) { error_setg(errp, "Invalid number of RAM banks"); return; } if (!s->dram_mr) { error_setg(errp, "Missing dram memory region"); return; } if (!ppc4xx_sdram_banks(s->dram_mr, s->nbanks, s->bank, valid_bank_sizes, errp)) { return; } for (i = 0; i < s->nbanks; i++) { if (s->bank[i].size) { s->bank[i].bcr = sdram_ddr_bcr(s->bank[i].base, s->bank[i].size); sdram_bank_set_bcr(&s->bank[i], s->bank[i].bcr, s->bank[i].base, s->bank[i].size, 0); } else { sdram_bank_set_bcr(&s->bank[i], 0, 0, 0, 0); } trace_ppc4xx_sdram_init(sdram_ddr_base(s->bank[i].bcr), sdram_ddr_size(s->bank[i].bcr), s->bank[i].bcr); } sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq); ppc4xx_dcr_register(dcr, SDRAM0_CFGADDR, s, &sdram_ddr_dcr_read, &sdram_ddr_dcr_write); ppc4xx_dcr_register(dcr, SDRAM0_CFGDATA, s, &sdram_ddr_dcr_read, &sdram_ddr_dcr_write); } static Property ppc4xx_sdram_ddr_props[] = { DEFINE_PROP_LINK("dram", Ppc4xxSdramDdrState, dram_mr, TYPE_MEMORY_REGION, MemoryRegion *), DEFINE_PROP_UINT32("nbanks", Ppc4xxSdramDdrState, nbanks, 4), DEFINE_PROP_END_OF_LIST(), }; static void ppc4xx_sdram_ddr_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); dc->realize = ppc4xx_sdram_ddr_realize; device_class_set_legacy_reset(dc, ppc4xx_sdram_ddr_reset); /* Reason: only works as function of a ppc4xx SoC */ dc->user_creatable = false; device_class_set_props(dc, ppc4xx_sdram_ddr_props); } void ppc4xx_sdram_ddr_enable(Ppc4xxSdramDdrState *s) { sdram_ddr_dcr_write(s, SDRAM0_CFGADDR, 0x20); sdram_ddr_dcr_write(s, SDRAM0_CFGDATA, 0x80000000); } /*****************************************************************************/ /* DDR2 SDRAM controller */ #define SDRAM_DDR2_BCR_MASK 0xffe0ffc1 enum { SDRAM_R0BAS = 0x40, SDRAM_R1BAS, SDRAM_R2BAS, SDRAM_R3BAS, SDRAM_CONF1HB = 0x45, SDRAM_PLBADDULL = 0x4a, SDRAM_CONF1LL = 0x4b, SDRAM_CONFPATHB = 0x4f, SDRAM_PLBADDUHB = 0x50, }; static uint32_t sdram_ddr2_bcr(hwaddr ram_base, hwaddr ram_size) { uint32_t bcr; switch (ram_size) { case 8 * MiB: bcr = 0xffc0; break; case 16 * MiB: bcr = 0xff80; break; case 32 * MiB: bcr = 0xff00; break; case 64 * MiB: bcr = 0xfe00; break; case 128 * MiB: bcr = 0xfc00; break; case 256 * MiB: bcr = 0xf800; break; case 512 * MiB: bcr = 0xf000; break; case 1 * GiB: bcr = 0xe000; break; case 2 * GiB: bcr = 0xc000; break; case 4 * GiB: bcr = 0x8000; break; default: error_report("invalid RAM size " HWADDR_FMT_plx, ram_size); return 0; } bcr |= ram_base >> 2 & 0xffe00000; bcr |= 1; return bcr; } static inline hwaddr sdram_ddr2_base(uint32_t bcr) { return (bcr & 0xffe00000) << 2; } static hwaddr sdram_ddr2_size(uint32_t bcr) { int sh; sh = 1024 - ((bcr >> 6) & 0x3ff); return 8 * MiB * sh; } static uint32_t sdram_ddr2_dcr_read(void *opaque, int dcrn) { Ppc4xxSdramDdr2State *s = opaque; uint32_t ret = 0; switch (dcrn) { case SDRAM_R0BAS: case SDRAM_R1BAS: case SDRAM_R2BAS: case SDRAM_R3BAS: if (s->bank[dcrn - SDRAM_R0BAS].size) { ret = sdram_ddr2_bcr(s->bank[dcrn - SDRAM_R0BAS].base, s->bank[dcrn - SDRAM_R0BAS].size); } break; case SDRAM_CONF1HB: case SDRAM_CONF1LL: case SDRAM_CONFPATHB: case SDRAM_PLBADDULL: case SDRAM_PLBADDUHB: break; case SDRAM0_CFGADDR: ret = s->addr; break; case SDRAM0_CFGDATA: switch (s->addr) { case 0x14: /* SDRAM_MCSTAT (405EX) */ case 0x1F: ret = 0x80000000; break; case 0x21: /* SDRAM_MCOPT2 */ ret = s->mcopt2; break; case 0x40: /* SDRAM_MB0CF */ ret = 0x00008001; break; case 0x7A: /* SDRAM_DLCR */ ret = 0x02000000; break; case 0xE1: /* SDR0_DDR0 */ ret = SDR0_DDR0_DDRM_ENCODE(1) | SDR0_DDR0_DDRM_DDR1; break; default: break; } break; default: break; } return ret; } #define SDRAM_DDR2_MCOPT2_DCEN BIT(27) static void sdram_ddr2_dcr_write(void *opaque, int dcrn, uint32_t val) { Ppc4xxSdramDdr2State *s = opaque; int i; switch (dcrn) { case SDRAM_R0BAS: case SDRAM_R1BAS: case SDRAM_R2BAS: case SDRAM_R3BAS: case SDRAM_CONF1HB: case SDRAM_CONF1LL: case SDRAM_CONFPATHB: case SDRAM_PLBADDULL: case SDRAM_PLBADDUHB: break; case SDRAM0_CFGADDR: s->addr = val; break; case SDRAM0_CFGDATA: switch (s->addr) { case 0x00: /* B0CR */ break; case 0x21: /* SDRAM_MCOPT2 */ if (!(s->mcopt2 & SDRAM_DDR2_MCOPT2_DCEN) && (val & SDRAM_DDR2_MCOPT2_DCEN)) { trace_ppc4xx_sdram_enable("enable"); /* validate all RAM mappings */ for (i = 0; i < s->nbanks; i++) { if (s->bank[i].size) { sdram_bank_set_bcr(&s->bank[i], s->bank[i].bcr, s->bank[i].base, s->bank[i].size, 1); } } s->mcopt2 |= SDRAM_DDR2_MCOPT2_DCEN; } else if ((s->mcopt2 & SDRAM_DDR2_MCOPT2_DCEN) && !(val & SDRAM_DDR2_MCOPT2_DCEN)) { trace_ppc4xx_sdram_enable("disable"); /* invalidate all RAM mappings */ for (i = 0; i < s->nbanks; i++) { if (s->bank[i].size) { sdram_bank_set_bcr(&s->bank[i], s->bank[i].bcr, s->bank[i].base, s->bank[i].size, 0); } } s->mcopt2 &= ~SDRAM_DDR2_MCOPT2_DCEN; } break; default: break; } break; default: break; } } static void ppc4xx_sdram_ddr2_reset(DeviceState *dev) { Ppc4xxSdramDdr2State *s = PPC4xx_SDRAM_DDR2(dev); s->addr = 0; s->mcopt2 = 0; } static void ppc4xx_sdram_ddr2_realize(DeviceState *dev, Error **errp) { Ppc4xxSdramDdr2State *s = PPC4xx_SDRAM_DDR2(dev); Ppc4xxDcrDeviceState *dcr = PPC4xx_DCR_DEVICE(dev); /* * SoC also has 4 GiB but that causes problem with 32 bit * builds (4*GiB overflows the 32 bit ram_addr_t). */ const ram_addr_t valid_bank_sizes[] = { 2 * GiB, 1 * GiB, 512 * MiB, 256 * MiB, 128 * MiB, 64 * MiB, 32 * MiB, 16 * MiB, 8 * MiB, 0 }; int i; if (s->nbanks < 1 || s->nbanks > 4) { error_setg(errp, "Invalid number of RAM banks"); return; } if (!s->dram_mr) { error_setg(errp, "Missing dram memory region"); return; } if (!ppc4xx_sdram_banks(s->dram_mr, s->nbanks, s->bank, valid_bank_sizes, errp)) { return; } for (i = 0; i < s->nbanks; i++) { if (s->bank[i].size) { s->bank[i].bcr = sdram_ddr2_bcr(s->bank[i].base, s->bank[i].size); s->bank[i].bcr &= SDRAM_DDR2_BCR_MASK; sdram_bank_set_bcr(&s->bank[i], s->bank[i].bcr, s->bank[i].base, s->bank[i].size, 0); } else { sdram_bank_set_bcr(&s->bank[i], 0, 0, 0, 0); } trace_ppc4xx_sdram_init(sdram_ddr2_base(s->bank[i].bcr), sdram_ddr2_size(s->bank[i].bcr), s->bank[i].bcr); } ppc4xx_dcr_register(dcr, SDRAM0_CFGADDR, s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write); ppc4xx_dcr_register(dcr, SDRAM0_CFGDATA, s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write); ppc4xx_dcr_register(dcr, SDRAM_R0BAS, s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write); ppc4xx_dcr_register(dcr, SDRAM_R1BAS, s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write); ppc4xx_dcr_register(dcr, SDRAM_R2BAS, s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write); ppc4xx_dcr_register(dcr, SDRAM_R3BAS, s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write); ppc4xx_dcr_register(dcr, SDRAM_CONF1HB, s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write); ppc4xx_dcr_register(dcr, SDRAM_PLBADDULL, s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write); ppc4xx_dcr_register(dcr, SDRAM_CONF1LL, s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write); ppc4xx_dcr_register(dcr, SDRAM_CONFPATHB, s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write); ppc4xx_dcr_register(dcr, SDRAM_PLBADDUHB, s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write); } static Property ppc4xx_sdram_ddr2_props[] = { DEFINE_PROP_LINK("dram", Ppc4xxSdramDdr2State, dram_mr, TYPE_MEMORY_REGION, MemoryRegion *), DEFINE_PROP_UINT32("nbanks", Ppc4xxSdramDdr2State, nbanks, 4), DEFINE_PROP_END_OF_LIST(), }; static void ppc4xx_sdram_ddr2_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); dc->realize = ppc4xx_sdram_ddr2_realize; device_class_set_legacy_reset(dc, ppc4xx_sdram_ddr2_reset); /* Reason: only works as function of a ppc4xx SoC */ dc->user_creatable = false; device_class_set_props(dc, ppc4xx_sdram_ddr2_props); } void ppc4xx_sdram_ddr2_enable(Ppc4xxSdramDdr2State *s) { sdram_ddr2_dcr_write(s, SDRAM0_CFGADDR, 0x21); sdram_ddr2_dcr_write(s, SDRAM0_CFGDATA, 0x08000000); } static const TypeInfo ppc4xx_sdram_types[] = { { .name = TYPE_PPC4xx_SDRAM_DDR, .parent = TYPE_PPC4xx_DCR_DEVICE, .instance_size = sizeof(Ppc4xxSdramDdrState), .class_init = ppc4xx_sdram_ddr_class_init, }, { .name = TYPE_PPC4xx_SDRAM_DDR2, .parent = TYPE_PPC4xx_DCR_DEVICE, .instance_size = sizeof(Ppc4xxSdramDdr2State), .class_init = ppc4xx_sdram_ddr2_class_init, } }; DEFINE_TYPES(ppc4xx_sdram_types)