Re: [PATCH 2/3] hw/ssi: Add Nuvoton PSPI Module

2023-02-07 Thread Philippe Mathieu-Daudé

On 7/2/23 20:21, Hao Wu wrote:
On Tue, Feb 7, 2023 at 10:46 AM Hao Wu > wrote:


Thanks for your review!

On Mon, Feb 6, 2023 at 11:13 PM Philippe Mathieu-Daudé
mailto:phi...@linaro.org>> wrote:

On 7/2/23 00:34, Hao Wu wrote:
 > Nuvoton's PSPI is a general purpose SPI module which enables
 > connections to SPI-based peripheral devices.
 >
 > Signed-off-by: Hao Wu mailto:wuhao...@google.com>>
 > Reviewed-by: Chris Rauer mailto:cra...@google.com>>
 > ---
 >   MAINTAINERS                |   6 +-
 >   hw/ssi/meson.build         |   2 +-
 >   hw/ssi/npcm_pspi.c         | 216
+
 >   hw/ssi/trace-events        |   5 +
 >   include/hw/ssi/npcm_pspi.h |  53 +
 >   5 files changed, 278 insertions(+), 4 deletions(-)
 >   create mode 100644 hw/ssi/npcm_pspi.c
 >   create mode 100644 include/hw/ssi/npcm_pspi.h




 > +static void npcm_pspi_realize(DeviceState *dev, Error **errp)
 > +{
 > +    NPCMPSPIState *s = NPCM_PSPI(dev);
 > +    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
 > +    Object *obj = OBJECT(dev);
 > +
 > +    s->spi = ssi_create_bus(dev, "pspi");

FYI there is an ongoing discussion about how to model QOM tree. If
this bus isn't shared with another controller, the "embed QOM child
in parent" style could be preferred. If so, the bus would be created
as:

        object_initialize_child(obj, "pspi", >spi, TYPE_SSI_BUS);

I was just following some existing code here. I think I can use the
new style. 


I've tried to use this and got the following error:
**
ERROR:../qom/object.c:511:object_initialize_with_type: assertion failed: 
(size >= type->instance_size)
Bail out! ERROR:../qom/object.c:511:object_initialize_with_type: 
assertion failed: (size >= type->instance_size)


I think the problem is that we define s->spi as SSIBus* instead of 
SSIBus. But if we define it as SSIBus, we'll
get an incomplete type error. Fixing it will require refactoring 
hw/ssi/ssi.c which I'm not sure if we want to do
it right now. This code is consistent with other code in hw/ssi so I 
guess we can leave it here for now and wait

for a future refactor.

Sorry, I was just mumbling alone thinking about what would need to be
done, not asking you to change it yet :/ I should have been
more explicit.



Re: [PATCH 2/3] hw/ssi: Add Nuvoton PSPI Module

2023-02-07 Thread Hao Wu
On Tue, Feb 7, 2023 at 10:46 AM Hao Wu  wrote:

> Thanks for your review!
>
> On Mon, Feb 6, 2023 at 11:13 PM Philippe Mathieu-Daudé 
> wrote:
>
>> On 7/2/23 00:34, Hao Wu wrote:
>> > Nuvoton's PSPI is a general purpose SPI module which enables
>> > connections to SPI-based peripheral devices.
>> >
>> > Signed-off-by: Hao Wu 
>> > Reviewed-by: Chris Rauer 
>> > ---
>> >   MAINTAINERS|   6 +-
>> >   hw/ssi/meson.build |   2 +-
>> >   hw/ssi/npcm_pspi.c | 216 +
>> >   hw/ssi/trace-events|   5 +
>> >   include/hw/ssi/npcm_pspi.h |  53 +
>> >   5 files changed, 278 insertions(+), 4 deletions(-)
>> >   create mode 100644 hw/ssi/npcm_pspi.c
>> >   create mode 100644 include/hw/ssi/npcm_pspi.h
>>
>>
>> > +static const MemoryRegionOps npcm_pspi_ctrl_ops = {
>> > +.read = npcm_pspi_ctrl_read,
>> > +.write = npcm_pspi_ctrl_write,
>> > +.endianness = DEVICE_LITTLE_ENDIAN,
>> > +.valid = {
>> > +.min_access_size = 1,
>> > +.max_access_size = 2,
>>
>> I'm not sure about ".max_access_size = 2". The datasheet does
>> not seem public. Does that mean the CPU bus can not do a 32-bit
>> access to read two consecutive 16-bit registers? (these fields
>> restrict the guest accesses to the device).
>>
>> > +.unaligned = false,
>> > +},
>>
>> You might want instead (which is how you implemented the r/w
>> handlers):
>>
>>  .impl.min_access_size = 2,
>>  .impl.max_access_size = 2,
>>
> Thanks for the reminder. The datasheet suggests it's either 8-bit or
> 16-bit accesses. But I think using your suggestion makes sense
> and will be more widely adapted.
>
>>
>> > +};
>>
>>
>> > +static void npcm_pspi_realize(DeviceState *dev, Error **errp)
>> > +{
>> > +NPCMPSPIState *s = NPCM_PSPI(dev);
>> > +SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
>> > +Object *obj = OBJECT(dev);
>> > +
>> > +s->spi = ssi_create_bus(dev, "pspi");
>>
>> FYI there is an ongoing discussion about how to model QOM tree. If
>> this bus isn't shared with another controller, the "embed QOM child
>> in parent" style could be preferred. If so, the bus would be created
>> as:
>>
>>object_initialize_child(obj, "pspi", >spi, TYPE_SSI_BUS);
>>
> I was just following some existing code here. I think I can use the new
> style.
>
I've tried to use this and got the following error:
**
ERROR:../qom/object.c:511:object_initialize_with_type: assertion failed:
(size >= type->instance_size)
Bail out! ERROR:../qom/object.c:511:object_initialize_with_type: assertion
failed: (size >= type->instance_size)

I think the problem is that we define s->spi as SSIBus* instead of SSIBus.
But if we define it as SSIBus, we'll
get an incomplete type error. Fixing it will require refactoring
hw/ssi/ssi.c which I'm not sure if we want to do
it right now. This code is consistent with other code in hw/ssi so I guess
we can leave it here for now and wait
for a future refactor.

>
>> > +memory_region_init_io(>mmio, obj, _pspi_ctrl_ops, s,
>> > +  "mmio", 4 * KiB);
>> > +sysbus_init_mmio(sbd, >mmio);
>> > +sysbus_init_irq(sbd, >irq);
>> > +}
>>
>>
>> > diff --git a/hw/ssi/trace-events b/hw/ssi/trace-events
>> > index c707d4aaba..16ea9954c4 100644
>> > --- a/hw/ssi/trace-events
>> > +++ b/hw/ssi/trace-events
>>
>> > +# npcm_pspi.c
>> > +npcm_pspi_enter_reset(const char *id, int reset_type) "%s reset type:
>> %d"
>> > +npcm_pspi_ctrl_read(const char *id, uint64_t addr, uint16_t data) "%s
>> offset: 0x%04" PRIx64 " value: 0x%08" PRIx16
>> > +npcm_pspi_ctrl_write(const char *id, uint64_t addr, uint16_t data) "%s
>> offset: 0x%04" PRIx64 " value: 0x%08" PRIx16
>>
>> Since the region is 4KiB and the implementation is 16-bit, the formats
>> could be simplified as offset 0x%03 and value 0x%04. The traces will
>> then be more digestible to human eyes.
>>
> I'll do this.
>
>>
>> Modulo the impl.access_size change:
>> Reviewed-by: Philippe Mathieu-Daudé 
>>
>>


Re: [PATCH 2/3] hw/ssi: Add Nuvoton PSPI Module

2023-02-07 Thread Hao Wu
Thanks for your review!

On Mon, Feb 6, 2023 at 11:13 PM Philippe Mathieu-Daudé 
wrote:

> On 7/2/23 00:34, Hao Wu wrote:
> > Nuvoton's PSPI is a general purpose SPI module which enables
> > connections to SPI-based peripheral devices.
> >
> > Signed-off-by: Hao Wu 
> > Reviewed-by: Chris Rauer 
> > ---
> >   MAINTAINERS|   6 +-
> >   hw/ssi/meson.build |   2 +-
> >   hw/ssi/npcm_pspi.c | 216 +
> >   hw/ssi/trace-events|   5 +
> >   include/hw/ssi/npcm_pspi.h |  53 +
> >   5 files changed, 278 insertions(+), 4 deletions(-)
> >   create mode 100644 hw/ssi/npcm_pspi.c
> >   create mode 100644 include/hw/ssi/npcm_pspi.h
>
>
> > +static const MemoryRegionOps npcm_pspi_ctrl_ops = {
> > +.read = npcm_pspi_ctrl_read,
> > +.write = npcm_pspi_ctrl_write,
> > +.endianness = DEVICE_LITTLE_ENDIAN,
> > +.valid = {
> > +.min_access_size = 1,
> > +.max_access_size = 2,
>
> I'm not sure about ".max_access_size = 2". The datasheet does
> not seem public. Does that mean the CPU bus can not do a 32-bit
> access to read two consecutive 16-bit registers? (these fields
> restrict the guest accesses to the device).
>
> > +.unaligned = false,
> > +},
>
> You might want instead (which is how you implemented the r/w
> handlers):
>
>  .impl.min_access_size = 2,
>  .impl.max_access_size = 2,
>
Thanks for the reminder. The datasheet suggests it's either 8-bit or
16-bit accesses. But I think using your suggestion makes sense
and will be more widely adapted.

>
> > +};
>
>
> > +static void npcm_pspi_realize(DeviceState *dev, Error **errp)
> > +{
> > +NPCMPSPIState *s = NPCM_PSPI(dev);
> > +SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
> > +Object *obj = OBJECT(dev);
> > +
> > +s->spi = ssi_create_bus(dev, "pspi");
>
> FYI there is an ongoing discussion about how to model QOM tree. If
> this bus isn't shared with another controller, the "embed QOM child
> in parent" style could be preferred. If so, the bus would be created
> as:
>
>object_initialize_child(obj, "pspi", >spi, TYPE_SSI_BUS);
>
I was just following some existing code here. I think I can use the new
style.

>
> > +memory_region_init_io(>mmio, obj, _pspi_ctrl_ops, s,
> > +  "mmio", 4 * KiB);
> > +sysbus_init_mmio(sbd, >mmio);
> > +sysbus_init_irq(sbd, >irq);
> > +}
>
>
> > diff --git a/hw/ssi/trace-events b/hw/ssi/trace-events
> > index c707d4aaba..16ea9954c4 100644
> > --- a/hw/ssi/trace-events
> > +++ b/hw/ssi/trace-events
>
> > +# npcm_pspi.c
> > +npcm_pspi_enter_reset(const char *id, int reset_type) "%s reset type:
> %d"
> > +npcm_pspi_ctrl_read(const char *id, uint64_t addr, uint16_t data) "%s
> offset: 0x%04" PRIx64 " value: 0x%08" PRIx16
> > +npcm_pspi_ctrl_write(const char *id, uint64_t addr, uint16_t data) "%s
> offset: 0x%04" PRIx64 " value: 0x%08" PRIx16
>
> Since the region is 4KiB and the implementation is 16-bit, the formats
> could be simplified as offset 0x%03 and value 0x%04. The traces will
> then be more digestible to human eyes.
>
I'll do this.

>
> Modulo the impl.access_size change:
> Reviewed-by: Philippe Mathieu-Daudé 
>
>


Re: [PATCH 2/3] hw/ssi: Add Nuvoton PSPI Module

2023-02-06 Thread Philippe Mathieu-Daudé

On 7/2/23 00:34, Hao Wu wrote:

Nuvoton's PSPI is a general purpose SPI module which enables
connections to SPI-based peripheral devices.

Signed-off-by: Hao Wu 
Reviewed-by: Chris Rauer 
---
  MAINTAINERS|   6 +-
  hw/ssi/meson.build |   2 +-
  hw/ssi/npcm_pspi.c | 216 +
  hw/ssi/trace-events|   5 +
  include/hw/ssi/npcm_pspi.h |  53 +
  5 files changed, 278 insertions(+), 4 deletions(-)
  create mode 100644 hw/ssi/npcm_pspi.c
  create mode 100644 include/hw/ssi/npcm_pspi.h




+static const MemoryRegionOps npcm_pspi_ctrl_ops = {
+.read = npcm_pspi_ctrl_read,
+.write = npcm_pspi_ctrl_write,
+.endianness = DEVICE_LITTLE_ENDIAN,
+.valid = {
+.min_access_size = 1,
+.max_access_size = 2,


I'm not sure about ".max_access_size = 2". The datasheet does
not seem public. Does that mean the CPU bus can not do a 32-bit
access to read two consecutive 16-bit registers? (these fields
restrict the guest accesses to the device).


+.unaligned = false,
+},


You might want instead (which is how you implemented the r/w
handlers):

.impl.min_access_size = 2,
.impl.max_access_size = 2,


+};




+static void npcm_pspi_realize(DeviceState *dev, Error **errp)
+{
+NPCMPSPIState *s = NPCM_PSPI(dev);
+SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+Object *obj = OBJECT(dev);
+
+s->spi = ssi_create_bus(dev, "pspi");


FYI there is an ongoing discussion about how to model QOM tree. If
this bus isn't shared with another controller, the "embed QOM child
in parent" style could be preferred. If so, the bus would be created
as:

  object_initialize_child(obj, "pspi", >spi, TYPE_SSI_BUS);


+memory_region_init_io(>mmio, obj, _pspi_ctrl_ops, s,
+  "mmio", 4 * KiB);
+sysbus_init_mmio(sbd, >mmio);
+sysbus_init_irq(sbd, >irq);
+}




diff --git a/hw/ssi/trace-events b/hw/ssi/trace-events
index c707d4aaba..16ea9954c4 100644
--- a/hw/ssi/trace-events
+++ b/hw/ssi/trace-events



+# npcm_pspi.c
+npcm_pspi_enter_reset(const char *id, int reset_type) "%s reset type: %d"
+npcm_pspi_ctrl_read(const char *id, uint64_t addr, uint16_t data) "%s offset: 0x%04" 
PRIx64 " value: 0x%08" PRIx16
+npcm_pspi_ctrl_write(const char *id, uint64_t addr, uint16_t data) "%s offset: 0x%04" 
PRIx64 " value: 0x%08" PRIx16


Since the region is 4KiB and the implementation is 16-bit, the formats
could be simplified as offset 0x%03 and value 0x%04. The traces will
then be more digestible to human eyes.

Modulo the impl.access_size change:
Reviewed-by: Philippe Mathieu-Daudé 




[PATCH 2/3] hw/ssi: Add Nuvoton PSPI Module

2023-02-06 Thread Hao Wu
Nuvoton's PSPI is a general purpose SPI module which enables
connections to SPI-based peripheral devices.

Signed-off-by: Hao Wu 
Reviewed-by: Chris Rauer 
---
 MAINTAINERS|   6 +-
 hw/ssi/meson.build |   2 +-
 hw/ssi/npcm_pspi.c | 216 +
 hw/ssi/trace-events|   5 +
 include/hw/ssi/npcm_pspi.h |  53 +
 5 files changed, 278 insertions(+), 4 deletions(-)
 create mode 100644 hw/ssi/npcm_pspi.c
 create mode 100644 include/hw/ssi/npcm_pspi.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 347936e41c..1e2a711373 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -803,9 +803,9 @@ M: Tyrone Ting 
 M: Hao Wu 
 L: qemu-...@nongnu.org
 S: Supported
-F: hw/*/npcm7xx*
-F: include/hw/*/npcm7xx*
-F: tests/qtest/npcm7xx*
+F: hw/*/npcm*
+F: include/hw/*/npcm*
+F: tests/qtest/npcm*
 F: pc-bios/npcm7xx_bootrom.bin
 F: roms/vbootrom
 F: docs/system/arm/nuvoton.rst
diff --git a/hw/ssi/meson.build b/hw/ssi/meson.build
index 702aa5e4df..904a47161a 100644
--- a/hw/ssi/meson.build
+++ b/hw/ssi/meson.build
@@ -1,6 +1,6 @@
 softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_smc.c'))
 softmmu_ss.add(when: 'CONFIG_MSF2', if_true: files('mss-spi.c'))
-softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_fiu.c'))
+softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_fiu.c', 
'npcm_pspi.c'))
 softmmu_ss.add(when: 'CONFIG_PL022', if_true: files('pl022.c'))
 softmmu_ss.add(when: 'CONFIG_SIFIVE_SPI', if_true: files('sifive_spi.c'))
 softmmu_ss.add(when: 'CONFIG_SSI', if_true: files('ssi.c'))
diff --git a/hw/ssi/npcm_pspi.c b/hw/ssi/npcm_pspi.c
new file mode 100644
index 00..565bba5282
--- /dev/null
+++ b/hw/ssi/npcm_pspi.c
@@ -0,0 +1,216 @@
+/*
+ * Nuvoton NPCM Peripheral SPI Module (PSPI)
+ *
+ * Copyright 2023 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/irq.h"
+#include "hw/registerfields.h"
+#include "hw/ssi/npcm_pspi.h"
+#include "migration/vmstate.h"
+#include "qapi/error.h"
+#include "qemu/error-report.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "qemu/units.h"
+
+#include "trace.h"
+
+REG16(PSPI_DATA, 0x0)
+REG16(PSPI_CTL1, 0x2)
+FIELD(PSPI_CTL1, SPIEN, 0,  1)
+FIELD(PSPI_CTL1, MOD,   2,  1)
+FIELD(PSPI_CTL1, EIR,   5,  1)
+FIELD(PSPI_CTL1, EIW,   6,  1)
+FIELD(PSPI_CTL1, SCM,   7,  1)
+FIELD(PSPI_CTL1, SCIDL, 8,  1)
+FIELD(PSPI_CTL1, SCDV,  9,  7)
+REG16(PSPI_STAT, 0x4)
+FIELD(PSPI_STAT, BSY,  0,  1)
+FIELD(PSPI_STAT, RBF,  1,  1)
+
+static void npcm_pspi_update_irq(NPCMPSPIState *s)
+{
+int level = 0;
+
+/* Only fire IRQ when the module is enabled. */
+if (FIELD_EX16(s->regs[R_PSPI_CTL1], PSPI_CTL1, SPIEN)) {
+/* Update interrupt as BSY is cleared. */
+if ((!FIELD_EX16(s->regs[R_PSPI_STAT], PSPI_STAT, BSY)) &&
+FIELD_EX16(s->regs[R_PSPI_CTL1], PSPI_CTL1, EIW)) {
+level = 1;
+}
+
+/* Update interrupt as RBF is set. */
+if (FIELD_EX16(s->regs[R_PSPI_STAT], PSPI_STAT, RBF) &&
+FIELD_EX16(s->regs[R_PSPI_CTL1], PSPI_CTL1, EIR)) {
+level = 1;
+}
+}
+qemu_set_irq(s->irq, level);
+}
+
+static uint16_t npcm_pspi_read_data(NPCMPSPIState *s)
+{
+uint16_t value = s->regs[R_PSPI_DATA];
+
+/* Clear stat bits as the value are read out. */
+s->regs[R_PSPI_STAT] = 0;
+
+return value;
+}
+
+static void npcm_pspi_write_data(NPCMPSPIState *s, uint16_t data)
+{
+uint16_t value = 0;
+
+if (FIELD_EX16(s->regs[R_PSPI_CTL1], PSPI_CTL1, MOD)) {
+value = ssi_transfer(s->spi, extract16(data, 8, 8)) << 8;
+}
+value |= ssi_transfer(s->spi, extract16(data, 0, 8));
+s->regs[R_PSPI_DATA] = value;
+
+/* Mark data as available */
+s->regs[R_PSPI_STAT] = R_PSPI_STAT_BSY_MASK | R_PSPI_STAT_RBF_MASK;
+}
+
+/* Control register read handler. */
+static uint64_t npcm_pspi_ctrl_read(void *opaque, hwaddr addr,
+unsigned int size)
+{
+NPCMPSPIState *s = opaque;
+uint16_t value;
+
+switch (addr) {
+case A_PSPI_DATA:
+value = npcm_pspi_read_data(s);
+break;
+
+case A_PSPI_CTL1:
+value = s->regs[R_PSPI_CTL1];
+break;
+
+case A_PSPI_STAT:
+value = s->regs[R_PSPI_STAT];
+break;
+
+default:
+qemu_log_mask(LOG_GUEST_ERROR,
+  "%s: write to invalid offset 0x%" PRIx64 "\n",
+