On 7/9/20 7:09 PM, Havard Skinnemoen wrote: > On Thu, Jul 9, 2020 at 9:23 AM Philippe Mathieu-Daudé <f4...@amsat.org> wrote: >> 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). > > Your feedback is super valuable, thanks a lot. I really appreciate it.
OK I'll continue, but might not have time until next week. After I plan to test too. What would be useful is an acceptance test (see examples in tests/acceptance/), using the artefacts from the link you shared elsewhere: https://openpower.xyz/job/run-meta-ci/distro=ubuntu,label=builder,target=gsj/lastSuccessfulBuild/artifact/openbmc/build/tmp/deploy/images/gsj/ But these are apparently not stable links (expire after 30 days?). >> [...] >>>>> +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). > > Good idea. I find this a little easier to understand though: > > #define NPCM7XX_GCR_MIN_DRAM_SIZE (128 * MiB) > > s->reset_intcr3 |= ctz64(dram_size / NPCM7XX_GCR_MIN_DRAM_SIZE) << 8; I like it, furthermore it will work with >4GB if this model is ever reused on an ARMv8-A SoC. >> But checking is_power_of_2(dram_size) and reporting an error >> else, is probably even better. > > OK, I'll add a check for this, and also explicit checks for too large > and too small. The former is currently redundant with the DRAM size > check I'm adding to npcm7xx_realize(), but I kind of like the idea of > checking for encoding limitations and addressing limitations > separately, as they may not necessarily stay the same forever. > >>>>> + } 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> >