On Thu, Jul 9, 2020 at 10:24 AM Philippe Mathieu-Daudé <f4...@amsat.org> wrote: > > 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.
OK, I'll try to post a v6 before the weekend, unless you prefer that I hold off until you've reviewed the whole series. > 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/ Yes, tests are definitely on my radar. I'm working on SPI flash qtests. I haven't had much success with avocado yet, but I'll keep trying (perhaps using docker to control the environment more tightly). Since the 5.1 release is frozen now, I might post some followup patches before this series is merged, e.g. tests, bootrom submodule+blob, more peripherals, etc. Is it preferable to keep this series frozen (modulo API updates) since you spent a lot of time reviewing it, and post the new stuff separately, or is it better to add new patches to the end of the series and resend the whole thing? > But these are apparently not stable links (expire after 30 days?). Sorry, I'm too ignorant about Jenkins to know. I'll see if I can figure something out. > >> [...] > >>>>> +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> > >