On 7/9/20 8:43 AM, Havard Skinnemoen wrote: > On Wed, Jul 8, 2020 at 11:04 PM Philippe Mathieu-Daudé <f4...@amsat.org> > wrote: >> On 7/9/20 2:35 AM, Havard Skinnemoen wrote: >>> Implement a device model for the System Global Control Registers in the >>> NPCM730 and NPCM750 BMC SoCs. >>> >>> This is primarily used to enable SMP boot (the boot ROM spins reading >>> the SCRPAD register) and DDR memory initialization; other registers are >>> best effort for now. >>> >>> The reset values of the MDLR and PWRON registers are determined by the >>> SoC variant (730 vs 750) and board straps respectively. >>> >>> Reviewed-by: Joel Stanley <j...@jms.id.au> >>> Reviewed-by: Cédric Le Goater <c...@kaod.org> >>> Signed-off-by: Havard Skinnemoen <hskinnem...@google.com> >>> --- [...] >>> diff --git a/hw/misc/npcm7xx_gcr.c b/hw/misc/npcm7xx_gcr.c >>> new file mode 100644 >>> index 0000000000..9934cd238d >>> --- /dev/null >>> +++ b/hw/misc/npcm7xx_gcr.c >>> @@ -0,0 +1,226 @@ >>> +/* >>> + * Nuvoton NPCM7xx System Global Control Registers. >>> + * >>> + * Copyright 2020 Google LLC >>> + * >>> + * This program is free software; you can redistribute it and/or modify it >>> + * under the terms of the GNU General Public License as published by the >>> + * Free Software Foundation; either version 2 of the License, or >>> + * (at your option) any later version. >>> + * >>> + * This program is distributed in the hope that it will be useful, but >>> WITHOUT >>> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or >>> + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License >>> + * for more details. >>> + */ >>> + >>> +#include "qemu/osdep.h" >>> + >>> +#include "hw/misc/npcm7xx_gcr.h" >>> +#include "hw/qdev-properties.h" >>> +#include "migration/vmstate.h" >>> +#include "qapi/error.h" >>> +#include "qemu/log.h" >>> +#include "qemu/module.h" >>> +#include "qemu/units.h" >>> + >>> +#include "trace.h" >>> + >>> +static const uint32_t cold_reset_values[NPCM7XX_GCR_NR_REGS] = { >>> + [NPCM7XX_GCR_PDID] = 0x04a92750, /* Poleg A1 */ >>> + [NPCM7XX_GCR_MISCPE] = 0x0000ffff, >>> + [NPCM7XX_GCR_SPSWC] = 0x00000003, >>> + [NPCM7XX_GCR_INTCR] = 0x0000035e, >>> + [NPCM7XX_GCR_HIFCR] = 0x0000004e, >>> + [NPCM7XX_GCR_INTCR2] = (1U << 19), /* DDR initialized */ >>> + [NPCM7XX_GCR_RESSR] = 0x80000000, >>> + [NPCM7XX_GCR_DSCNT] = 0x000000c0, >>> + [NPCM7XX_GCR_DAVCLVLR] = 0x5a00f3cf, >>> + [NPCM7XX_GCR_SCRPAD] = 0x00000008, >>> + [NPCM7XX_GCR_USB1PHYCTL] = 0x034730e4, >>> + [NPCM7XX_GCR_USB2PHYCTL] = 0x034730e4, >>> +}; >>> + >>> +static uint64_t npcm7xx_gcr_read(void *opaque, hwaddr offset, unsigned >>> size) >>> +{ >>> + uint32_t reg = offset / sizeof(uint32_t); >>> + NPCM7xxGCRState *s = opaque; >>> + >>> + if (reg >= NPCM7XX_GCR_NR_REGS) { >>> + qemu_log_mask(LOG_GUEST_ERROR, "%s: offset 0x%04x out of range\n", >>> + __func__, (unsigned int)offset); >> >> Maybe use HWADDR_PRIx instead of casting to int? > > Will do, thanks!
Glad you are not annoyed by my review comments. FYI your series quality is in my top-4 "adding new machine to QEMU". I'd like to use it as example to follow. I am slowly reviewing because this is not part of my work duties, so I do that in my free time before/after work, which is why I can barely do more that 2 per day, as I have to learn the SoC and cross check documentation (or in this case, existing firmware code since there is no public doc). [...] >>> +static void npcm7xx_gcr_realize(DeviceState *dev, Error **errp) >>> +{ >>> + NPCM7xxGCRState *s = NPCM7XX_GCR(dev); >>> + uint64_t dram_size; >>> + Error *err = NULL; >>> + Object *obj; >>> + >>> + obj = object_property_get_link(OBJECT(dev), "dram-mr", &err); >>> + if (!obj) { >>> + error_setg(errp, "%s: required dram-mr link not found: %s", >>> + __func__, error_get_pretty(err)); >>> + return; >>> + } >>> + dram_size = memory_region_size(MEMORY_REGION(obj)); >>> + >>> + /* Power-on reset value */ >>> + s->reset_intcr3 = 0x00001002; >>> + >>> + /* >>> + * The GMMAP (Graphics Memory Map) field is used by u-boot to detect >>> the >>> + * DRAM size, and is normally initialized by the boot block as part of >>> DRAM >>> + * training. However, since we don't have a complete emulation of the >>> + * memory controller and try to make it look like it has already been >>> + * initialized, the boot block will skip this initialization, and we >>> need >>> + * to make sure this field is set correctly up front. >>> + * >>> + * WARNING: some versions of u-boot only looks at bits 8 and 9, so 2 >>> GiB or >>> + * more of DRAM will be interpreted as 128 MiB. >> >> I'd say u-boot is right in wrapping at 2GB, as more DRAM is >> un-addressable. > > Ah, maybe I shouldn't have said "or more". The bug is that if you > specify _exactly_ 2GiB, u-boot will see 128 MiB. > > But I agree more than 2GiB doesn't make sense, so I'll add a check for that. > > Not sure if I agree that the check should be here. > 2 GiB is an > addressing limitation, and the GCR module shouldn't really know what > the SoC's address space looks like. The lower limit is because the GCR > module can't encode anything less than 128 MiB. > >>> + * >>> + * >>> https://github.com/Nuvoton-Israel/u-boot/blob/2aef993bd2aafeb5408dbaad0f3ce099ee40c4aa/board/nuvoton/poleg/poleg.c#L244 >>> + */ >>> + if (dram_size >= 2 * GiB) { >> >> See my comment in this series on the machine patch. >> >>> + s->reset_intcr3 |= 4 << 8; >>> + } else if (dram_size >= 1 * GiB) { >>> + s->reset_intcr3 |= 3 << 8; >>> + } else if (dram_size >= 512 * MiB) { >>> + s->reset_intcr3 |= 2 << 8; >>> + } else if (dram_size >= 256 * MiB) { >>> + s->reset_intcr3 |= 1 << 8; >>> + } else if (dram_size >= 128 * MiB) { >>> + s->reset_intcr3 |= 0 << 8; I think this can be simplified as: s->reset_intcr3 = (4 - clz32(dram_size)) << 8; Which implicitly truncate to power of 2 (which is what this block does, as you can have only 1 bank managed per this SGC). But checking is_power_of_2(dram_size) and reporting an error else, is probably even better. >>> + } else { >>> + error_setg(errp, >>> + "npcm7xx_gcr: DRAM size %" PRIu64 >>> + " is too small (need 128 MiB minimum)", >>> + dram_size); >> >> Ah, so you could add the same error for >2GB. Easier. >> >> Preferably using HWADDR_PRIx, and similar error for >2GB: >> Reviewed-by: Philippe Mathieu-Daudé <f4...@amsat.org>