All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v5 00/11]  RISC-V Add the OpenTitan Machine
@ 2020-05-28 22:14 ` Alistair Francis
  0 siblings, 0 replies; 68+ messages in thread
From: Alistair Francis @ 2020-05-28 22:14 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv; +Cc: alistair.francis, bmeng.cn, palmer, alistair23

OpenTitan is an open source silicon Root of Trust (RoT) project. This
series adds initial support for the OpenTitan machine to QEMU.

This series add the Ibex CPU to the QEMU RISC-V target. It then adds the
OpenTitan machine, the Ibex UART and the Ibex PLIC.

The UART has been tested sending and receiving data.

With this series QEMU can boot the OpenTitan ROM, Tock OS and a Tock
userspace app.

The Ibex PLIC is similar to the RISC-V PLIC (and is based on the QEMU
implementation) with some differences. The hope is that the Ibex PLIC
will converge to follow the RISC-V spec. As that happens I want to
update the QEMU Ibex PLIC and hopefully eventually replace the current
PLIC as the implementation is a little overlay complex.

For more details on OpenTitan, see here: https://docs.opentitan.org/

v5:
 - Add some of the missing unimplemented devices
 - Don't set PMP feature in init() function
v4:
 - Don't set the reset vector in realise
 - Fix a bug where the MMU is always enabled
 - Fixup the PMP/MMU size logic
v3:
 - Small fixes pointed out in review
v2:
 - Rebase on master
 - Get uart receive working



Alistair Francis (11):
  riscv/boot: Add a missing header include
  target/riscv: Don't overwrite the reset vector
  target/riscv: Disable the MMU correctly
  target/riscv: Don't set PMP feature in the cpu init
  target/riscv: Add the lowRISC Ibex CPU
  riscv: Initial commit of OpenTitan machine
  hw/char: Initial commit of Ibex UART
  hw/intc: Initial commit of lowRISC Ibex PLIC
  riscv/opentitan: Connect the PLIC device
  riscv/opentitan: Connect the UART device
  target/riscv: Use a smaller guess size for no-MMU PMP

 default-configs/riscv32-softmmu.mak |   1 +
 default-configs/riscv64-softmmu.mak |  11 +-
 include/hw/char/ibex_uart.h         | 110 +++++++
 include/hw/intc/ibex_plic.h         |  63 ++++
 include/hw/riscv/boot.h             |   1 +
 include/hw/riscv/opentitan.h        |  84 +++++
 target/riscv/cpu.h                  |   1 +
 hw/char/ibex_uart.c                 | 492 ++++++++++++++++++++++++++++
 hw/intc/ibex_plic.c                 | 261 +++++++++++++++
 hw/riscv/opentitan.c                | 219 +++++++++++++
 target/riscv/cpu.c                  |  27 +-
 target/riscv/pmp.c                  |  14 +-
 MAINTAINERS                         |  13 +
 hw/char/Makefile.objs               |   1 +
 hw/intc/Makefile.objs               |   1 +
 hw/riscv/Kconfig                    |   9 +
 hw/riscv/Makefile.objs              |   1 +
 17 files changed, 1291 insertions(+), 18 deletions(-)
 create mode 100644 include/hw/char/ibex_uart.h
 create mode 100644 include/hw/intc/ibex_plic.h
 create mode 100644 include/hw/riscv/opentitan.h
 create mode 100644 hw/char/ibex_uart.c
 create mode 100644 hw/intc/ibex_plic.c
 create mode 100644 hw/riscv/opentitan.c

-- 
2.26.2



^ permalink raw reply	[flat|nested] 68+ messages in thread

* [PATCH v5 00/11]  RISC-V Add the OpenTitan Machine
@ 2020-05-28 22:14 ` Alistair Francis
  0 siblings, 0 replies; 68+ messages in thread
From: Alistair Francis @ 2020-05-28 22:14 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv; +Cc: palmer, alistair.francis, alistair23, bmeng.cn

OpenTitan is an open source silicon Root of Trust (RoT) project. This
series adds initial support for the OpenTitan machine to QEMU.

This series add the Ibex CPU to the QEMU RISC-V target. It then adds the
OpenTitan machine, the Ibex UART and the Ibex PLIC.

The UART has been tested sending and receiving data.

With this series QEMU can boot the OpenTitan ROM, Tock OS and a Tock
userspace app.

The Ibex PLIC is similar to the RISC-V PLIC (and is based on the QEMU
implementation) with some differences. The hope is that the Ibex PLIC
will converge to follow the RISC-V spec. As that happens I want to
update the QEMU Ibex PLIC and hopefully eventually replace the current
PLIC as the implementation is a little overlay complex.

For more details on OpenTitan, see here: https://docs.opentitan.org/

v5:
 - Add some of the missing unimplemented devices
 - Don't set PMP feature in init() function
v4:
 - Don't set the reset vector in realise
 - Fix a bug where the MMU is always enabled
 - Fixup the PMP/MMU size logic
v3:
 - Small fixes pointed out in review
v2:
 - Rebase on master
 - Get uart receive working



Alistair Francis (11):
  riscv/boot: Add a missing header include
  target/riscv: Don't overwrite the reset vector
  target/riscv: Disable the MMU correctly
  target/riscv: Don't set PMP feature in the cpu init
  target/riscv: Add the lowRISC Ibex CPU
  riscv: Initial commit of OpenTitan machine
  hw/char: Initial commit of Ibex UART
  hw/intc: Initial commit of lowRISC Ibex PLIC
  riscv/opentitan: Connect the PLIC device
  riscv/opentitan: Connect the UART device
  target/riscv: Use a smaller guess size for no-MMU PMP

 default-configs/riscv32-softmmu.mak |   1 +
 default-configs/riscv64-softmmu.mak |  11 +-
 include/hw/char/ibex_uart.h         | 110 +++++++
 include/hw/intc/ibex_plic.h         |  63 ++++
 include/hw/riscv/boot.h             |   1 +
 include/hw/riscv/opentitan.h        |  84 +++++
 target/riscv/cpu.h                  |   1 +
 hw/char/ibex_uart.c                 | 492 ++++++++++++++++++++++++++++
 hw/intc/ibex_plic.c                 | 261 +++++++++++++++
 hw/riscv/opentitan.c                | 219 +++++++++++++
 target/riscv/cpu.c                  |  27 +-
 target/riscv/pmp.c                  |  14 +-
 MAINTAINERS                         |  13 +
 hw/char/Makefile.objs               |   1 +
 hw/intc/Makefile.objs               |   1 +
 hw/riscv/Kconfig                    |   9 +
 hw/riscv/Makefile.objs              |   1 +
 17 files changed, 1291 insertions(+), 18 deletions(-)
 create mode 100644 include/hw/char/ibex_uart.h
 create mode 100644 include/hw/intc/ibex_plic.h
 create mode 100644 include/hw/riscv/opentitan.h
 create mode 100644 hw/char/ibex_uart.c
 create mode 100644 hw/intc/ibex_plic.c
 create mode 100644 hw/riscv/opentitan.c

-- 
2.26.2



^ permalink raw reply	[flat|nested] 68+ messages in thread

* [PATCH v5 01/11] riscv/boot: Add a missing header include
  2020-05-28 22:14 ` Alistair Francis
@ 2020-05-28 22:14   ` Alistair Francis
  -1 siblings, 0 replies; 68+ messages in thread
From: Alistair Francis @ 2020-05-28 22:14 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv; +Cc: alistair.francis, bmeng.cn, palmer, alistair23

As the functions declared in this header use the symbol_fn_t
typedef itself declared in "hw/loader.h", we need to include
it here to make the header file self-contained.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Reviewed-by: Bin Meng <bin.meng@windriver.com>
---
 include/hw/riscv/boot.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/include/hw/riscv/boot.h b/include/hw/riscv/boot.h
index 474a940ad5..9daa98da08 100644
--- a/include/hw/riscv/boot.h
+++ b/include/hw/riscv/boot.h
@@ -21,6 +21,7 @@
 #define RISCV_BOOT_H
 
 #include "exec/cpu-defs.h"
+#include "hw/loader.h"
 
 void riscv_find_and_load_firmware(MachineState *machine,
                                   const char *default_machine_firmware,
-- 
2.26.2



^ permalink raw reply related	[flat|nested] 68+ messages in thread

* [PATCH v5 01/11] riscv/boot: Add a missing header include
@ 2020-05-28 22:14   ` Alistair Francis
  0 siblings, 0 replies; 68+ messages in thread
From: Alistair Francis @ 2020-05-28 22:14 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv; +Cc: palmer, alistair.francis, alistair23, bmeng.cn

As the functions declared in this header use the symbol_fn_t
typedef itself declared in "hw/loader.h", we need to include
it here to make the header file self-contained.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Reviewed-by: Bin Meng <bin.meng@windriver.com>
---
 include/hw/riscv/boot.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/include/hw/riscv/boot.h b/include/hw/riscv/boot.h
index 474a940ad5..9daa98da08 100644
--- a/include/hw/riscv/boot.h
+++ b/include/hw/riscv/boot.h
@@ -21,6 +21,7 @@
 #define RISCV_BOOT_H
 
 #include "exec/cpu-defs.h"
+#include "hw/loader.h"
 
 void riscv_find_and_load_firmware(MachineState *machine,
                                   const char *default_machine_firmware,
-- 
2.26.2



^ permalink raw reply related	[flat|nested] 68+ messages in thread

* [PATCH v5 02/11] target/riscv: Don't overwrite the reset vector
  2020-05-28 22:14 ` Alistair Francis
@ 2020-05-28 22:14   ` Alistair Francis
  -1 siblings, 0 replies; 68+ messages in thread
From: Alistair Francis @ 2020-05-28 22:14 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv; +Cc: alistair.francis, bmeng.cn, palmer, alistair23

The reset vector is set in the init function don't set it again in
realize.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Bin Meng <bin.meng@windriver.com>
---
 target/riscv/cpu.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 059d71f2c7..5eb3c02735 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -133,6 +133,7 @@ static void riscv_base32_cpu_init(Object *obj)
     CPURISCVState *env = &RISCV_CPU(obj)->env;
     /* We set this in the realise function */
     set_misa(env, 0);
+    set_resetvec(env, DEFAULT_RSTVEC);
 }
 
 static void rv32gcsu_priv1_09_1_cpu_init(Object *obj)
@@ -180,6 +181,7 @@ static void riscv_base64_cpu_init(Object *obj)
     CPURISCVState *env = &RISCV_CPU(obj)->env;
     /* We set this in the realise function */
     set_misa(env, 0);
+    set_resetvec(env, DEFAULT_RSTVEC);
 }
 
 static void rv64gcsu_priv1_09_1_cpu_init(Object *obj)
@@ -399,7 +401,6 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
     }
 
     set_priv_version(env, priv_version);
-    set_resetvec(env, DEFAULT_RSTVEC);
 
     if (cpu->cfg.mmu) {
         set_feature(env, RISCV_FEATURE_MMU);
-- 
2.26.2



^ permalink raw reply related	[flat|nested] 68+ messages in thread

* [PATCH v5 02/11] target/riscv: Don't overwrite the reset vector
@ 2020-05-28 22:14   ` Alistair Francis
  0 siblings, 0 replies; 68+ messages in thread
From: Alistair Francis @ 2020-05-28 22:14 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv; +Cc: palmer, alistair.francis, alistair23, bmeng.cn

The reset vector is set in the init function don't set it again in
realize.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Bin Meng <bin.meng@windriver.com>
---
 target/riscv/cpu.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 059d71f2c7..5eb3c02735 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -133,6 +133,7 @@ static void riscv_base32_cpu_init(Object *obj)
     CPURISCVState *env = &RISCV_CPU(obj)->env;
     /* We set this in the realise function */
     set_misa(env, 0);
+    set_resetvec(env, DEFAULT_RSTVEC);
 }
 
 static void rv32gcsu_priv1_09_1_cpu_init(Object *obj)
@@ -180,6 +181,7 @@ static void riscv_base64_cpu_init(Object *obj)
     CPURISCVState *env = &RISCV_CPU(obj)->env;
     /* We set this in the realise function */
     set_misa(env, 0);
+    set_resetvec(env, DEFAULT_RSTVEC);
 }
 
 static void rv64gcsu_priv1_09_1_cpu_init(Object *obj)
@@ -399,7 +401,6 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
     }
 
     set_priv_version(env, priv_version);
-    set_resetvec(env, DEFAULT_RSTVEC);
 
     if (cpu->cfg.mmu) {
         set_feature(env, RISCV_FEATURE_MMU);
-- 
2.26.2



^ permalink raw reply related	[flat|nested] 68+ messages in thread

* [PATCH v5 03/11] target/riscv: Disable the MMU correctly
  2020-05-28 22:14 ` Alistair Francis
@ 2020-05-28 22:14   ` Alistair Francis
  -1 siblings, 0 replies; 68+ messages in thread
From: Alistair Francis @ 2020-05-28 22:14 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv; +Cc: alistair.francis, bmeng.cn, palmer, alistair23

Previously if we didn't enable the MMU it would be enabled in the
realize() function anyway. Let's ensure that if we don't want the MMU we
disable it. We also don't need to enable the MMU as it will be enalbed
in realize() by default.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 5eb3c02735..8deba3d16d 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -142,7 +142,6 @@ static void rv32gcsu_priv1_09_1_cpu_init(Object *obj)
     set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
     set_priv_version(env, PRIV_VERSION_1_09_1);
     set_resetvec(env, DEFAULT_RSTVEC);
-    set_feature(env, RISCV_FEATURE_MMU);
     set_feature(env, RISCV_FEATURE_PMP);
 }
 
@@ -152,7 +151,6 @@ static void rv32gcsu_priv1_10_0_cpu_init(Object *obj)
     set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
     set_priv_version(env, PRIV_VERSION_1_10_0);
     set_resetvec(env, DEFAULT_RSTVEC);
-    set_feature(env, RISCV_FEATURE_MMU);
     set_feature(env, RISCV_FEATURE_PMP);
 }
 
@@ -163,6 +161,7 @@ static void rv32imacu_nommu_cpu_init(Object *obj)
     set_priv_version(env, PRIV_VERSION_1_10_0);
     set_resetvec(env, DEFAULT_RSTVEC);
     set_feature(env, RISCV_FEATURE_PMP);
+    qdev_prop_set_bit(DEVICE(obj), "mmu", false);
 }
 
 static void rv32imafcu_nommu_cpu_init(Object *obj)
@@ -172,6 +171,7 @@ static void rv32imafcu_nommu_cpu_init(Object *obj)
     set_priv_version(env, PRIV_VERSION_1_10_0);
     set_resetvec(env, DEFAULT_RSTVEC);
     set_feature(env, RISCV_FEATURE_PMP);
+    qdev_prop_set_bit(DEVICE(obj), "mmu", false);
 }
 
 #elif defined(TARGET_RISCV64)
@@ -190,7 +190,6 @@ static void rv64gcsu_priv1_09_1_cpu_init(Object *obj)
     set_misa(env, RV64 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
     set_priv_version(env, PRIV_VERSION_1_09_1);
     set_resetvec(env, DEFAULT_RSTVEC);
-    set_feature(env, RISCV_FEATURE_MMU);
     set_feature(env, RISCV_FEATURE_PMP);
 }
 
@@ -200,7 +199,6 @@ static void rv64gcsu_priv1_10_0_cpu_init(Object *obj)
     set_misa(env, RV64 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
     set_priv_version(env, PRIV_VERSION_1_10_0);
     set_resetvec(env, DEFAULT_RSTVEC);
-    set_feature(env, RISCV_FEATURE_MMU);
     set_feature(env, RISCV_FEATURE_PMP);
 }
 
@@ -211,6 +209,7 @@ static void rv64imacu_nommu_cpu_init(Object *obj)
     set_priv_version(env, PRIV_VERSION_1_10_0);
     set_resetvec(env, DEFAULT_RSTVEC);
     set_feature(env, RISCV_FEATURE_PMP);
+    qdev_prop_set_bit(DEVICE(obj), "mmu", false);
 }
 
 #endif
-- 
2.26.2



^ permalink raw reply related	[flat|nested] 68+ messages in thread

* [PATCH v5 03/11] target/riscv: Disable the MMU correctly
@ 2020-05-28 22:14   ` Alistair Francis
  0 siblings, 0 replies; 68+ messages in thread
From: Alistair Francis @ 2020-05-28 22:14 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv; +Cc: palmer, alistair.francis, alistair23, bmeng.cn

Previously if we didn't enable the MMU it would be enabled in the
realize() function anyway. Let's ensure that if we don't want the MMU we
disable it. We also don't need to enable the MMU as it will be enalbed
in realize() by default.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 5eb3c02735..8deba3d16d 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -142,7 +142,6 @@ static void rv32gcsu_priv1_09_1_cpu_init(Object *obj)
     set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
     set_priv_version(env, PRIV_VERSION_1_09_1);
     set_resetvec(env, DEFAULT_RSTVEC);
-    set_feature(env, RISCV_FEATURE_MMU);
     set_feature(env, RISCV_FEATURE_PMP);
 }
 
@@ -152,7 +151,6 @@ static void rv32gcsu_priv1_10_0_cpu_init(Object *obj)
     set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
     set_priv_version(env, PRIV_VERSION_1_10_0);
     set_resetvec(env, DEFAULT_RSTVEC);
-    set_feature(env, RISCV_FEATURE_MMU);
     set_feature(env, RISCV_FEATURE_PMP);
 }
 
@@ -163,6 +161,7 @@ static void rv32imacu_nommu_cpu_init(Object *obj)
     set_priv_version(env, PRIV_VERSION_1_10_0);
     set_resetvec(env, DEFAULT_RSTVEC);
     set_feature(env, RISCV_FEATURE_PMP);
+    qdev_prop_set_bit(DEVICE(obj), "mmu", false);
 }
 
 static void rv32imafcu_nommu_cpu_init(Object *obj)
@@ -172,6 +171,7 @@ static void rv32imafcu_nommu_cpu_init(Object *obj)
     set_priv_version(env, PRIV_VERSION_1_10_0);
     set_resetvec(env, DEFAULT_RSTVEC);
     set_feature(env, RISCV_FEATURE_PMP);
+    qdev_prop_set_bit(DEVICE(obj), "mmu", false);
 }
 
 #elif defined(TARGET_RISCV64)
@@ -190,7 +190,6 @@ static void rv64gcsu_priv1_09_1_cpu_init(Object *obj)
     set_misa(env, RV64 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
     set_priv_version(env, PRIV_VERSION_1_09_1);
     set_resetvec(env, DEFAULT_RSTVEC);
-    set_feature(env, RISCV_FEATURE_MMU);
     set_feature(env, RISCV_FEATURE_PMP);
 }
 
@@ -200,7 +199,6 @@ static void rv64gcsu_priv1_10_0_cpu_init(Object *obj)
     set_misa(env, RV64 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
     set_priv_version(env, PRIV_VERSION_1_10_0);
     set_resetvec(env, DEFAULT_RSTVEC);
-    set_feature(env, RISCV_FEATURE_MMU);
     set_feature(env, RISCV_FEATURE_PMP);
 }
 
@@ -211,6 +209,7 @@ static void rv64imacu_nommu_cpu_init(Object *obj)
     set_priv_version(env, PRIV_VERSION_1_10_0);
     set_resetvec(env, DEFAULT_RSTVEC);
     set_feature(env, RISCV_FEATURE_PMP);
+    qdev_prop_set_bit(DEVICE(obj), "mmu", false);
 }
 
 #endif
-- 
2.26.2



^ permalink raw reply related	[flat|nested] 68+ messages in thread

* [PATCH v5 04/11] target/riscv: Don't set PMP feature in the cpu init
  2020-05-28 22:14 ` Alistair Francis
@ 2020-05-28 22:14   ` Alistair Francis
  -1 siblings, 0 replies; 68+ messages in thread
From: Alistair Francis @ 2020-05-28 22:14 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv; +Cc: alistair.francis, bmeng.cn, palmer, alistair23

The PMP is enabled by default via the "pmp" property so there is no need
for us to set it in the init function. As all CPUs have PMP support just
remove the set_feature() call in the CPU init functions.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.c | 7 -------
 1 file changed, 7 deletions(-)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 8deba3d16d..406e8f37d7 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -142,7 +142,6 @@ static void rv32gcsu_priv1_09_1_cpu_init(Object *obj)
     set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
     set_priv_version(env, PRIV_VERSION_1_09_1);
     set_resetvec(env, DEFAULT_RSTVEC);
-    set_feature(env, RISCV_FEATURE_PMP);
 }
 
 static void rv32gcsu_priv1_10_0_cpu_init(Object *obj)
@@ -151,7 +150,6 @@ static void rv32gcsu_priv1_10_0_cpu_init(Object *obj)
     set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
     set_priv_version(env, PRIV_VERSION_1_10_0);
     set_resetvec(env, DEFAULT_RSTVEC);
-    set_feature(env, RISCV_FEATURE_PMP);
 }
 
 static void rv32imacu_nommu_cpu_init(Object *obj)
@@ -160,7 +158,6 @@ static void rv32imacu_nommu_cpu_init(Object *obj)
     set_misa(env, RV32 | RVI | RVM | RVA | RVC | RVU);
     set_priv_version(env, PRIV_VERSION_1_10_0);
     set_resetvec(env, DEFAULT_RSTVEC);
-    set_feature(env, RISCV_FEATURE_PMP);
     qdev_prop_set_bit(DEVICE(obj), "mmu", false);
 }
 
@@ -170,7 +167,6 @@ static void rv32imafcu_nommu_cpu_init(Object *obj)
     set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVC | RVU);
     set_priv_version(env, PRIV_VERSION_1_10_0);
     set_resetvec(env, DEFAULT_RSTVEC);
-    set_feature(env, RISCV_FEATURE_PMP);
     qdev_prop_set_bit(DEVICE(obj), "mmu", false);
 }
 
@@ -190,7 +186,6 @@ static void rv64gcsu_priv1_09_1_cpu_init(Object *obj)
     set_misa(env, RV64 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
     set_priv_version(env, PRIV_VERSION_1_09_1);
     set_resetvec(env, DEFAULT_RSTVEC);
-    set_feature(env, RISCV_FEATURE_PMP);
 }
 
 static void rv64gcsu_priv1_10_0_cpu_init(Object *obj)
@@ -199,7 +194,6 @@ static void rv64gcsu_priv1_10_0_cpu_init(Object *obj)
     set_misa(env, RV64 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
     set_priv_version(env, PRIV_VERSION_1_10_0);
     set_resetvec(env, DEFAULT_RSTVEC);
-    set_feature(env, RISCV_FEATURE_PMP);
 }
 
 static void rv64imacu_nommu_cpu_init(Object *obj)
@@ -208,7 +202,6 @@ static void rv64imacu_nommu_cpu_init(Object *obj)
     set_misa(env, RV64 | RVI | RVM | RVA | RVC | RVU);
     set_priv_version(env, PRIV_VERSION_1_10_0);
     set_resetvec(env, DEFAULT_RSTVEC);
-    set_feature(env, RISCV_FEATURE_PMP);
     qdev_prop_set_bit(DEVICE(obj), "mmu", false);
 }
 
-- 
2.26.2



^ permalink raw reply related	[flat|nested] 68+ messages in thread

* [PATCH v5 04/11] target/riscv: Don't set PMP feature in the cpu init
@ 2020-05-28 22:14   ` Alistair Francis
  0 siblings, 0 replies; 68+ messages in thread
From: Alistair Francis @ 2020-05-28 22:14 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv; +Cc: palmer, alistair.francis, alistair23, bmeng.cn

The PMP is enabled by default via the "pmp" property so there is no need
for us to set it in the init function. As all CPUs have PMP support just
remove the set_feature() call in the CPU init functions.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.c | 7 -------
 1 file changed, 7 deletions(-)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 8deba3d16d..406e8f37d7 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -142,7 +142,6 @@ static void rv32gcsu_priv1_09_1_cpu_init(Object *obj)
     set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
     set_priv_version(env, PRIV_VERSION_1_09_1);
     set_resetvec(env, DEFAULT_RSTVEC);
-    set_feature(env, RISCV_FEATURE_PMP);
 }
 
 static void rv32gcsu_priv1_10_0_cpu_init(Object *obj)
@@ -151,7 +150,6 @@ static void rv32gcsu_priv1_10_0_cpu_init(Object *obj)
     set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
     set_priv_version(env, PRIV_VERSION_1_10_0);
     set_resetvec(env, DEFAULT_RSTVEC);
-    set_feature(env, RISCV_FEATURE_PMP);
 }
 
 static void rv32imacu_nommu_cpu_init(Object *obj)
@@ -160,7 +158,6 @@ static void rv32imacu_nommu_cpu_init(Object *obj)
     set_misa(env, RV32 | RVI | RVM | RVA | RVC | RVU);
     set_priv_version(env, PRIV_VERSION_1_10_0);
     set_resetvec(env, DEFAULT_RSTVEC);
-    set_feature(env, RISCV_FEATURE_PMP);
     qdev_prop_set_bit(DEVICE(obj), "mmu", false);
 }
 
@@ -170,7 +167,6 @@ static void rv32imafcu_nommu_cpu_init(Object *obj)
     set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVC | RVU);
     set_priv_version(env, PRIV_VERSION_1_10_0);
     set_resetvec(env, DEFAULT_RSTVEC);
-    set_feature(env, RISCV_FEATURE_PMP);
     qdev_prop_set_bit(DEVICE(obj), "mmu", false);
 }
 
@@ -190,7 +186,6 @@ static void rv64gcsu_priv1_09_1_cpu_init(Object *obj)
     set_misa(env, RV64 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
     set_priv_version(env, PRIV_VERSION_1_09_1);
     set_resetvec(env, DEFAULT_RSTVEC);
-    set_feature(env, RISCV_FEATURE_PMP);
 }
 
 static void rv64gcsu_priv1_10_0_cpu_init(Object *obj)
@@ -199,7 +194,6 @@ static void rv64gcsu_priv1_10_0_cpu_init(Object *obj)
     set_misa(env, RV64 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
     set_priv_version(env, PRIV_VERSION_1_10_0);
     set_resetvec(env, DEFAULT_RSTVEC);
-    set_feature(env, RISCV_FEATURE_PMP);
 }
 
 static void rv64imacu_nommu_cpu_init(Object *obj)
@@ -208,7 +202,6 @@ static void rv64imacu_nommu_cpu_init(Object *obj)
     set_misa(env, RV64 | RVI | RVM | RVA | RVC | RVU);
     set_priv_version(env, PRIV_VERSION_1_10_0);
     set_resetvec(env, DEFAULT_RSTVEC);
-    set_feature(env, RISCV_FEATURE_PMP);
     qdev_prop_set_bit(DEVICE(obj), "mmu", false);
 }
 
-- 
2.26.2



^ permalink raw reply related	[flat|nested] 68+ messages in thread

* [PATCH v5 05/11] target/riscv: Add the lowRISC Ibex CPU
  2020-05-28 22:14 ` Alistair Francis
@ 2020-05-28 22:14   ` Alistair Francis
  -1 siblings, 0 replies; 68+ messages in thread
From: Alistair Francis @ 2020-05-28 22:14 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv; +Cc: alistair.francis, bmeng.cn, palmer, alistair23

Ibex is a small and efficient, 32-bit, in-order RISC-V core with
a 2-stage pipeline that implements the RV32IMC instruction set
architecture.

For more details on lowRISC see here:
https://github.com/lowRISC/ibex

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Bin Meng <bin.meng@windriver.com>
Reviewed-by: LIU Zhiwei <zhiwei_liu@c-sky.com>
---
 target/riscv/cpu.h |  1 +
 target/riscv/cpu.c | 10 ++++++++++
 2 files changed, 11 insertions(+)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index d0e7f5b9c5..8733d7467f 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -35,6 +35,7 @@
 #define TYPE_RISCV_CPU_ANY              RISCV_CPU_TYPE_NAME("any")
 #define TYPE_RISCV_CPU_BASE32           RISCV_CPU_TYPE_NAME("rv32")
 #define TYPE_RISCV_CPU_BASE64           RISCV_CPU_TYPE_NAME("rv64")
+#define TYPE_RISCV_CPU_IBEX             RISCV_CPU_TYPE_NAME("lowrisc-ibex")
 #define TYPE_RISCV_CPU_SIFIVE_E31       RISCV_CPU_TYPE_NAME("sifive-e31")
 #define TYPE_RISCV_CPU_SIFIVE_E34       RISCV_CPU_TYPE_NAME("sifive-e34")
 #define TYPE_RISCV_CPU_SIFIVE_E51       RISCV_CPU_TYPE_NAME("sifive-e51")
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 406e8f37d7..6e0d4d1dda 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -152,6 +152,15 @@ static void rv32gcsu_priv1_10_0_cpu_init(Object *obj)
     set_resetvec(env, DEFAULT_RSTVEC);
 }
 
+static void rv32imcu_nommu_cpu_init(Object *obj)
+{
+    CPURISCVState *env = &RISCV_CPU(obj)->env;
+    set_misa(env, RV32 | RVI | RVM | RVC | RVU);
+    set_priv_version(env, PRIV_VERSION_1_10_0);
+    set_resetvec(env, 0x8090);
+    qdev_prop_set_bit(DEVICE(obj), "mmu", false);
+}
+
 static void rv32imacu_nommu_cpu_init(Object *obj)
 {
     CPURISCVState *env = &RISCV_CPU(obj)->env;
@@ -611,6 +620,7 @@ static const TypeInfo riscv_cpu_type_infos[] = {
     DEFINE_CPU(TYPE_RISCV_CPU_ANY,              riscv_any_cpu_init),
 #if defined(TARGET_RISCV32)
     DEFINE_CPU(TYPE_RISCV_CPU_BASE32,           riscv_base32_cpu_init),
+    DEFINE_CPU(TYPE_RISCV_CPU_IBEX,             rv32imcu_nommu_cpu_init),
     DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E31,       rv32imacu_nommu_cpu_init),
     DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E34,       rv32imafcu_nommu_cpu_init),
     DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U34,       rv32gcsu_priv1_10_0_cpu_init),
-- 
2.26.2



^ permalink raw reply related	[flat|nested] 68+ messages in thread

* [PATCH v5 05/11] target/riscv: Add the lowRISC Ibex CPU
@ 2020-05-28 22:14   ` Alistair Francis
  0 siblings, 0 replies; 68+ messages in thread
From: Alistair Francis @ 2020-05-28 22:14 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv; +Cc: palmer, alistair.francis, alistair23, bmeng.cn

Ibex is a small and efficient, 32-bit, in-order RISC-V core with
a 2-stage pipeline that implements the RV32IMC instruction set
architecture.

For more details on lowRISC see here:
https://github.com/lowRISC/ibex

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Bin Meng <bin.meng@windriver.com>
Reviewed-by: LIU Zhiwei <zhiwei_liu@c-sky.com>
---
 target/riscv/cpu.h |  1 +
 target/riscv/cpu.c | 10 ++++++++++
 2 files changed, 11 insertions(+)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index d0e7f5b9c5..8733d7467f 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -35,6 +35,7 @@
 #define TYPE_RISCV_CPU_ANY              RISCV_CPU_TYPE_NAME("any")
 #define TYPE_RISCV_CPU_BASE32           RISCV_CPU_TYPE_NAME("rv32")
 #define TYPE_RISCV_CPU_BASE64           RISCV_CPU_TYPE_NAME("rv64")
+#define TYPE_RISCV_CPU_IBEX             RISCV_CPU_TYPE_NAME("lowrisc-ibex")
 #define TYPE_RISCV_CPU_SIFIVE_E31       RISCV_CPU_TYPE_NAME("sifive-e31")
 #define TYPE_RISCV_CPU_SIFIVE_E34       RISCV_CPU_TYPE_NAME("sifive-e34")
 #define TYPE_RISCV_CPU_SIFIVE_E51       RISCV_CPU_TYPE_NAME("sifive-e51")
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 406e8f37d7..6e0d4d1dda 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -152,6 +152,15 @@ static void rv32gcsu_priv1_10_0_cpu_init(Object *obj)
     set_resetvec(env, DEFAULT_RSTVEC);
 }
 
+static void rv32imcu_nommu_cpu_init(Object *obj)
+{
+    CPURISCVState *env = &RISCV_CPU(obj)->env;
+    set_misa(env, RV32 | RVI | RVM | RVC | RVU);
+    set_priv_version(env, PRIV_VERSION_1_10_0);
+    set_resetvec(env, 0x8090);
+    qdev_prop_set_bit(DEVICE(obj), "mmu", false);
+}
+
 static void rv32imacu_nommu_cpu_init(Object *obj)
 {
     CPURISCVState *env = &RISCV_CPU(obj)->env;
@@ -611,6 +620,7 @@ static const TypeInfo riscv_cpu_type_infos[] = {
     DEFINE_CPU(TYPE_RISCV_CPU_ANY,              riscv_any_cpu_init),
 #if defined(TARGET_RISCV32)
     DEFINE_CPU(TYPE_RISCV_CPU_BASE32,           riscv_base32_cpu_init),
+    DEFINE_CPU(TYPE_RISCV_CPU_IBEX,             rv32imcu_nommu_cpu_init),
     DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E31,       rv32imacu_nommu_cpu_init),
     DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E34,       rv32imafcu_nommu_cpu_init),
     DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U34,       rv32gcsu_priv1_10_0_cpu_init),
-- 
2.26.2



^ permalink raw reply related	[flat|nested] 68+ messages in thread

* [PATCH v5 06/11] riscv: Initial commit of OpenTitan machine
  2020-05-28 22:14 ` Alistair Francis
@ 2020-05-28 22:14   ` Alistair Francis
  -1 siblings, 0 replies; 68+ messages in thread
From: Alistair Francis @ 2020-05-28 22:14 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv; +Cc: alistair.francis, bmeng.cn, palmer, alistair23

This adds a barebone OpenTitan machine to QEMU.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Bin Meng <bin.meng@windriver.com>
---
 default-configs/riscv32-softmmu.mak |   1 +
 default-configs/riscv64-softmmu.mak |  11 +-
 include/hw/riscv/opentitan.h        |  68 ++++++++++
 hw/riscv/opentitan.c                | 184 ++++++++++++++++++++++++++++
 MAINTAINERS                         |   9 ++
 hw/riscv/Kconfig                    |   5 +
 hw/riscv/Makefile.objs              |   1 +
 7 files changed, 278 insertions(+), 1 deletion(-)
 create mode 100644 include/hw/riscv/opentitan.h
 create mode 100644 hw/riscv/opentitan.c

diff --git a/default-configs/riscv32-softmmu.mak b/default-configs/riscv32-softmmu.mak
index 1ae077ed87..94a236c9c2 100644
--- a/default-configs/riscv32-softmmu.mak
+++ b/default-configs/riscv32-softmmu.mak
@@ -10,3 +10,4 @@ CONFIG_SPIKE=y
 CONFIG_SIFIVE_E=y
 CONFIG_SIFIVE_U=y
 CONFIG_RISCV_VIRT=y
+CONFIG_OPENTITAN=y
diff --git a/default-configs/riscv64-softmmu.mak b/default-configs/riscv64-softmmu.mak
index 235c6f473f..aaf6d735bb 100644
--- a/default-configs/riscv64-softmmu.mak
+++ b/default-configs/riscv64-softmmu.mak
@@ -1,3 +1,12 @@
 # Default configuration for riscv64-softmmu
 
-include riscv32-softmmu.mak
+# Uncomment the following lines to disable these optional devices:
+#
+#CONFIG_PCI_DEVICES=n
+
+# Boards:
+#
+CONFIG_SPIKE=y
+CONFIG_SIFIVE_E=y
+CONFIG_SIFIVE_U=y
+CONFIG_RISCV_VIRT=y
diff --git a/include/hw/riscv/opentitan.h b/include/hw/riscv/opentitan.h
new file mode 100644
index 0000000000..a4b6499444
--- /dev/null
+++ b/include/hw/riscv/opentitan.h
@@ -0,0 +1,68 @@
+/*
+ * QEMU RISC-V Board Compatible with OpenTitan FPGA platform
+ *
+ * Copyright (c) 2020 Western Digital
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef HW_OPENTITAN_H
+#define HW_OPENTITAN_H
+
+#include "hw/riscv/riscv_hart.h"
+
+#define TYPE_RISCV_IBEX_SOC "riscv.lowrisc.ibex.soc"
+#define RISCV_IBEX_SOC(obj) \
+    OBJECT_CHECK(LowRISCIbexSoCState, (obj), TYPE_RISCV_IBEX_SOC)
+
+typedef struct LowRISCIbexSoCState {
+    /*< private >*/
+    SysBusDevice parent_obj;
+
+    /*< public >*/
+    RISCVHartArrayState cpus;
+    MemoryRegion flash_mem;
+    MemoryRegion rom;
+} LowRISCIbexSoCState;
+
+typedef struct OpenTitanState {
+    /*< private >*/
+    SysBusDevice parent_obj;
+
+    /*< public >*/
+    LowRISCIbexSoCState soc;
+} OpenTitanState;
+
+enum {
+    IBEX_ROM,
+    IBEX_RAM,
+    IBEX_FLASH,
+    IBEX_UART,
+    IBEX_GPIO,
+    IBEX_SPI,
+    IBEX_FLASH_CTRL,
+    IBEX_RV_TIMER,
+    IBEX_AES,
+    IBEX_HMAC,
+    IBEX_PLIC,
+    IBEX_PWRMGR,
+    IBEX_RSTMGR,
+    IBEX_CLKMGR,
+    IBEX_PINMUX,
+    IBEX_ALERT_HANDLER,
+    IBEX_NMI_GEN,
+    IBEX_USBDEV,
+    IBEX_PADCTRL,
+};
+
+#endif
diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c
new file mode 100644
index 0000000000..b4fb836466
--- /dev/null
+++ b/hw/riscv/opentitan.c
@@ -0,0 +1,184 @@
+/*
+ * QEMU RISC-V Board Compatible with OpenTitan FPGA platform
+ *
+ * Copyright (c) 2020 Western Digital
+ *
+ * Provides a board compatible with the OpenTitan FPGA platform:
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/riscv/opentitan.h"
+#include "qapi/error.h"
+#include "hw/boards.h"
+#include "hw/misc/unimp.h"
+#include "hw/riscv/boot.h"
+#include "exec/address-spaces.h"
+
+static const struct MemmapEntry {
+    hwaddr base;
+    hwaddr size;
+} ibex_memmap[] = {
+    [IBEX_ROM] =            {  0x00008000,   0xc000 },
+    [IBEX_RAM] =            {  0x10000000,  0x10000 },
+    [IBEX_FLASH] =          {  0x20000000,  0x80000 },
+    [IBEX_UART] =           {  0x40000000,  0x10000 },
+    [IBEX_GPIO] =           {  0x40010000,  0x10000 },
+    [IBEX_SPI] =            {  0x40020000,  0x10000 },
+    [IBEX_FLASH_CTRL] =     {  0x40030000,  0x10000 },
+    [IBEX_PINMUX] =         {  0x40070000,  0x10000 },
+    [IBEX_RV_TIMER] =       {  0x40080000,  0x10000 },
+    [IBEX_PLIC] =           {  0x40090000,  0x10000 },
+    [IBEX_PWRMGR] =         {  0x400A0000,  0x10000 },
+    [IBEX_RSTMGR] =         {  0x400B0000,  0x10000 },
+    [IBEX_CLKMGR] =         {  0x400C0000,  0x10000 },
+    [IBEX_AES] =            {  0x40110000,  0x10000 },
+    [IBEX_HMAC] =           {  0x40120000,  0x10000 },
+    [IBEX_ALERT_HANDLER] =  {  0x40130000,  0x10000 },
+    [IBEX_NMI_GEN] =        {  0x40140000,  0x10000 },
+    [IBEX_USBDEV] =         {  0x40150000,  0x10000 },
+    [IBEX_PADCTRL] =        {  0x40160000,  0x10000 }
+};
+
+static void riscv_opentitan_init(MachineState *machine)
+{
+    const struct MemmapEntry *memmap = ibex_memmap;
+    OpenTitanState *s = g_new0(OpenTitanState, 1);
+    MemoryRegion *sys_mem = get_system_memory();
+    MemoryRegion *main_mem = g_new(MemoryRegion, 1);
+
+    /* Initialize SoC */
+    object_initialize_child(OBJECT(machine), "soc", &s->soc,
+                            sizeof(s->soc), TYPE_RISCV_IBEX_SOC,
+                            &error_abort, NULL);
+    object_property_set_bool(OBJECT(&s->soc), true, "realized",
+                            &error_abort);
+
+    memory_region_init_ram(main_mem, NULL, "riscv.lowrisc.ibex.ram",
+        memmap[IBEX_RAM].size, &error_fatal);
+    memory_region_add_subregion(sys_mem,
+        memmap[IBEX_RAM].base, main_mem);
+
+
+    if (machine->firmware) {
+        riscv_load_firmware(machine->firmware, memmap[IBEX_RAM].base, NULL);
+    }
+
+    if (machine->kernel_filename) {
+        riscv_load_kernel(machine->kernel_filename, NULL);
+    }
+}
+
+static void riscv_opentitan_machine_init(MachineClass *mc)
+{
+    mc->desc = "RISC-V Board compatible with OpenTitan";
+    mc->init = riscv_opentitan_init;
+    mc->max_cpus = 1;
+    mc->default_cpu_type = TYPE_RISCV_CPU_IBEX;
+}
+
+DEFINE_MACHINE("opentitan", riscv_opentitan_machine_init)
+
+static void riscv_lowrisc_ibex_soc_init(Object *obj)
+{
+    LowRISCIbexSoCState *s = RISCV_IBEX_SOC(obj);
+
+    object_initialize_child(obj, "cpus", &s->cpus,
+                            sizeof(s->cpus), TYPE_RISCV_HART_ARRAY,
+                            &error_abort, NULL);
+}
+
+static void riscv_lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp)
+{
+    const struct MemmapEntry *memmap = ibex_memmap;
+    MachineState *ms = MACHINE(qdev_get_machine());
+    LowRISCIbexSoCState *s = RISCV_IBEX_SOC(dev_soc);
+    MemoryRegion *sys_mem = get_system_memory();
+
+    object_property_set_str(OBJECT(&s->cpus), ms->cpu_type, "cpu-type",
+                            &error_abort);
+    object_property_set_int(OBJECT(&s->cpus), ms->smp.cpus, "num-harts",
+                            &error_abort);
+    object_property_set_bool(OBJECT(&s->cpus), true, "realized",
+                            &error_abort);
+
+    /* Boot ROM */
+    memory_region_init_rom(&s->rom, OBJECT(dev_soc), "riscv.lowrisc.ibex.rom",
+                           memmap[IBEX_ROM].size, &error_fatal);
+    memory_region_add_subregion(sys_mem,
+        memmap[IBEX_ROM].base, &s->rom);
+
+    /* Flash memory */
+    memory_region_init_rom(&s->flash_mem, OBJECT(dev_soc), "riscv.lowrisc.ibex.flash",
+                           memmap[IBEX_FLASH].size, &error_fatal);
+    memory_region_add_subregion(sys_mem, memmap[IBEX_FLASH].base,
+                                &s->flash_mem);
+
+    create_unimplemented_device("riscv.lowrisc.ibex.uart",
+        memmap[IBEX_UART].base, memmap[IBEX_UART].size);
+    create_unimplemented_device("riscv.lowrisc.ibex.gpio",
+        memmap[IBEX_GPIO].base, memmap[IBEX_GPIO].size);
+    create_unimplemented_device("riscv.lowrisc.ibex.spi",
+        memmap[IBEX_SPI].base, memmap[IBEX_SPI].size);
+    create_unimplemented_device("riscv.lowrisc.ibex.flash_ctrl",
+        memmap[IBEX_FLASH_CTRL].base, memmap[IBEX_FLASH_CTRL].size);
+    create_unimplemented_device("riscv.lowrisc.ibex.rv_timer",
+        memmap[IBEX_RV_TIMER].base, memmap[IBEX_RV_TIMER].size);
+    create_unimplemented_device("riscv.lowrisc.ibex.pwrmgr",
+        memmap[IBEX_PWRMGR].base, memmap[IBEX_PWRMGR].size);
+    create_unimplemented_device("riscv.lowrisc.ibex.rstmgr",
+        memmap[IBEX_RSTMGR].base, memmap[IBEX_RSTMGR].size);
+    create_unimplemented_device("riscv.lowrisc.ibex.clkmgr",
+        memmap[IBEX_CLKMGR].base, memmap[IBEX_CLKMGR].size);
+    create_unimplemented_device("riscv.lowrisc.ibex.aes",
+        memmap[IBEX_AES].base, memmap[IBEX_AES].size);
+    create_unimplemented_device("riscv.lowrisc.ibex.hmac",
+        memmap[IBEX_HMAC].base, memmap[IBEX_HMAC].size);
+    create_unimplemented_device("riscv.lowrisc.ibex.plic",
+        memmap[IBEX_PLIC].base, memmap[IBEX_PLIC].size);
+    create_unimplemented_device("riscv.lowrisc.ibex.pinmux",
+        memmap[IBEX_PINMUX].base, memmap[IBEX_PINMUX].size);
+    create_unimplemented_device("riscv.lowrisc.ibex.alert_handler",
+        memmap[IBEX_ALERT_HANDLER].base, memmap[IBEX_ALERT_HANDLER].size);
+    create_unimplemented_device("riscv.lowrisc.ibex.nmi_gen",
+        memmap[IBEX_NMI_GEN].base, memmap[IBEX_NMI_GEN].size);
+    create_unimplemented_device("riscv.lowrisc.ibex.usbdev",
+        memmap[IBEX_USBDEV].base, memmap[IBEX_USBDEV].size);
+    create_unimplemented_device("riscv.lowrisc.ibex.padctrl",
+        memmap[IBEX_PADCTRL].base, memmap[IBEX_PADCTRL].size);
+}
+
+static void riscv_lowrisc_ibex_soc_class_init(ObjectClass *oc, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(oc);
+
+    dc->realize = riscv_lowrisc_ibex_soc_realize;
+    /* Reason: Uses serial_hds in realize function, thus can't be used twice */
+    dc->user_creatable = false;
+}
+
+static const TypeInfo riscv_lowrisc_ibex_soc_type_info = {
+    .name = TYPE_RISCV_IBEX_SOC,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(LowRISCIbexSoCState),
+    .instance_init = riscv_lowrisc_ibex_soc_init,
+    .class_init = riscv_lowrisc_ibex_soc_class_init,
+};
+
+static void riscv_lowrisc_ibex_soc_register_types(void)
+{
+    type_register_static(&riscv_lowrisc_ibex_soc_type_info);
+}
+
+type_init(riscv_lowrisc_ibex_soc_register_types)
diff --git a/MAINTAINERS b/MAINTAINERS
index 0944d9c731..3e7d9cb0a5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1238,6 +1238,15 @@ F: pc-bios/canyonlands.dt[sb]
 F: pc-bios/u-boot-sam460ex-20100605.bin
 F: roms/u-boot-sam460ex
 
+RISC-V Machines
+---------------
+OpenTitan
+M: Alistair Francis <Alistair.Francis@wdc.com>
+L: qemu-riscv@nongnu.org
+S: Supported
+F: hw/riscv/opentitan.c
+F: include/hw/riscv/opentitan.h
+
 SH4 Machines
 ------------
 R2D
diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
index ff9fbe958a..94d19571f7 100644
--- a/hw/riscv/Kconfig
+++ b/hw/riscv/Kconfig
@@ -27,6 +27,11 @@ config SPIKE
     select HTIF
     select SIFIVE
 
+config OPENTITAN
+    bool
+    select HART
+    select UNIMP
+
 config RISCV_VIRT
     bool
     imply PCI_DEVICES
diff --git a/hw/riscv/Makefile.objs b/hw/riscv/Makefile.objs
index fc3c6dd7c8..57cc708f5d 100644
--- a/hw/riscv/Makefile.objs
+++ b/hw/riscv/Makefile.objs
@@ -1,6 +1,7 @@
 obj-y += boot.o
 obj-$(CONFIG_SPIKE) += riscv_htif.o
 obj-$(CONFIG_HART) += riscv_hart.o
+obj-$(CONFIG_OPENTITAN) += opentitan.o
 obj-$(CONFIG_SIFIVE_E) += sifive_e.o
 obj-$(CONFIG_SIFIVE_E) += sifive_e_prci.o
 obj-$(CONFIG_SIFIVE) += sifive_clint.o
-- 
2.26.2



^ permalink raw reply related	[flat|nested] 68+ messages in thread

* [PATCH v5 06/11] riscv: Initial commit of OpenTitan machine
@ 2020-05-28 22:14   ` Alistair Francis
  0 siblings, 0 replies; 68+ messages in thread
From: Alistair Francis @ 2020-05-28 22:14 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv; +Cc: palmer, alistair.francis, alistair23, bmeng.cn

This adds a barebone OpenTitan machine to QEMU.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Bin Meng <bin.meng@windriver.com>
---
 default-configs/riscv32-softmmu.mak |   1 +
 default-configs/riscv64-softmmu.mak |  11 +-
 include/hw/riscv/opentitan.h        |  68 ++++++++++
 hw/riscv/opentitan.c                | 184 ++++++++++++++++++++++++++++
 MAINTAINERS                         |   9 ++
 hw/riscv/Kconfig                    |   5 +
 hw/riscv/Makefile.objs              |   1 +
 7 files changed, 278 insertions(+), 1 deletion(-)
 create mode 100644 include/hw/riscv/opentitan.h
 create mode 100644 hw/riscv/opentitan.c

diff --git a/default-configs/riscv32-softmmu.mak b/default-configs/riscv32-softmmu.mak
index 1ae077ed87..94a236c9c2 100644
--- a/default-configs/riscv32-softmmu.mak
+++ b/default-configs/riscv32-softmmu.mak
@@ -10,3 +10,4 @@ CONFIG_SPIKE=y
 CONFIG_SIFIVE_E=y
 CONFIG_SIFIVE_U=y
 CONFIG_RISCV_VIRT=y
+CONFIG_OPENTITAN=y
diff --git a/default-configs/riscv64-softmmu.mak b/default-configs/riscv64-softmmu.mak
index 235c6f473f..aaf6d735bb 100644
--- a/default-configs/riscv64-softmmu.mak
+++ b/default-configs/riscv64-softmmu.mak
@@ -1,3 +1,12 @@
 # Default configuration for riscv64-softmmu
 
-include riscv32-softmmu.mak
+# Uncomment the following lines to disable these optional devices:
+#
+#CONFIG_PCI_DEVICES=n
+
+# Boards:
+#
+CONFIG_SPIKE=y
+CONFIG_SIFIVE_E=y
+CONFIG_SIFIVE_U=y
+CONFIG_RISCV_VIRT=y
diff --git a/include/hw/riscv/opentitan.h b/include/hw/riscv/opentitan.h
new file mode 100644
index 0000000000..a4b6499444
--- /dev/null
+++ b/include/hw/riscv/opentitan.h
@@ -0,0 +1,68 @@
+/*
+ * QEMU RISC-V Board Compatible with OpenTitan FPGA platform
+ *
+ * Copyright (c) 2020 Western Digital
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef HW_OPENTITAN_H
+#define HW_OPENTITAN_H
+
+#include "hw/riscv/riscv_hart.h"
+
+#define TYPE_RISCV_IBEX_SOC "riscv.lowrisc.ibex.soc"
+#define RISCV_IBEX_SOC(obj) \
+    OBJECT_CHECK(LowRISCIbexSoCState, (obj), TYPE_RISCV_IBEX_SOC)
+
+typedef struct LowRISCIbexSoCState {
+    /*< private >*/
+    SysBusDevice parent_obj;
+
+    /*< public >*/
+    RISCVHartArrayState cpus;
+    MemoryRegion flash_mem;
+    MemoryRegion rom;
+} LowRISCIbexSoCState;
+
+typedef struct OpenTitanState {
+    /*< private >*/
+    SysBusDevice parent_obj;
+
+    /*< public >*/
+    LowRISCIbexSoCState soc;
+} OpenTitanState;
+
+enum {
+    IBEX_ROM,
+    IBEX_RAM,
+    IBEX_FLASH,
+    IBEX_UART,
+    IBEX_GPIO,
+    IBEX_SPI,
+    IBEX_FLASH_CTRL,
+    IBEX_RV_TIMER,
+    IBEX_AES,
+    IBEX_HMAC,
+    IBEX_PLIC,
+    IBEX_PWRMGR,
+    IBEX_RSTMGR,
+    IBEX_CLKMGR,
+    IBEX_PINMUX,
+    IBEX_ALERT_HANDLER,
+    IBEX_NMI_GEN,
+    IBEX_USBDEV,
+    IBEX_PADCTRL,
+};
+
+#endif
diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c
new file mode 100644
index 0000000000..b4fb836466
--- /dev/null
+++ b/hw/riscv/opentitan.c
@@ -0,0 +1,184 @@
+/*
+ * QEMU RISC-V Board Compatible with OpenTitan FPGA platform
+ *
+ * Copyright (c) 2020 Western Digital
+ *
+ * Provides a board compatible with the OpenTitan FPGA platform:
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/riscv/opentitan.h"
+#include "qapi/error.h"
+#include "hw/boards.h"
+#include "hw/misc/unimp.h"
+#include "hw/riscv/boot.h"
+#include "exec/address-spaces.h"
+
+static const struct MemmapEntry {
+    hwaddr base;
+    hwaddr size;
+} ibex_memmap[] = {
+    [IBEX_ROM] =            {  0x00008000,   0xc000 },
+    [IBEX_RAM] =            {  0x10000000,  0x10000 },
+    [IBEX_FLASH] =          {  0x20000000,  0x80000 },
+    [IBEX_UART] =           {  0x40000000,  0x10000 },
+    [IBEX_GPIO] =           {  0x40010000,  0x10000 },
+    [IBEX_SPI] =            {  0x40020000,  0x10000 },
+    [IBEX_FLASH_CTRL] =     {  0x40030000,  0x10000 },
+    [IBEX_PINMUX] =         {  0x40070000,  0x10000 },
+    [IBEX_RV_TIMER] =       {  0x40080000,  0x10000 },
+    [IBEX_PLIC] =           {  0x40090000,  0x10000 },
+    [IBEX_PWRMGR] =         {  0x400A0000,  0x10000 },
+    [IBEX_RSTMGR] =         {  0x400B0000,  0x10000 },
+    [IBEX_CLKMGR] =         {  0x400C0000,  0x10000 },
+    [IBEX_AES] =            {  0x40110000,  0x10000 },
+    [IBEX_HMAC] =           {  0x40120000,  0x10000 },
+    [IBEX_ALERT_HANDLER] =  {  0x40130000,  0x10000 },
+    [IBEX_NMI_GEN] =        {  0x40140000,  0x10000 },
+    [IBEX_USBDEV] =         {  0x40150000,  0x10000 },
+    [IBEX_PADCTRL] =        {  0x40160000,  0x10000 }
+};
+
+static void riscv_opentitan_init(MachineState *machine)
+{
+    const struct MemmapEntry *memmap = ibex_memmap;
+    OpenTitanState *s = g_new0(OpenTitanState, 1);
+    MemoryRegion *sys_mem = get_system_memory();
+    MemoryRegion *main_mem = g_new(MemoryRegion, 1);
+
+    /* Initialize SoC */
+    object_initialize_child(OBJECT(machine), "soc", &s->soc,
+                            sizeof(s->soc), TYPE_RISCV_IBEX_SOC,
+                            &error_abort, NULL);
+    object_property_set_bool(OBJECT(&s->soc), true, "realized",
+                            &error_abort);
+
+    memory_region_init_ram(main_mem, NULL, "riscv.lowrisc.ibex.ram",
+        memmap[IBEX_RAM].size, &error_fatal);
+    memory_region_add_subregion(sys_mem,
+        memmap[IBEX_RAM].base, main_mem);
+
+
+    if (machine->firmware) {
+        riscv_load_firmware(machine->firmware, memmap[IBEX_RAM].base, NULL);
+    }
+
+    if (machine->kernel_filename) {
+        riscv_load_kernel(machine->kernel_filename, NULL);
+    }
+}
+
+static void riscv_opentitan_machine_init(MachineClass *mc)
+{
+    mc->desc = "RISC-V Board compatible with OpenTitan";
+    mc->init = riscv_opentitan_init;
+    mc->max_cpus = 1;
+    mc->default_cpu_type = TYPE_RISCV_CPU_IBEX;
+}
+
+DEFINE_MACHINE("opentitan", riscv_opentitan_machine_init)
+
+static void riscv_lowrisc_ibex_soc_init(Object *obj)
+{
+    LowRISCIbexSoCState *s = RISCV_IBEX_SOC(obj);
+
+    object_initialize_child(obj, "cpus", &s->cpus,
+                            sizeof(s->cpus), TYPE_RISCV_HART_ARRAY,
+                            &error_abort, NULL);
+}
+
+static void riscv_lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp)
+{
+    const struct MemmapEntry *memmap = ibex_memmap;
+    MachineState *ms = MACHINE(qdev_get_machine());
+    LowRISCIbexSoCState *s = RISCV_IBEX_SOC(dev_soc);
+    MemoryRegion *sys_mem = get_system_memory();
+
+    object_property_set_str(OBJECT(&s->cpus), ms->cpu_type, "cpu-type",
+                            &error_abort);
+    object_property_set_int(OBJECT(&s->cpus), ms->smp.cpus, "num-harts",
+                            &error_abort);
+    object_property_set_bool(OBJECT(&s->cpus), true, "realized",
+                            &error_abort);
+
+    /* Boot ROM */
+    memory_region_init_rom(&s->rom, OBJECT(dev_soc), "riscv.lowrisc.ibex.rom",
+                           memmap[IBEX_ROM].size, &error_fatal);
+    memory_region_add_subregion(sys_mem,
+        memmap[IBEX_ROM].base, &s->rom);
+
+    /* Flash memory */
+    memory_region_init_rom(&s->flash_mem, OBJECT(dev_soc), "riscv.lowrisc.ibex.flash",
+                           memmap[IBEX_FLASH].size, &error_fatal);
+    memory_region_add_subregion(sys_mem, memmap[IBEX_FLASH].base,
+                                &s->flash_mem);
+
+    create_unimplemented_device("riscv.lowrisc.ibex.uart",
+        memmap[IBEX_UART].base, memmap[IBEX_UART].size);
+    create_unimplemented_device("riscv.lowrisc.ibex.gpio",
+        memmap[IBEX_GPIO].base, memmap[IBEX_GPIO].size);
+    create_unimplemented_device("riscv.lowrisc.ibex.spi",
+        memmap[IBEX_SPI].base, memmap[IBEX_SPI].size);
+    create_unimplemented_device("riscv.lowrisc.ibex.flash_ctrl",
+        memmap[IBEX_FLASH_CTRL].base, memmap[IBEX_FLASH_CTRL].size);
+    create_unimplemented_device("riscv.lowrisc.ibex.rv_timer",
+        memmap[IBEX_RV_TIMER].base, memmap[IBEX_RV_TIMER].size);
+    create_unimplemented_device("riscv.lowrisc.ibex.pwrmgr",
+        memmap[IBEX_PWRMGR].base, memmap[IBEX_PWRMGR].size);
+    create_unimplemented_device("riscv.lowrisc.ibex.rstmgr",
+        memmap[IBEX_RSTMGR].base, memmap[IBEX_RSTMGR].size);
+    create_unimplemented_device("riscv.lowrisc.ibex.clkmgr",
+        memmap[IBEX_CLKMGR].base, memmap[IBEX_CLKMGR].size);
+    create_unimplemented_device("riscv.lowrisc.ibex.aes",
+        memmap[IBEX_AES].base, memmap[IBEX_AES].size);
+    create_unimplemented_device("riscv.lowrisc.ibex.hmac",
+        memmap[IBEX_HMAC].base, memmap[IBEX_HMAC].size);
+    create_unimplemented_device("riscv.lowrisc.ibex.plic",
+        memmap[IBEX_PLIC].base, memmap[IBEX_PLIC].size);
+    create_unimplemented_device("riscv.lowrisc.ibex.pinmux",
+        memmap[IBEX_PINMUX].base, memmap[IBEX_PINMUX].size);
+    create_unimplemented_device("riscv.lowrisc.ibex.alert_handler",
+        memmap[IBEX_ALERT_HANDLER].base, memmap[IBEX_ALERT_HANDLER].size);
+    create_unimplemented_device("riscv.lowrisc.ibex.nmi_gen",
+        memmap[IBEX_NMI_GEN].base, memmap[IBEX_NMI_GEN].size);
+    create_unimplemented_device("riscv.lowrisc.ibex.usbdev",
+        memmap[IBEX_USBDEV].base, memmap[IBEX_USBDEV].size);
+    create_unimplemented_device("riscv.lowrisc.ibex.padctrl",
+        memmap[IBEX_PADCTRL].base, memmap[IBEX_PADCTRL].size);
+}
+
+static void riscv_lowrisc_ibex_soc_class_init(ObjectClass *oc, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(oc);
+
+    dc->realize = riscv_lowrisc_ibex_soc_realize;
+    /* Reason: Uses serial_hds in realize function, thus can't be used twice */
+    dc->user_creatable = false;
+}
+
+static const TypeInfo riscv_lowrisc_ibex_soc_type_info = {
+    .name = TYPE_RISCV_IBEX_SOC,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(LowRISCIbexSoCState),
+    .instance_init = riscv_lowrisc_ibex_soc_init,
+    .class_init = riscv_lowrisc_ibex_soc_class_init,
+};
+
+static void riscv_lowrisc_ibex_soc_register_types(void)
+{
+    type_register_static(&riscv_lowrisc_ibex_soc_type_info);
+}
+
+type_init(riscv_lowrisc_ibex_soc_register_types)
diff --git a/MAINTAINERS b/MAINTAINERS
index 0944d9c731..3e7d9cb0a5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1238,6 +1238,15 @@ F: pc-bios/canyonlands.dt[sb]
 F: pc-bios/u-boot-sam460ex-20100605.bin
 F: roms/u-boot-sam460ex
 
+RISC-V Machines
+---------------
+OpenTitan
+M: Alistair Francis <Alistair.Francis@wdc.com>
+L: qemu-riscv@nongnu.org
+S: Supported
+F: hw/riscv/opentitan.c
+F: include/hw/riscv/opentitan.h
+
 SH4 Machines
 ------------
 R2D
diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
index ff9fbe958a..94d19571f7 100644
--- a/hw/riscv/Kconfig
+++ b/hw/riscv/Kconfig
@@ -27,6 +27,11 @@ config SPIKE
     select HTIF
     select SIFIVE
 
+config OPENTITAN
+    bool
+    select HART
+    select UNIMP
+
 config RISCV_VIRT
     bool
     imply PCI_DEVICES
diff --git a/hw/riscv/Makefile.objs b/hw/riscv/Makefile.objs
index fc3c6dd7c8..57cc708f5d 100644
--- a/hw/riscv/Makefile.objs
+++ b/hw/riscv/Makefile.objs
@@ -1,6 +1,7 @@
 obj-y += boot.o
 obj-$(CONFIG_SPIKE) += riscv_htif.o
 obj-$(CONFIG_HART) += riscv_hart.o
+obj-$(CONFIG_OPENTITAN) += opentitan.o
 obj-$(CONFIG_SIFIVE_E) += sifive_e.o
 obj-$(CONFIG_SIFIVE_E) += sifive_e_prci.o
 obj-$(CONFIG_SIFIVE) += sifive_clint.o
-- 
2.26.2



^ permalink raw reply related	[flat|nested] 68+ messages in thread

* [PATCH v5 07/11] hw/char: Initial commit of Ibex UART
  2020-05-28 22:14 ` Alistair Francis
@ 2020-05-28 22:14   ` Alistair Francis
  -1 siblings, 0 replies; 68+ messages in thread
From: Alistair Francis @ 2020-05-28 22:14 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv; +Cc: alistair.francis, bmeng.cn, palmer, alistair23

This is the initial commit of the Ibex UART device. Serial TX is
working, while RX has been implemeneted but untested.

This is based on the documentation from:
https://docs.opentitan.org/hw/ip/uart/doc/

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 include/hw/char/ibex_uart.h | 110 ++++++++
 hw/char/ibex_uart.c         | 492 ++++++++++++++++++++++++++++++++++++
 MAINTAINERS                 |   2 +
 hw/char/Makefile.objs       |   1 +
 hw/riscv/Kconfig            |   4 +
 5 files changed, 609 insertions(+)
 create mode 100644 include/hw/char/ibex_uart.h
 create mode 100644 hw/char/ibex_uart.c

diff --git a/include/hw/char/ibex_uart.h b/include/hw/char/ibex_uart.h
new file mode 100644
index 0000000000..2bec772615
--- /dev/null
+++ b/include/hw/char/ibex_uart.h
@@ -0,0 +1,110 @@
+/*
+ * QEMU lowRISC Ibex UART device
+ *
+ * Copyright (c) 2020 Western Digital
+ *
+ * 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.
+ */
+
+#ifndef HW_IBEX_UART_H
+#define HW_IBEX_UART_H
+
+#include "hw/sysbus.h"
+#include "chardev/char-fe.h"
+#include "qemu/timer.h"
+
+#define IBEX_UART_INTR_STATE   0x00
+    #define INTR_STATE_TX_WATERMARK (1 << 0)
+    #define INTR_STATE_RX_WATERMARK (1 << 1)
+    #define INTR_STATE_TX_EMPTY     (1 << 2)
+    #define INTR_STATE_RX_OVERFLOW  (1 << 3)
+#define IBEX_UART_INTR_ENABLE  0x04
+#define IBEX_UART_INTR_TEST    0x08
+
+#define IBEX_UART_CTRL         0x0c
+    #define UART_CTRL_TX_ENABLE     (1 << 0)
+    #define UART_CTRL_RX_ENABLE     (1 << 1)
+    #define UART_CTRL_NF            (1 << 2)
+    #define UART_CTRL_SLPBK         (1 << 4)
+    #define UART_CTRL_LLPBK         (1 << 5)
+    #define UART_CTRL_PARITY_EN     (1 << 6)
+    #define UART_CTRL_PARITY_ODD    (1 << 7)
+    #define UART_CTRL_RXBLVL        (3 << 8)
+    #define UART_CTRL_NCO           (0xFFFF << 16)
+
+#define IBEX_UART_STATUS       0x10
+    #define UART_STATUS_TXFULL  (1 << 0)
+    #define UART_STATUS_RXFULL  (1 << 1)
+    #define UART_STATUS_TXEMPTY (1 << 2)
+    #define UART_STATUS_RXIDLE  (1 << 4)
+    #define UART_STATUS_RXEMPTY (1 << 5)
+
+#define IBEX_UART_RDATA        0x14
+#define IBEX_UART_WDATA        0x18
+
+#define IBEX_UART_FIFO_CTRL    0x1c
+    #define FIFO_CTRL_RXRST          (1 << 0)
+    #define FIFO_CTRL_TXRST          (1 << 1)
+    #define FIFO_CTRL_RXILVL         (7 << 2)
+    #define FIFO_CTRL_RXILVL_SHIFT   (2)
+    #define FIFO_CTRL_TXILVL         (3 << 5)
+    #define FIFO_CTRL_TXILVL_SHIFT   (5)
+
+#define IBEX_UART_FIFO_STATUS  0x20
+#define IBEX_UART_OVRD         0x24
+#define IBEX_UART_VAL          0x28
+#define IBEX_UART_TIMEOUT_CTRL 0x2c
+
+#define IBEX_UART_TX_FIFO_SIZE 16
+
+#define TYPE_IBEX_UART "ibex-uart"
+#define IBEX_UART(obj) \
+    OBJECT_CHECK(IbexUartState, (obj), TYPE_IBEX_UART)
+
+typedef struct {
+    /* <private> */
+    SysBusDevice parent_obj;
+
+    /* <public> */
+    MemoryRegion mmio;
+
+    uint8_t tx_fifo[IBEX_UART_TX_FIFO_SIZE];
+    uint32_t tx_level;
+
+    QEMUTimer *fifo_trigger_handle;
+    uint64_t char_tx_time;
+
+    uint32_t uart_intr_state;
+    uint32_t uart_intr_enable;
+    uint32_t uart_ctrl;
+    uint32_t uart_status;
+    uint32_t uart_rdata;
+    uint32_t uart_fifo_ctrl;
+    uint32_t uart_fifo_status;
+    uint32_t uart_ovrd;
+    uint32_t uart_val;
+    uint32_t uart_timeout_ctrl;
+
+    CharBackend chr;
+    qemu_irq tx_watermark;
+    qemu_irq rx_watermark;
+    qemu_irq tx_empty;
+    qemu_irq rx_overflow;
+} IbexUartState;
+#endif /* HW_IBEX_UART_H */
diff --git a/hw/char/ibex_uart.c b/hw/char/ibex_uart.c
new file mode 100644
index 0000000000..c416325d73
--- /dev/null
+++ b/hw/char/ibex_uart.c
@@ -0,0 +1,492 @@
+/*
+ * QEMU lowRISC Ibex UART device
+ *
+ * Copyright (c) 2020 Western Digital
+ *
+ * For details check the documentation here:
+ *    https://docs.opentitan.org/hw/ip/uart/doc/
+ *
+ * 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.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/char/ibex_uart.h"
+#include "hw/irq.h"
+#include "hw/qdev-properties.h"
+#include "migration/vmstate.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+
+static void ibex_uart_update_irqs(IbexUartState *s)
+{
+    if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_TX_WATERMARK) {
+        qemu_set_irq(s->tx_watermark, 1);
+    } else {
+        qemu_set_irq(s->tx_watermark, 0);
+    }
+
+    if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_RX_WATERMARK) {
+        qemu_set_irq(s->rx_watermark, 1);
+    } else {
+        qemu_set_irq(s->rx_watermark, 0);
+    }
+
+    if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_TX_EMPTY) {
+        qemu_set_irq(s->tx_empty, 1);
+    } else {
+        qemu_set_irq(s->tx_empty, 0);
+    }
+
+    if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_RX_OVERFLOW) {
+        qemu_set_irq(s->rx_overflow, 1);
+    } else {
+        qemu_set_irq(s->rx_overflow, 0);
+    }
+}
+
+static int ibex_uart_can_receive(void *opaque)
+{
+    IbexUartState *s = opaque;
+
+    if (s->uart_ctrl & UART_CTRL_RX_ENABLE) {
+        return 1;
+    }
+
+    return 0;
+}
+
+static void ibex_uart_receive(void *opaque, const uint8_t *buf, int size)
+{
+    IbexUartState *s = opaque;
+    uint8_t rx_fifo_level = (s->uart_fifo_ctrl & FIFO_CTRL_RXILVL)
+                            >> FIFO_CTRL_RXILVL_SHIFT;
+
+    s->uart_rdata = *buf;
+
+    s->uart_status &= ~UART_STATUS_RXIDLE;
+    s->uart_status &= ~UART_STATUS_RXEMPTY;
+
+    if (size > rx_fifo_level) {
+        s->uart_intr_state |= INTR_STATE_RX_WATERMARK;
+    }
+
+    ibex_uart_update_irqs(s);
+}
+
+static gboolean ibex_uart_xmit(GIOChannel *chan, GIOCondition cond,
+                               void *opaque)
+{
+    IbexUartState *s = opaque;
+    uint8_t tx_fifo_level = (s->uart_fifo_ctrl & FIFO_CTRL_TXILVL)
+                            >> FIFO_CTRL_TXILVL_SHIFT;
+    int ret;
+
+    /* instant drain the fifo when there's no back-end */
+    if (!qemu_chr_fe_backend_connected(&s->chr)) {
+        s->tx_level = 0;
+        return FALSE;
+    }
+
+    if (!s->tx_level) {
+        s->uart_status &= UART_STATUS_TXFULL;
+        s->uart_status |= UART_STATUS_TXEMPTY;
+        s->uart_intr_state |= INTR_STATE_TX_EMPTY;
+        s->uart_intr_state &= ~INTR_STATE_TX_WATERMARK;
+        ibex_uart_update_irqs(s);
+        return FALSE;
+    }
+
+    ret = qemu_chr_fe_write(&s->chr, s->tx_fifo, s->tx_level);
+
+    if (ret >= 0) {
+        s->tx_level -= ret;
+        memmove(s->tx_fifo, s->tx_fifo + ret, s->tx_level);
+    }
+
+    if (s->tx_level) {
+        guint r = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP,
+                                        ibex_uart_xmit, s);
+        if (!r) {
+            s->tx_level = 0;
+            return FALSE;
+        }
+    }
+
+    /* Clear the TX Full bit */
+    if (s->tx_level != IBEX_UART_TX_FIFO_SIZE) {
+        s->uart_status &= ~UART_STATUS_TXFULL;
+    }
+
+    /* Disable the TX_WATERMARK IRQ */
+    if (s->tx_level < tx_fifo_level) {
+        s->uart_intr_state &= ~INTR_STATE_TX_WATERMARK;
+    }
+
+    /* Set TX empty */
+    if (s->tx_level == 0) {
+        s->uart_status |= UART_STATUS_TXEMPTY;
+        s->uart_intr_state |= INTR_STATE_TX_EMPTY;
+    }
+
+    ibex_uart_update_irqs(s);
+    return FALSE;
+}
+
+static void uart_write_tx_fifo(IbexUartState *s, const uint8_t *buf,
+                               int size)
+{
+    uint64_t current_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+    uint8_t tx_fifo_level = (s->uart_fifo_ctrl & FIFO_CTRL_TXILVL)
+                            >> FIFO_CTRL_TXILVL_SHIFT;
+
+    if (size > IBEX_UART_TX_FIFO_SIZE - s->tx_level) {
+        size = IBEX_UART_TX_FIFO_SIZE - s->tx_level;
+        qemu_log_mask(LOG_GUEST_ERROR, "ibex_uart: TX FIFO overflow");
+    }
+
+    memcpy(s->tx_fifo + s->tx_level, buf, size);
+    s->tx_level += size;
+
+    if (s->tx_level > 0) {
+        s->uart_status &= ~UART_STATUS_TXEMPTY;
+    }
+
+    if (s->tx_level >= tx_fifo_level) {
+        s->uart_intr_state |= INTR_STATE_TX_WATERMARK;
+        ibex_uart_update_irqs(s);
+    }
+
+    if (s->tx_level == IBEX_UART_TX_FIFO_SIZE) {
+        s->uart_status |= UART_STATUS_TXFULL;
+    }
+
+    timer_mod(s->fifo_trigger_handle, current_time +
+              (s->char_tx_time * 4));
+}
+
+static void ibex_uart_reset(DeviceState *dev)
+{
+    IbexUartState *s = IBEX_UART(dev);
+
+    s->uart_intr_state = 0x00000000;
+    s->uart_intr_state = 0x00000000;
+    s->uart_intr_enable = 0x00000000;
+    s->uart_ctrl = 0x00000000;
+    s->uart_status = 0x0000003c;
+    s->uart_rdata = 0x00000000;
+    s->uart_fifo_ctrl = 0x00000000;
+    s->uart_fifo_status = 0x00000000;
+    s->uart_ovrd = 0x00000000;
+    s->uart_val = 0x00000000;
+    s->uart_timeout_ctrl = 0x00000000;
+
+    s->tx_level = 0;
+
+    s->char_tx_time = (NANOSECONDS_PER_SECOND / 230400) * 10;
+
+    ibex_uart_update_irqs(s);
+}
+
+static uint64_t ibex_uart_read(void *opaque, hwaddr addr,
+                                       unsigned int size)
+{
+    IbexUartState *s = opaque;
+    uint64_t retvalue = 0;
+
+    switch (addr) {
+    case IBEX_UART_INTR_STATE:
+        retvalue = s->uart_intr_state;
+        break;
+    case IBEX_UART_INTR_ENABLE:
+        retvalue = s->uart_intr_enable;
+        break;
+    case IBEX_UART_INTR_TEST:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: wdata is write only\n", __func__);
+        break;
+
+    case IBEX_UART_CTRL:
+        retvalue = s->uart_ctrl;
+        break;
+    case IBEX_UART_STATUS:
+        retvalue = s->uart_status;
+        break;
+
+    case IBEX_UART_RDATA:
+        retvalue = s->uart_rdata;
+        if (s->uart_ctrl & UART_CTRL_RX_ENABLE) {
+            qemu_chr_fe_accept_input(&s->chr);
+
+            s->uart_status |= UART_STATUS_RXIDLE;
+            s->uart_status |= UART_STATUS_RXEMPTY;
+        }
+        break;
+    case IBEX_UART_WDATA:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: wdata is write only\n", __func__);
+        break;
+
+    case IBEX_UART_FIFO_CTRL:
+        retvalue = s->uart_fifo_ctrl;
+        break;
+    case IBEX_UART_FIFO_STATUS:
+        retvalue = s->uart_fifo_status;
+
+        retvalue |= s->tx_level & 0x1F;
+
+        qemu_log_mask(LOG_UNIMP,
+                      "%s: RX fifos are not supported\n", __func__);
+        break;
+
+    case IBEX_UART_OVRD:
+        retvalue = s->uart_ovrd;
+        qemu_log_mask(LOG_UNIMP,
+                      "%s: ovrd is not supported\n", __func__);
+        break;
+    case IBEX_UART_VAL:
+        retvalue = s->uart_val;
+        qemu_log_mask(LOG_UNIMP,
+                      "%s: val is not supported\n", __func__);
+        break;
+    case IBEX_UART_TIMEOUT_CTRL:
+        retvalue = s->uart_timeout_ctrl;
+        qemu_log_mask(LOG_UNIMP,
+                      "%s: timeout_ctrl is not supported\n", __func__);
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
+        return 0;
+    }
+
+    return retvalue;
+}
+
+static void ibex_uart_write(void *opaque, hwaddr addr,
+                                  uint64_t val64, unsigned int size)
+{
+    IbexUartState *s = opaque;
+    uint32_t value = val64;
+
+    switch (addr) {
+    case IBEX_UART_INTR_STATE:
+        /* Write 1 clear */
+        s->uart_intr_state &= ~value;
+        ibex_uart_update_irqs(s);
+        break;
+    case IBEX_UART_INTR_ENABLE:
+        s->uart_intr_enable = value;
+        ibex_uart_update_irqs(s);
+        break;
+    case IBEX_UART_INTR_TEST:
+        s->uart_intr_state |= value;
+        ibex_uart_update_irqs(s);
+        break;
+
+    case IBEX_UART_CTRL:
+        s->uart_ctrl = value;
+
+        if (value & UART_CTRL_NF) {
+            qemu_log_mask(LOG_UNIMP,
+                          "%s: UART_CTRL_NF is not supported\n", __func__);
+        }
+        if (value & UART_CTRL_SLPBK) {
+            qemu_log_mask(LOG_UNIMP,
+                          "%s: UART_CTRL_SLPBK is not supported\n", __func__);
+        }
+        if (value & UART_CTRL_LLPBK) {
+            qemu_log_mask(LOG_UNIMP,
+                          "%s: UART_CTRL_LLPBK is not supported\n", __func__);
+        }
+        if (value & UART_CTRL_PARITY_EN) {
+            qemu_log_mask(LOG_UNIMP,
+                          "%s: UART_CTRL_PARITY_EN is not supported\n",
+                          __func__);
+        }
+        if (value & UART_CTRL_PARITY_ODD) {
+            qemu_log_mask(LOG_UNIMP,
+                          "%s: UART_CTRL_PARITY_ODD is not supported\n",
+                          __func__);
+        }
+        if (value & UART_CTRL_RXBLVL) {
+            qemu_log_mask(LOG_UNIMP,
+                          "%s: UART_CTRL_RXBLVL is not supported\n", __func__);
+        }
+        if (value & UART_CTRL_NCO) {
+            uint64_t baud = ((value & UART_CTRL_NCO) >> 16);
+            baud *= 1000;
+            baud /= 2 ^ 20;
+
+            s->char_tx_time = (NANOSECONDS_PER_SECOND / baud) * 10;
+        }
+        break;
+    case IBEX_UART_STATUS:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: status is read only\n", __func__);
+        break;
+
+    case IBEX_UART_RDATA:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: rdata is read only\n", __func__);
+        break;
+    case IBEX_UART_WDATA:
+        uart_write_tx_fifo(s, (uint8_t *) &value, 1);
+        break;
+
+    case IBEX_UART_FIFO_CTRL:
+        s->uart_fifo_ctrl = value;
+
+        if (value & FIFO_CTRL_RXRST) {
+            qemu_log_mask(LOG_UNIMP,
+                          "%s: RX fifos are not supported\n", __func__);
+        }
+        if (value & FIFO_CTRL_TXRST) {
+            s->tx_level = 0;
+        }
+        break;
+    case IBEX_UART_FIFO_STATUS:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: fifo_status is read only\n", __func__);
+        break;
+
+    case IBEX_UART_OVRD:
+        s->uart_ovrd = value;
+        qemu_log_mask(LOG_UNIMP,
+                      "%s: ovrd is not supported\n", __func__);
+        break;
+    case IBEX_UART_VAL:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: val is read only\n", __func__);
+        break;
+    case IBEX_UART_TIMEOUT_CTRL:
+        s->uart_timeout_ctrl = value;
+        qemu_log_mask(LOG_UNIMP,
+                      "%s: timeout_ctrl is not supported\n", __func__);
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
+    }
+}
+
+static void fifo_trigger_update(void *opaque)
+{
+    IbexUartState *s = opaque;
+
+    if (s->uart_ctrl & UART_CTRL_TX_ENABLE) {
+        ibex_uart_xmit(NULL, G_IO_OUT, s);
+    }
+}
+
+static const MemoryRegionOps ibex_uart_ops = {
+    .read = ibex_uart_read,
+    .write = ibex_uart_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .impl.min_access_size = 4,
+    .impl.max_access_size = 4,
+};
+
+static int cadence_uart_post_load(void *opaque, int version_id)
+{
+    IbexUartState *s = opaque;
+
+    ibex_uart_update_irqs(s);
+    return 0;
+}
+
+static const VMStateDescription vmstate_ibex_uart = {
+    .name = TYPE_IBEX_UART,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .post_load = cadence_uart_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8_ARRAY(tx_fifo, IbexUartState,
+                            IBEX_UART_TX_FIFO_SIZE),
+        VMSTATE_UINT32(tx_level, IbexUartState),
+        VMSTATE_UINT64(char_tx_time, IbexUartState),
+        VMSTATE_TIMER_PTR(fifo_trigger_handle, IbexUartState),
+        VMSTATE_UINT32(uart_intr_state, IbexUartState),
+        VMSTATE_UINT32(uart_intr_enable, IbexUartState),
+        VMSTATE_UINT32(uart_ctrl, IbexUartState),
+        VMSTATE_UINT32(uart_status, IbexUartState),
+        VMSTATE_UINT32(uart_rdata, IbexUartState),
+        VMSTATE_UINT32(uart_fifo_ctrl, IbexUartState),
+        VMSTATE_UINT32(uart_fifo_status, IbexUartState),
+        VMSTATE_UINT32(uart_ovrd, IbexUartState),
+        VMSTATE_UINT32(uart_val, IbexUartState),
+        VMSTATE_UINT32(uart_timeout_ctrl, IbexUartState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property ibex_uart_properties[] = {
+    DEFINE_PROP_CHR("chardev", IbexUartState, chr),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ibex_uart_init(Object *obj)
+{
+    IbexUartState *s = IBEX_UART(obj);
+
+    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->tx_watermark);
+    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->rx_watermark);
+    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->tx_empty);
+    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->rx_overflow);
+
+    memory_region_init_io(&s->mmio, obj, &ibex_uart_ops, s,
+                          TYPE_IBEX_UART, 0x400);
+    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
+}
+
+static void ibex_uart_realize(DeviceState *dev, Error **errp)
+{
+    IbexUartState *s = IBEX_UART(dev);
+
+    s->fifo_trigger_handle = timer_new_ns(QEMU_CLOCK_VIRTUAL,
+                                          fifo_trigger_update, s);
+
+    qemu_chr_fe_set_handlers(&s->chr, ibex_uart_can_receive,
+                             ibex_uart_receive, NULL, NULL,
+                             s, NULL, true);
+}
+
+static void ibex_uart_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->reset = ibex_uart_reset;
+    dc->realize = ibex_uart_realize;
+    dc->vmsd = &vmstate_ibex_uart;
+    device_class_set_props(dc, ibex_uart_properties);
+}
+
+static const TypeInfo ibex_uart_info = {
+    .name          = TYPE_IBEX_UART,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(IbexUartState),
+    .instance_init = ibex_uart_init,
+    .class_init    = ibex_uart_class_init,
+};
+
+static void ibex_uart_register_types(void)
+{
+    type_register_static(&ibex_uart_info);
+}
+
+type_init(ibex_uart_register_types)
diff --git a/MAINTAINERS b/MAINTAINERS
index 3e7d9cb0a5..a1ce186a7e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1245,7 +1245,9 @@ M: Alistair Francis <Alistair.Francis@wdc.com>
 L: qemu-riscv@nongnu.org
 S: Supported
 F: hw/riscv/opentitan.c
+F: hw/char/ibex_uart.c
 F: include/hw/riscv/opentitan.h
+F: include/hw/char/ibex_uart.h
 
 SH4 Machines
 ------------
diff --git a/hw/char/Makefile.objs b/hw/char/Makefile.objs
index 9e9a6c1aff..633996be5b 100644
--- a/hw/char/Makefile.objs
+++ b/hw/char/Makefile.objs
@@ -12,6 +12,7 @@ common-obj-$(CONFIG_VIRTIO_SERIAL) += virtio-console.o
 common-obj-$(CONFIG_XILINX) += xilinx_uartlite.o
 common-obj-$(CONFIG_XEN) += xen_console.o
 common-obj-$(CONFIG_CADENCE) += cadence_uart.o
+common-obj-$(CONFIG_IBEX) += ibex_uart.o
 
 common-obj-$(CONFIG_EXYNOS4) += exynos4210_uart.o
 common-obj-$(CONFIG_COLDFIRE) += mcf_uart.o
diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
index 94d19571f7..28947ef3e0 100644
--- a/hw/riscv/Kconfig
+++ b/hw/riscv/Kconfig
@@ -4,6 +4,9 @@ config HTIF
 config HART
     bool
 
+config IBEX
+    bool
+
 config SIFIVE
     bool
     select MSI_NONBROKEN
@@ -29,6 +32,7 @@ config SPIKE
 
 config OPENTITAN
     bool
+    select IBEX
     select HART
     select UNIMP
 
-- 
2.26.2



^ permalink raw reply related	[flat|nested] 68+ messages in thread

* [PATCH v5 07/11] hw/char: Initial commit of Ibex UART
@ 2020-05-28 22:14   ` Alistair Francis
  0 siblings, 0 replies; 68+ messages in thread
From: Alistair Francis @ 2020-05-28 22:14 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv; +Cc: palmer, alistair.francis, alistair23, bmeng.cn

This is the initial commit of the Ibex UART device. Serial TX is
working, while RX has been implemeneted but untested.

This is based on the documentation from:
https://docs.opentitan.org/hw/ip/uart/doc/

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 include/hw/char/ibex_uart.h | 110 ++++++++
 hw/char/ibex_uart.c         | 492 ++++++++++++++++++++++++++++++++++++
 MAINTAINERS                 |   2 +
 hw/char/Makefile.objs       |   1 +
 hw/riscv/Kconfig            |   4 +
 5 files changed, 609 insertions(+)
 create mode 100644 include/hw/char/ibex_uart.h
 create mode 100644 hw/char/ibex_uart.c

diff --git a/include/hw/char/ibex_uart.h b/include/hw/char/ibex_uart.h
new file mode 100644
index 0000000000..2bec772615
--- /dev/null
+++ b/include/hw/char/ibex_uart.h
@@ -0,0 +1,110 @@
+/*
+ * QEMU lowRISC Ibex UART device
+ *
+ * Copyright (c) 2020 Western Digital
+ *
+ * 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.
+ */
+
+#ifndef HW_IBEX_UART_H
+#define HW_IBEX_UART_H
+
+#include "hw/sysbus.h"
+#include "chardev/char-fe.h"
+#include "qemu/timer.h"
+
+#define IBEX_UART_INTR_STATE   0x00
+    #define INTR_STATE_TX_WATERMARK (1 << 0)
+    #define INTR_STATE_RX_WATERMARK (1 << 1)
+    #define INTR_STATE_TX_EMPTY     (1 << 2)
+    #define INTR_STATE_RX_OVERFLOW  (1 << 3)
+#define IBEX_UART_INTR_ENABLE  0x04
+#define IBEX_UART_INTR_TEST    0x08
+
+#define IBEX_UART_CTRL         0x0c
+    #define UART_CTRL_TX_ENABLE     (1 << 0)
+    #define UART_CTRL_RX_ENABLE     (1 << 1)
+    #define UART_CTRL_NF            (1 << 2)
+    #define UART_CTRL_SLPBK         (1 << 4)
+    #define UART_CTRL_LLPBK         (1 << 5)
+    #define UART_CTRL_PARITY_EN     (1 << 6)
+    #define UART_CTRL_PARITY_ODD    (1 << 7)
+    #define UART_CTRL_RXBLVL        (3 << 8)
+    #define UART_CTRL_NCO           (0xFFFF << 16)
+
+#define IBEX_UART_STATUS       0x10
+    #define UART_STATUS_TXFULL  (1 << 0)
+    #define UART_STATUS_RXFULL  (1 << 1)
+    #define UART_STATUS_TXEMPTY (1 << 2)
+    #define UART_STATUS_RXIDLE  (1 << 4)
+    #define UART_STATUS_RXEMPTY (1 << 5)
+
+#define IBEX_UART_RDATA        0x14
+#define IBEX_UART_WDATA        0x18
+
+#define IBEX_UART_FIFO_CTRL    0x1c
+    #define FIFO_CTRL_RXRST          (1 << 0)
+    #define FIFO_CTRL_TXRST          (1 << 1)
+    #define FIFO_CTRL_RXILVL         (7 << 2)
+    #define FIFO_CTRL_RXILVL_SHIFT   (2)
+    #define FIFO_CTRL_TXILVL         (3 << 5)
+    #define FIFO_CTRL_TXILVL_SHIFT   (5)
+
+#define IBEX_UART_FIFO_STATUS  0x20
+#define IBEX_UART_OVRD         0x24
+#define IBEX_UART_VAL          0x28
+#define IBEX_UART_TIMEOUT_CTRL 0x2c
+
+#define IBEX_UART_TX_FIFO_SIZE 16
+
+#define TYPE_IBEX_UART "ibex-uart"
+#define IBEX_UART(obj) \
+    OBJECT_CHECK(IbexUartState, (obj), TYPE_IBEX_UART)
+
+typedef struct {
+    /* <private> */
+    SysBusDevice parent_obj;
+
+    /* <public> */
+    MemoryRegion mmio;
+
+    uint8_t tx_fifo[IBEX_UART_TX_FIFO_SIZE];
+    uint32_t tx_level;
+
+    QEMUTimer *fifo_trigger_handle;
+    uint64_t char_tx_time;
+
+    uint32_t uart_intr_state;
+    uint32_t uart_intr_enable;
+    uint32_t uart_ctrl;
+    uint32_t uart_status;
+    uint32_t uart_rdata;
+    uint32_t uart_fifo_ctrl;
+    uint32_t uart_fifo_status;
+    uint32_t uart_ovrd;
+    uint32_t uart_val;
+    uint32_t uart_timeout_ctrl;
+
+    CharBackend chr;
+    qemu_irq tx_watermark;
+    qemu_irq rx_watermark;
+    qemu_irq tx_empty;
+    qemu_irq rx_overflow;
+} IbexUartState;
+#endif /* HW_IBEX_UART_H */
diff --git a/hw/char/ibex_uart.c b/hw/char/ibex_uart.c
new file mode 100644
index 0000000000..c416325d73
--- /dev/null
+++ b/hw/char/ibex_uart.c
@@ -0,0 +1,492 @@
+/*
+ * QEMU lowRISC Ibex UART device
+ *
+ * Copyright (c) 2020 Western Digital
+ *
+ * For details check the documentation here:
+ *    https://docs.opentitan.org/hw/ip/uart/doc/
+ *
+ * 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.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/char/ibex_uart.h"
+#include "hw/irq.h"
+#include "hw/qdev-properties.h"
+#include "migration/vmstate.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+
+static void ibex_uart_update_irqs(IbexUartState *s)
+{
+    if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_TX_WATERMARK) {
+        qemu_set_irq(s->tx_watermark, 1);
+    } else {
+        qemu_set_irq(s->tx_watermark, 0);
+    }
+
+    if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_RX_WATERMARK) {
+        qemu_set_irq(s->rx_watermark, 1);
+    } else {
+        qemu_set_irq(s->rx_watermark, 0);
+    }
+
+    if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_TX_EMPTY) {
+        qemu_set_irq(s->tx_empty, 1);
+    } else {
+        qemu_set_irq(s->tx_empty, 0);
+    }
+
+    if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_RX_OVERFLOW) {
+        qemu_set_irq(s->rx_overflow, 1);
+    } else {
+        qemu_set_irq(s->rx_overflow, 0);
+    }
+}
+
+static int ibex_uart_can_receive(void *opaque)
+{
+    IbexUartState *s = opaque;
+
+    if (s->uart_ctrl & UART_CTRL_RX_ENABLE) {
+        return 1;
+    }
+
+    return 0;
+}
+
+static void ibex_uart_receive(void *opaque, const uint8_t *buf, int size)
+{
+    IbexUartState *s = opaque;
+    uint8_t rx_fifo_level = (s->uart_fifo_ctrl & FIFO_CTRL_RXILVL)
+                            >> FIFO_CTRL_RXILVL_SHIFT;
+
+    s->uart_rdata = *buf;
+
+    s->uart_status &= ~UART_STATUS_RXIDLE;
+    s->uart_status &= ~UART_STATUS_RXEMPTY;
+
+    if (size > rx_fifo_level) {
+        s->uart_intr_state |= INTR_STATE_RX_WATERMARK;
+    }
+
+    ibex_uart_update_irqs(s);
+}
+
+static gboolean ibex_uart_xmit(GIOChannel *chan, GIOCondition cond,
+                               void *opaque)
+{
+    IbexUartState *s = opaque;
+    uint8_t tx_fifo_level = (s->uart_fifo_ctrl & FIFO_CTRL_TXILVL)
+                            >> FIFO_CTRL_TXILVL_SHIFT;
+    int ret;
+
+    /* instant drain the fifo when there's no back-end */
+    if (!qemu_chr_fe_backend_connected(&s->chr)) {
+        s->tx_level = 0;
+        return FALSE;
+    }
+
+    if (!s->tx_level) {
+        s->uart_status &= UART_STATUS_TXFULL;
+        s->uart_status |= UART_STATUS_TXEMPTY;
+        s->uart_intr_state |= INTR_STATE_TX_EMPTY;
+        s->uart_intr_state &= ~INTR_STATE_TX_WATERMARK;
+        ibex_uart_update_irqs(s);
+        return FALSE;
+    }
+
+    ret = qemu_chr_fe_write(&s->chr, s->tx_fifo, s->tx_level);
+
+    if (ret >= 0) {
+        s->tx_level -= ret;
+        memmove(s->tx_fifo, s->tx_fifo + ret, s->tx_level);
+    }
+
+    if (s->tx_level) {
+        guint r = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP,
+                                        ibex_uart_xmit, s);
+        if (!r) {
+            s->tx_level = 0;
+            return FALSE;
+        }
+    }
+
+    /* Clear the TX Full bit */
+    if (s->tx_level != IBEX_UART_TX_FIFO_SIZE) {
+        s->uart_status &= ~UART_STATUS_TXFULL;
+    }
+
+    /* Disable the TX_WATERMARK IRQ */
+    if (s->tx_level < tx_fifo_level) {
+        s->uart_intr_state &= ~INTR_STATE_TX_WATERMARK;
+    }
+
+    /* Set TX empty */
+    if (s->tx_level == 0) {
+        s->uart_status |= UART_STATUS_TXEMPTY;
+        s->uart_intr_state |= INTR_STATE_TX_EMPTY;
+    }
+
+    ibex_uart_update_irqs(s);
+    return FALSE;
+}
+
+static void uart_write_tx_fifo(IbexUartState *s, const uint8_t *buf,
+                               int size)
+{
+    uint64_t current_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+    uint8_t tx_fifo_level = (s->uart_fifo_ctrl & FIFO_CTRL_TXILVL)
+                            >> FIFO_CTRL_TXILVL_SHIFT;
+
+    if (size > IBEX_UART_TX_FIFO_SIZE - s->tx_level) {
+        size = IBEX_UART_TX_FIFO_SIZE - s->tx_level;
+        qemu_log_mask(LOG_GUEST_ERROR, "ibex_uart: TX FIFO overflow");
+    }
+
+    memcpy(s->tx_fifo + s->tx_level, buf, size);
+    s->tx_level += size;
+
+    if (s->tx_level > 0) {
+        s->uart_status &= ~UART_STATUS_TXEMPTY;
+    }
+
+    if (s->tx_level >= tx_fifo_level) {
+        s->uart_intr_state |= INTR_STATE_TX_WATERMARK;
+        ibex_uart_update_irqs(s);
+    }
+
+    if (s->tx_level == IBEX_UART_TX_FIFO_SIZE) {
+        s->uart_status |= UART_STATUS_TXFULL;
+    }
+
+    timer_mod(s->fifo_trigger_handle, current_time +
+              (s->char_tx_time * 4));
+}
+
+static void ibex_uart_reset(DeviceState *dev)
+{
+    IbexUartState *s = IBEX_UART(dev);
+
+    s->uart_intr_state = 0x00000000;
+    s->uart_intr_state = 0x00000000;
+    s->uart_intr_enable = 0x00000000;
+    s->uart_ctrl = 0x00000000;
+    s->uart_status = 0x0000003c;
+    s->uart_rdata = 0x00000000;
+    s->uart_fifo_ctrl = 0x00000000;
+    s->uart_fifo_status = 0x00000000;
+    s->uart_ovrd = 0x00000000;
+    s->uart_val = 0x00000000;
+    s->uart_timeout_ctrl = 0x00000000;
+
+    s->tx_level = 0;
+
+    s->char_tx_time = (NANOSECONDS_PER_SECOND / 230400) * 10;
+
+    ibex_uart_update_irqs(s);
+}
+
+static uint64_t ibex_uart_read(void *opaque, hwaddr addr,
+                                       unsigned int size)
+{
+    IbexUartState *s = opaque;
+    uint64_t retvalue = 0;
+
+    switch (addr) {
+    case IBEX_UART_INTR_STATE:
+        retvalue = s->uart_intr_state;
+        break;
+    case IBEX_UART_INTR_ENABLE:
+        retvalue = s->uart_intr_enable;
+        break;
+    case IBEX_UART_INTR_TEST:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: wdata is write only\n", __func__);
+        break;
+
+    case IBEX_UART_CTRL:
+        retvalue = s->uart_ctrl;
+        break;
+    case IBEX_UART_STATUS:
+        retvalue = s->uart_status;
+        break;
+
+    case IBEX_UART_RDATA:
+        retvalue = s->uart_rdata;
+        if (s->uart_ctrl & UART_CTRL_RX_ENABLE) {
+            qemu_chr_fe_accept_input(&s->chr);
+
+            s->uart_status |= UART_STATUS_RXIDLE;
+            s->uart_status |= UART_STATUS_RXEMPTY;
+        }
+        break;
+    case IBEX_UART_WDATA:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: wdata is write only\n", __func__);
+        break;
+
+    case IBEX_UART_FIFO_CTRL:
+        retvalue = s->uart_fifo_ctrl;
+        break;
+    case IBEX_UART_FIFO_STATUS:
+        retvalue = s->uart_fifo_status;
+
+        retvalue |= s->tx_level & 0x1F;
+
+        qemu_log_mask(LOG_UNIMP,
+                      "%s: RX fifos are not supported\n", __func__);
+        break;
+
+    case IBEX_UART_OVRD:
+        retvalue = s->uart_ovrd;
+        qemu_log_mask(LOG_UNIMP,
+                      "%s: ovrd is not supported\n", __func__);
+        break;
+    case IBEX_UART_VAL:
+        retvalue = s->uart_val;
+        qemu_log_mask(LOG_UNIMP,
+                      "%s: val is not supported\n", __func__);
+        break;
+    case IBEX_UART_TIMEOUT_CTRL:
+        retvalue = s->uart_timeout_ctrl;
+        qemu_log_mask(LOG_UNIMP,
+                      "%s: timeout_ctrl is not supported\n", __func__);
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
+        return 0;
+    }
+
+    return retvalue;
+}
+
+static void ibex_uart_write(void *opaque, hwaddr addr,
+                                  uint64_t val64, unsigned int size)
+{
+    IbexUartState *s = opaque;
+    uint32_t value = val64;
+
+    switch (addr) {
+    case IBEX_UART_INTR_STATE:
+        /* Write 1 clear */
+        s->uart_intr_state &= ~value;
+        ibex_uart_update_irqs(s);
+        break;
+    case IBEX_UART_INTR_ENABLE:
+        s->uart_intr_enable = value;
+        ibex_uart_update_irqs(s);
+        break;
+    case IBEX_UART_INTR_TEST:
+        s->uart_intr_state |= value;
+        ibex_uart_update_irqs(s);
+        break;
+
+    case IBEX_UART_CTRL:
+        s->uart_ctrl = value;
+
+        if (value & UART_CTRL_NF) {
+            qemu_log_mask(LOG_UNIMP,
+                          "%s: UART_CTRL_NF is not supported\n", __func__);
+        }
+        if (value & UART_CTRL_SLPBK) {
+            qemu_log_mask(LOG_UNIMP,
+                          "%s: UART_CTRL_SLPBK is not supported\n", __func__);
+        }
+        if (value & UART_CTRL_LLPBK) {
+            qemu_log_mask(LOG_UNIMP,
+                          "%s: UART_CTRL_LLPBK is not supported\n", __func__);
+        }
+        if (value & UART_CTRL_PARITY_EN) {
+            qemu_log_mask(LOG_UNIMP,
+                          "%s: UART_CTRL_PARITY_EN is not supported\n",
+                          __func__);
+        }
+        if (value & UART_CTRL_PARITY_ODD) {
+            qemu_log_mask(LOG_UNIMP,
+                          "%s: UART_CTRL_PARITY_ODD is not supported\n",
+                          __func__);
+        }
+        if (value & UART_CTRL_RXBLVL) {
+            qemu_log_mask(LOG_UNIMP,
+                          "%s: UART_CTRL_RXBLVL is not supported\n", __func__);
+        }
+        if (value & UART_CTRL_NCO) {
+            uint64_t baud = ((value & UART_CTRL_NCO) >> 16);
+            baud *= 1000;
+            baud /= 2 ^ 20;
+
+            s->char_tx_time = (NANOSECONDS_PER_SECOND / baud) * 10;
+        }
+        break;
+    case IBEX_UART_STATUS:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: status is read only\n", __func__);
+        break;
+
+    case IBEX_UART_RDATA:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: rdata is read only\n", __func__);
+        break;
+    case IBEX_UART_WDATA:
+        uart_write_tx_fifo(s, (uint8_t *) &value, 1);
+        break;
+
+    case IBEX_UART_FIFO_CTRL:
+        s->uart_fifo_ctrl = value;
+
+        if (value & FIFO_CTRL_RXRST) {
+            qemu_log_mask(LOG_UNIMP,
+                          "%s: RX fifos are not supported\n", __func__);
+        }
+        if (value & FIFO_CTRL_TXRST) {
+            s->tx_level = 0;
+        }
+        break;
+    case IBEX_UART_FIFO_STATUS:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: fifo_status is read only\n", __func__);
+        break;
+
+    case IBEX_UART_OVRD:
+        s->uart_ovrd = value;
+        qemu_log_mask(LOG_UNIMP,
+                      "%s: ovrd is not supported\n", __func__);
+        break;
+    case IBEX_UART_VAL:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: val is read only\n", __func__);
+        break;
+    case IBEX_UART_TIMEOUT_CTRL:
+        s->uart_timeout_ctrl = value;
+        qemu_log_mask(LOG_UNIMP,
+                      "%s: timeout_ctrl is not supported\n", __func__);
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
+    }
+}
+
+static void fifo_trigger_update(void *opaque)
+{
+    IbexUartState *s = opaque;
+
+    if (s->uart_ctrl & UART_CTRL_TX_ENABLE) {
+        ibex_uart_xmit(NULL, G_IO_OUT, s);
+    }
+}
+
+static const MemoryRegionOps ibex_uart_ops = {
+    .read = ibex_uart_read,
+    .write = ibex_uart_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .impl.min_access_size = 4,
+    .impl.max_access_size = 4,
+};
+
+static int cadence_uart_post_load(void *opaque, int version_id)
+{
+    IbexUartState *s = opaque;
+
+    ibex_uart_update_irqs(s);
+    return 0;
+}
+
+static const VMStateDescription vmstate_ibex_uart = {
+    .name = TYPE_IBEX_UART,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .post_load = cadence_uart_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8_ARRAY(tx_fifo, IbexUartState,
+                            IBEX_UART_TX_FIFO_SIZE),
+        VMSTATE_UINT32(tx_level, IbexUartState),
+        VMSTATE_UINT64(char_tx_time, IbexUartState),
+        VMSTATE_TIMER_PTR(fifo_trigger_handle, IbexUartState),
+        VMSTATE_UINT32(uart_intr_state, IbexUartState),
+        VMSTATE_UINT32(uart_intr_enable, IbexUartState),
+        VMSTATE_UINT32(uart_ctrl, IbexUartState),
+        VMSTATE_UINT32(uart_status, IbexUartState),
+        VMSTATE_UINT32(uart_rdata, IbexUartState),
+        VMSTATE_UINT32(uart_fifo_ctrl, IbexUartState),
+        VMSTATE_UINT32(uart_fifo_status, IbexUartState),
+        VMSTATE_UINT32(uart_ovrd, IbexUartState),
+        VMSTATE_UINT32(uart_val, IbexUartState),
+        VMSTATE_UINT32(uart_timeout_ctrl, IbexUartState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property ibex_uart_properties[] = {
+    DEFINE_PROP_CHR("chardev", IbexUartState, chr),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ibex_uart_init(Object *obj)
+{
+    IbexUartState *s = IBEX_UART(obj);
+
+    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->tx_watermark);
+    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->rx_watermark);
+    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->tx_empty);
+    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->rx_overflow);
+
+    memory_region_init_io(&s->mmio, obj, &ibex_uart_ops, s,
+                          TYPE_IBEX_UART, 0x400);
+    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
+}
+
+static void ibex_uart_realize(DeviceState *dev, Error **errp)
+{
+    IbexUartState *s = IBEX_UART(dev);
+
+    s->fifo_trigger_handle = timer_new_ns(QEMU_CLOCK_VIRTUAL,
+                                          fifo_trigger_update, s);
+
+    qemu_chr_fe_set_handlers(&s->chr, ibex_uart_can_receive,
+                             ibex_uart_receive, NULL, NULL,
+                             s, NULL, true);
+}
+
+static void ibex_uart_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->reset = ibex_uart_reset;
+    dc->realize = ibex_uart_realize;
+    dc->vmsd = &vmstate_ibex_uart;
+    device_class_set_props(dc, ibex_uart_properties);
+}
+
+static const TypeInfo ibex_uart_info = {
+    .name          = TYPE_IBEX_UART,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(IbexUartState),
+    .instance_init = ibex_uart_init,
+    .class_init    = ibex_uart_class_init,
+};
+
+static void ibex_uart_register_types(void)
+{
+    type_register_static(&ibex_uart_info);
+}
+
+type_init(ibex_uart_register_types)
diff --git a/MAINTAINERS b/MAINTAINERS
index 3e7d9cb0a5..a1ce186a7e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1245,7 +1245,9 @@ M: Alistair Francis <Alistair.Francis@wdc.com>
 L: qemu-riscv@nongnu.org
 S: Supported
 F: hw/riscv/opentitan.c
+F: hw/char/ibex_uart.c
 F: include/hw/riscv/opentitan.h
+F: include/hw/char/ibex_uart.h
 
 SH4 Machines
 ------------
diff --git a/hw/char/Makefile.objs b/hw/char/Makefile.objs
index 9e9a6c1aff..633996be5b 100644
--- a/hw/char/Makefile.objs
+++ b/hw/char/Makefile.objs
@@ -12,6 +12,7 @@ common-obj-$(CONFIG_VIRTIO_SERIAL) += virtio-console.o
 common-obj-$(CONFIG_XILINX) += xilinx_uartlite.o
 common-obj-$(CONFIG_XEN) += xen_console.o
 common-obj-$(CONFIG_CADENCE) += cadence_uart.o
+common-obj-$(CONFIG_IBEX) += ibex_uart.o
 
 common-obj-$(CONFIG_EXYNOS4) += exynos4210_uart.o
 common-obj-$(CONFIG_COLDFIRE) += mcf_uart.o
diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
index 94d19571f7..28947ef3e0 100644
--- a/hw/riscv/Kconfig
+++ b/hw/riscv/Kconfig
@@ -4,6 +4,9 @@ config HTIF
 config HART
     bool
 
+config IBEX
+    bool
+
 config SIFIVE
     bool
     select MSI_NONBROKEN
@@ -29,6 +32,7 @@ config SPIKE
 
 config OPENTITAN
     bool
+    select IBEX
     select HART
     select UNIMP
 
-- 
2.26.2



^ permalink raw reply related	[flat|nested] 68+ messages in thread

* [PATCH v5 08/11] hw/intc: Initial commit of lowRISC Ibex PLIC
  2020-05-28 22:14 ` Alistair Francis
@ 2020-05-28 22:14   ` Alistair Francis
  -1 siblings, 0 replies; 68+ messages in thread
From: Alistair Francis @ 2020-05-28 22:14 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv; +Cc: alistair.francis, bmeng.cn, palmer, alistair23

The Ibex core contains a PLIC that although similar to the RISC-V spec
is not RISC-V spec compliant.

This patch implements a Ibex PLIC in a somewhat generic way.

As the current RISC-V PLIC needs tidying up, my hope is that as the Ibex
PLIC move towards spec compliance this PLIC implementation can be
updated until it can replace the current PLIC.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 include/hw/intc/ibex_plic.h |  63 +++++++++
 hw/intc/ibex_plic.c         | 261 ++++++++++++++++++++++++++++++++++++
 MAINTAINERS                 |   2 +
 hw/intc/Makefile.objs       |   1 +
 4 files changed, 327 insertions(+)
 create mode 100644 include/hw/intc/ibex_plic.h
 create mode 100644 hw/intc/ibex_plic.c

diff --git a/include/hw/intc/ibex_plic.h b/include/hw/intc/ibex_plic.h
new file mode 100644
index 0000000000..ddc7909903
--- /dev/null
+++ b/include/hw/intc/ibex_plic.h
@@ -0,0 +1,63 @@
+/*
+ * QEMU RISC-V lowRISC Ibex PLIC
+ *
+ * Copyright (c) 2020 Western Digital
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef HW_IBEX_PLIC_H
+#define HW_IBEX_PLIC_H
+
+#include "hw/sysbus.h"
+
+#define TYPE_IBEX_PLIC "ibex-plic"
+#define IBEX_PLIC(obj) \
+    OBJECT_CHECK(IbexPlicState, (obj), TYPE_IBEX_PLIC)
+
+typedef struct IbexPlicState {
+    /*< private >*/
+    SysBusDevice parent_obj;
+
+    /*< public >*/
+    MemoryRegion mmio;
+
+    uint32_t *pending;
+    uint32_t *source;
+    uint32_t *priority;
+    uint32_t *enable;
+    uint32_t threshold;
+    uint32_t claim;
+
+    /* config */
+    uint32_t num_cpus;
+    uint32_t num_sources;
+
+    uint32_t pending_base;
+    uint32_t pending_num;
+
+    uint32_t source_base;
+    uint32_t source_num;
+
+    uint32_t priority_base;
+    uint32_t priority_num;
+
+    uint32_t enable_base;
+    uint32_t enable_num;
+
+    uint32_t threshold_base;
+
+    uint32_t claim_base;
+} IbexPlicState;
+
+#endif /* HW_IBEX_PLIC_H */
diff --git a/hw/intc/ibex_plic.c b/hw/intc/ibex_plic.c
new file mode 100644
index 0000000000..41079518c6
--- /dev/null
+++ b/hw/intc/ibex_plic.c
@@ -0,0 +1,261 @@
+/*
+ * QEMU RISC-V lowRISC Ibex PLIC
+ *
+ * Copyright (c) 2020 Western Digital
+ *
+ * Documentation avaliable: https://docs.opentitan.org/hw/ip/rv_plic/doc/
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "hw/qdev-properties.h"
+#include "hw/core/cpu.h"
+#include "hw/boards.h"
+#include "hw/pci/msi.h"
+#include "target/riscv/cpu_bits.h"
+#include "target/riscv/cpu.h"
+#include "hw/intc/ibex_plic.h"
+
+static bool addr_between(uint32_t addr, uint32_t base, uint32_t num)
+{
+    uint32_t end = base + (num * 0x04);
+
+    if (addr >= base && addr < end) {
+        return true;
+    }
+
+    return false;
+}
+
+static void ibex_plic_irqs_set_pending(IbexPlicState *s, int irq, bool level)
+{
+    int pending_num = irq / 32;
+
+    s->pending[pending_num] |= level << (irq % 32);
+}
+
+static bool ibex_plic_irqs_pending(IbexPlicState *s, uint32_t context)
+{
+    int i;
+
+    for (i = 0; i < s->pending_num; i++) {
+        uint32_t irq_num = ctz64(s->pending[i]) + (i * 32);
+
+        if (!(s->pending[i] & s->enable[i])) {
+            /* No pending and enabled IRQ */
+            continue;
+        }
+
+        if (s->priority[irq_num] > s->threshold) {
+            if (!s->claim) {
+                s->claim = irq_num;
+            }
+            return true;
+        }
+    }
+
+    return false;
+}
+
+static void ibex_plic_update(IbexPlicState *s)
+{
+    CPUState *cpu;
+    int level, i;
+
+    for (i = 0; i < s->num_cpus; i++) {
+        cpu = qemu_get_cpu(i);
+
+        if (!cpu) {
+            continue;
+        }
+
+        level = ibex_plic_irqs_pending(s, 0);
+
+        riscv_cpu_update_mip(RISCV_CPU(cpu), MIP_MEIP, BOOL_TO_MASK(level));
+    }
+}
+
+static void ibex_plic_reset(DeviceState *dev)
+{
+    IbexPlicState *s = IBEX_PLIC(dev);
+
+    s->threshold = 0x00000000;
+    s->claim = 0x00000000;
+}
+
+static uint64_t ibex_plic_read(void *opaque, hwaddr addr,
+                               unsigned int size)
+{
+    IbexPlicState *s = opaque;
+    int offset;
+    uint32_t ret = 0;
+
+    if (addr_between(addr, s->pending_base, s->pending_num)) {
+        offset = (addr - s->pending_base) / 4;
+        ret = s->pending[offset];
+    } else if (addr_between(addr, s->source_base, s->source_num)) {
+        qemu_log_mask(LOG_UNIMP,
+                      "%s: Interrupt source mode not supported\n", __func__);
+    } else if (addr_between(addr, s->priority_base, s->priority_num)) {
+        offset = (addr - s->priority_base) / 4;
+        ret = s->priority[offset];
+    } else if (addr_between(addr, s->enable_base, s->enable_num)) {
+        offset = (addr - s->enable_base) / 4;
+        ret = s->enable[offset];
+    } else if (addr_between(addr, s->threshold_base, 1)) {
+        ret = s->threshold;
+    } else if (addr_between(addr, s->claim_base, 1)) {
+        int pending_num = s->claim / 32;
+        s->pending[pending_num] &= ~(1 << (s->claim % 32));
+
+        ret = s->claim;
+    }
+
+    return ret;
+}
+
+static void ibex_plic_write(void *opaque, hwaddr addr,
+                            uint64_t value, unsigned int size)
+{
+    IbexPlicState *s = opaque;
+
+    if (addr_between(addr, s->pending_base, s->pending_num)) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: Pending registers are read only\n", __func__);
+    } else if (addr_between(addr, s->source_base, s->source_num)) {
+        qemu_log_mask(LOG_UNIMP,
+                      "%s: Interrupt source mode not supported\n", __func__);
+    } else if (addr_between(addr, s->priority_base, s->priority_num)) {
+        uint32_t irq = ((addr - s->priority_base) >> 2) + 1;
+        s->priority[irq] = value & 7;
+    } else if (addr_between(addr, s->enable_base, s->enable_num)) {
+        uint32_t enable_reg = (addr - s->enable_base) / 4;
+
+        s->enable[enable_reg] = value;
+    } else if (addr_between(addr, s->threshold_base, 1)) {
+        s->threshold = value & 3;
+    } else if (addr_between(addr, s->claim_base, 1)) {
+        if (s->claim == value) {
+            /* Interrupt was completed */
+            s->claim = 0;
+        }
+    }
+
+    ibex_plic_update(s);
+}
+
+static const MemoryRegionOps ibex_plic_ops = {
+    .read = ibex_plic_read,
+    .write = ibex_plic_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4
+    }
+};
+
+static void ibex_plic_irq_request(void *opaque, int irq, int level)
+{
+    IbexPlicState *s = opaque;
+
+    ibex_plic_irqs_set_pending(s, irq, level > 0);
+    ibex_plic_update(s);
+}
+
+static Property ibex_plic_properties[] = {
+    DEFINE_PROP_UINT32("num-cpus", IbexPlicState, num_cpus, 1),
+    DEFINE_PROP_UINT32("num-sources", IbexPlicState, num_sources, 80),
+
+    DEFINE_PROP_UINT32("pending-base", IbexPlicState, pending_base, 0),
+    DEFINE_PROP_UINT32("pending-num", IbexPlicState, pending_num, 3),
+
+    DEFINE_PROP_UINT32("source-base", IbexPlicState, source_base, 0x0c),
+    DEFINE_PROP_UINT32("source-num", IbexPlicState, source_num, 3),
+
+    DEFINE_PROP_UINT32("priority-base", IbexPlicState, priority_base, 0x18),
+    DEFINE_PROP_UINT32("priority-num", IbexPlicState, priority_num, 80),
+
+    DEFINE_PROP_UINT32("enable-base", IbexPlicState, enable_base, 0x200),
+    DEFINE_PROP_UINT32("enable-num", IbexPlicState, enable_num, 3),
+
+    DEFINE_PROP_UINT32("threshold-base", IbexPlicState, threshold_base, 0x20c),
+
+    DEFINE_PROP_UINT32("claim-base", IbexPlicState, claim_base, 0x210),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ibex_plic_init(Object *obj)
+{
+    IbexPlicState *s = IBEX_PLIC(obj);
+
+    memory_region_init_io(&s->mmio, obj, &ibex_plic_ops, s,
+                          TYPE_IBEX_PLIC, 0x400);
+    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
+}
+
+static void ibex_plic_realize(DeviceState *dev, Error **errp)
+{
+    IbexPlicState *s = IBEX_PLIC(dev);
+    int i;
+
+    s->pending = g_new0(uint32_t, s->pending_num);
+    s->source = g_new0(uint32_t, s->source_num);
+    s->priority = g_new0(uint32_t, s->priority_num);
+    s->enable = g_new0(uint32_t, s->enable_num);
+
+    qdev_init_gpio_in(dev, ibex_plic_irq_request, s->num_sources);
+
+    /*
+     * We can't allow the supervisor to control SEIP as this would allow the
+     * supervisor to clear a pending external interrupt which will result in
+     * a lost interrupt in the case a PLIC is attached. The SEIP bit must be
+     * hardware controlled when a PLIC is attached.
+     */
+    MachineState *ms = MACHINE(qdev_get_machine());
+    unsigned int smp_cpus = ms->smp.cpus;
+    for (i = 0; i < smp_cpus; i++) {
+        RISCVCPU *cpu = RISCV_CPU(qemu_get_cpu(i));
+        if (riscv_cpu_claim_interrupts(cpu, MIP_SEIP) < 0) {
+            error_report("SEIP already claimed");
+            exit(1);
+        }
+    }
+
+    msi_nonbroken = true;
+}
+
+static void ibex_plic_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->reset = ibex_plic_reset;
+    device_class_set_props(dc, ibex_plic_properties);
+    dc->realize = ibex_plic_realize;
+}
+
+static const TypeInfo ibex_plic_info = {
+    .name          = TYPE_IBEX_PLIC,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(IbexPlicState),
+    .instance_init = ibex_plic_init,
+    .class_init    = ibex_plic_class_init,
+};
+
+static void ibex_plic_register_types(void)
+{
+    type_register_static(&ibex_plic_info);
+}
+
+type_init(ibex_plic_register_types)
diff --git a/MAINTAINERS b/MAINTAINERS
index a1ce186a7e..d6b2819e44 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1246,8 +1246,10 @@ L: qemu-riscv@nongnu.org
 S: Supported
 F: hw/riscv/opentitan.c
 F: hw/char/ibex_uart.c
+F: hw/intc/ibex_plic.c
 F: include/hw/riscv/opentitan.h
 F: include/hw/char/ibex_uart.h
+F: include/hw/intc/ibex_plic.h
 
 SH4 Machines
 ------------
diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs
index f726d87532..a61e6728fe 100644
--- a/hw/intc/Makefile.objs
+++ b/hw/intc/Makefile.objs
@@ -49,3 +49,4 @@ obj-$(CONFIG_ARM_GIC) += arm_gicv3_cpuif.o
 obj-$(CONFIG_MIPS_CPS) += mips_gic.o
 obj-$(CONFIG_NIOS2) += nios2_iic.o
 obj-$(CONFIG_OMPIC) += ompic.o
+obj-$(CONFIG_IBEX) += ibex_plic.o
-- 
2.26.2



^ permalink raw reply related	[flat|nested] 68+ messages in thread

* [PATCH v5 08/11] hw/intc: Initial commit of lowRISC Ibex PLIC
@ 2020-05-28 22:14   ` Alistair Francis
  0 siblings, 0 replies; 68+ messages in thread
From: Alistair Francis @ 2020-05-28 22:14 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv; +Cc: palmer, alistair.francis, alistair23, bmeng.cn

The Ibex core contains a PLIC that although similar to the RISC-V spec
is not RISC-V spec compliant.

This patch implements a Ibex PLIC in a somewhat generic way.

As the current RISC-V PLIC needs tidying up, my hope is that as the Ibex
PLIC move towards spec compliance this PLIC implementation can be
updated until it can replace the current PLIC.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 include/hw/intc/ibex_plic.h |  63 +++++++++
 hw/intc/ibex_plic.c         | 261 ++++++++++++++++++++++++++++++++++++
 MAINTAINERS                 |   2 +
 hw/intc/Makefile.objs       |   1 +
 4 files changed, 327 insertions(+)
 create mode 100644 include/hw/intc/ibex_plic.h
 create mode 100644 hw/intc/ibex_plic.c

diff --git a/include/hw/intc/ibex_plic.h b/include/hw/intc/ibex_plic.h
new file mode 100644
index 0000000000..ddc7909903
--- /dev/null
+++ b/include/hw/intc/ibex_plic.h
@@ -0,0 +1,63 @@
+/*
+ * QEMU RISC-V lowRISC Ibex PLIC
+ *
+ * Copyright (c) 2020 Western Digital
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef HW_IBEX_PLIC_H
+#define HW_IBEX_PLIC_H
+
+#include "hw/sysbus.h"
+
+#define TYPE_IBEX_PLIC "ibex-plic"
+#define IBEX_PLIC(obj) \
+    OBJECT_CHECK(IbexPlicState, (obj), TYPE_IBEX_PLIC)
+
+typedef struct IbexPlicState {
+    /*< private >*/
+    SysBusDevice parent_obj;
+
+    /*< public >*/
+    MemoryRegion mmio;
+
+    uint32_t *pending;
+    uint32_t *source;
+    uint32_t *priority;
+    uint32_t *enable;
+    uint32_t threshold;
+    uint32_t claim;
+
+    /* config */
+    uint32_t num_cpus;
+    uint32_t num_sources;
+
+    uint32_t pending_base;
+    uint32_t pending_num;
+
+    uint32_t source_base;
+    uint32_t source_num;
+
+    uint32_t priority_base;
+    uint32_t priority_num;
+
+    uint32_t enable_base;
+    uint32_t enable_num;
+
+    uint32_t threshold_base;
+
+    uint32_t claim_base;
+} IbexPlicState;
+
+#endif /* HW_IBEX_PLIC_H */
diff --git a/hw/intc/ibex_plic.c b/hw/intc/ibex_plic.c
new file mode 100644
index 0000000000..41079518c6
--- /dev/null
+++ b/hw/intc/ibex_plic.c
@@ -0,0 +1,261 @@
+/*
+ * QEMU RISC-V lowRISC Ibex PLIC
+ *
+ * Copyright (c) 2020 Western Digital
+ *
+ * Documentation avaliable: https://docs.opentitan.org/hw/ip/rv_plic/doc/
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "hw/qdev-properties.h"
+#include "hw/core/cpu.h"
+#include "hw/boards.h"
+#include "hw/pci/msi.h"
+#include "target/riscv/cpu_bits.h"
+#include "target/riscv/cpu.h"
+#include "hw/intc/ibex_plic.h"
+
+static bool addr_between(uint32_t addr, uint32_t base, uint32_t num)
+{
+    uint32_t end = base + (num * 0x04);
+
+    if (addr >= base && addr < end) {
+        return true;
+    }
+
+    return false;
+}
+
+static void ibex_plic_irqs_set_pending(IbexPlicState *s, int irq, bool level)
+{
+    int pending_num = irq / 32;
+
+    s->pending[pending_num] |= level << (irq % 32);
+}
+
+static bool ibex_plic_irqs_pending(IbexPlicState *s, uint32_t context)
+{
+    int i;
+
+    for (i = 0; i < s->pending_num; i++) {
+        uint32_t irq_num = ctz64(s->pending[i]) + (i * 32);
+
+        if (!(s->pending[i] & s->enable[i])) {
+            /* No pending and enabled IRQ */
+            continue;
+        }
+
+        if (s->priority[irq_num] > s->threshold) {
+            if (!s->claim) {
+                s->claim = irq_num;
+            }
+            return true;
+        }
+    }
+
+    return false;
+}
+
+static void ibex_plic_update(IbexPlicState *s)
+{
+    CPUState *cpu;
+    int level, i;
+
+    for (i = 0; i < s->num_cpus; i++) {
+        cpu = qemu_get_cpu(i);
+
+        if (!cpu) {
+            continue;
+        }
+
+        level = ibex_plic_irqs_pending(s, 0);
+
+        riscv_cpu_update_mip(RISCV_CPU(cpu), MIP_MEIP, BOOL_TO_MASK(level));
+    }
+}
+
+static void ibex_plic_reset(DeviceState *dev)
+{
+    IbexPlicState *s = IBEX_PLIC(dev);
+
+    s->threshold = 0x00000000;
+    s->claim = 0x00000000;
+}
+
+static uint64_t ibex_plic_read(void *opaque, hwaddr addr,
+                               unsigned int size)
+{
+    IbexPlicState *s = opaque;
+    int offset;
+    uint32_t ret = 0;
+
+    if (addr_between(addr, s->pending_base, s->pending_num)) {
+        offset = (addr - s->pending_base) / 4;
+        ret = s->pending[offset];
+    } else if (addr_between(addr, s->source_base, s->source_num)) {
+        qemu_log_mask(LOG_UNIMP,
+                      "%s: Interrupt source mode not supported\n", __func__);
+    } else if (addr_between(addr, s->priority_base, s->priority_num)) {
+        offset = (addr - s->priority_base) / 4;
+        ret = s->priority[offset];
+    } else if (addr_between(addr, s->enable_base, s->enable_num)) {
+        offset = (addr - s->enable_base) / 4;
+        ret = s->enable[offset];
+    } else if (addr_between(addr, s->threshold_base, 1)) {
+        ret = s->threshold;
+    } else if (addr_between(addr, s->claim_base, 1)) {
+        int pending_num = s->claim / 32;
+        s->pending[pending_num] &= ~(1 << (s->claim % 32));
+
+        ret = s->claim;
+    }
+
+    return ret;
+}
+
+static void ibex_plic_write(void *opaque, hwaddr addr,
+                            uint64_t value, unsigned int size)
+{
+    IbexPlicState *s = opaque;
+
+    if (addr_between(addr, s->pending_base, s->pending_num)) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: Pending registers are read only\n", __func__);
+    } else if (addr_between(addr, s->source_base, s->source_num)) {
+        qemu_log_mask(LOG_UNIMP,
+                      "%s: Interrupt source mode not supported\n", __func__);
+    } else if (addr_between(addr, s->priority_base, s->priority_num)) {
+        uint32_t irq = ((addr - s->priority_base) >> 2) + 1;
+        s->priority[irq] = value & 7;
+    } else if (addr_between(addr, s->enable_base, s->enable_num)) {
+        uint32_t enable_reg = (addr - s->enable_base) / 4;
+
+        s->enable[enable_reg] = value;
+    } else if (addr_between(addr, s->threshold_base, 1)) {
+        s->threshold = value & 3;
+    } else if (addr_between(addr, s->claim_base, 1)) {
+        if (s->claim == value) {
+            /* Interrupt was completed */
+            s->claim = 0;
+        }
+    }
+
+    ibex_plic_update(s);
+}
+
+static const MemoryRegionOps ibex_plic_ops = {
+    .read = ibex_plic_read,
+    .write = ibex_plic_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4
+    }
+};
+
+static void ibex_plic_irq_request(void *opaque, int irq, int level)
+{
+    IbexPlicState *s = opaque;
+
+    ibex_plic_irqs_set_pending(s, irq, level > 0);
+    ibex_plic_update(s);
+}
+
+static Property ibex_plic_properties[] = {
+    DEFINE_PROP_UINT32("num-cpus", IbexPlicState, num_cpus, 1),
+    DEFINE_PROP_UINT32("num-sources", IbexPlicState, num_sources, 80),
+
+    DEFINE_PROP_UINT32("pending-base", IbexPlicState, pending_base, 0),
+    DEFINE_PROP_UINT32("pending-num", IbexPlicState, pending_num, 3),
+
+    DEFINE_PROP_UINT32("source-base", IbexPlicState, source_base, 0x0c),
+    DEFINE_PROP_UINT32("source-num", IbexPlicState, source_num, 3),
+
+    DEFINE_PROP_UINT32("priority-base", IbexPlicState, priority_base, 0x18),
+    DEFINE_PROP_UINT32("priority-num", IbexPlicState, priority_num, 80),
+
+    DEFINE_PROP_UINT32("enable-base", IbexPlicState, enable_base, 0x200),
+    DEFINE_PROP_UINT32("enable-num", IbexPlicState, enable_num, 3),
+
+    DEFINE_PROP_UINT32("threshold-base", IbexPlicState, threshold_base, 0x20c),
+
+    DEFINE_PROP_UINT32("claim-base", IbexPlicState, claim_base, 0x210),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ibex_plic_init(Object *obj)
+{
+    IbexPlicState *s = IBEX_PLIC(obj);
+
+    memory_region_init_io(&s->mmio, obj, &ibex_plic_ops, s,
+                          TYPE_IBEX_PLIC, 0x400);
+    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
+}
+
+static void ibex_plic_realize(DeviceState *dev, Error **errp)
+{
+    IbexPlicState *s = IBEX_PLIC(dev);
+    int i;
+
+    s->pending = g_new0(uint32_t, s->pending_num);
+    s->source = g_new0(uint32_t, s->source_num);
+    s->priority = g_new0(uint32_t, s->priority_num);
+    s->enable = g_new0(uint32_t, s->enable_num);
+
+    qdev_init_gpio_in(dev, ibex_plic_irq_request, s->num_sources);
+
+    /*
+     * We can't allow the supervisor to control SEIP as this would allow the
+     * supervisor to clear a pending external interrupt which will result in
+     * a lost interrupt in the case a PLIC is attached. The SEIP bit must be
+     * hardware controlled when a PLIC is attached.
+     */
+    MachineState *ms = MACHINE(qdev_get_machine());
+    unsigned int smp_cpus = ms->smp.cpus;
+    for (i = 0; i < smp_cpus; i++) {
+        RISCVCPU *cpu = RISCV_CPU(qemu_get_cpu(i));
+        if (riscv_cpu_claim_interrupts(cpu, MIP_SEIP) < 0) {
+            error_report("SEIP already claimed");
+            exit(1);
+        }
+    }
+
+    msi_nonbroken = true;
+}
+
+static void ibex_plic_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->reset = ibex_plic_reset;
+    device_class_set_props(dc, ibex_plic_properties);
+    dc->realize = ibex_plic_realize;
+}
+
+static const TypeInfo ibex_plic_info = {
+    .name          = TYPE_IBEX_PLIC,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(IbexPlicState),
+    .instance_init = ibex_plic_init,
+    .class_init    = ibex_plic_class_init,
+};
+
+static void ibex_plic_register_types(void)
+{
+    type_register_static(&ibex_plic_info);
+}
+
+type_init(ibex_plic_register_types)
diff --git a/MAINTAINERS b/MAINTAINERS
index a1ce186a7e..d6b2819e44 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1246,8 +1246,10 @@ L: qemu-riscv@nongnu.org
 S: Supported
 F: hw/riscv/opentitan.c
 F: hw/char/ibex_uart.c
+F: hw/intc/ibex_plic.c
 F: include/hw/riscv/opentitan.h
 F: include/hw/char/ibex_uart.h
+F: include/hw/intc/ibex_plic.h
 
 SH4 Machines
 ------------
diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs
index f726d87532..a61e6728fe 100644
--- a/hw/intc/Makefile.objs
+++ b/hw/intc/Makefile.objs
@@ -49,3 +49,4 @@ obj-$(CONFIG_ARM_GIC) += arm_gicv3_cpuif.o
 obj-$(CONFIG_MIPS_CPS) += mips_gic.o
 obj-$(CONFIG_NIOS2) += nios2_iic.o
 obj-$(CONFIG_OMPIC) += ompic.o
+obj-$(CONFIG_IBEX) += ibex_plic.o
-- 
2.26.2



^ permalink raw reply related	[flat|nested] 68+ messages in thread

* [PATCH v5 09/11] riscv/opentitan: Connect the PLIC device
  2020-05-28 22:14 ` Alistair Francis
@ 2020-05-28 22:14   ` Alistair Francis
  -1 siblings, 0 replies; 68+ messages in thread
From: Alistair Francis @ 2020-05-28 22:14 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv; +Cc: alistair.francis, bmeng.cn, palmer, alistair23

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Bin Meng <bin.meng@windriver.com>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
---
 include/hw/riscv/opentitan.h |  3 +++
 hw/riscv/opentitan.c         | 19 +++++++++++++++++--
 2 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/include/hw/riscv/opentitan.h b/include/hw/riscv/opentitan.h
index a4b6499444..76f72905a8 100644
--- a/include/hw/riscv/opentitan.h
+++ b/include/hw/riscv/opentitan.h
@@ -20,6 +20,7 @@
 #define HW_OPENTITAN_H
 
 #include "hw/riscv/riscv_hart.h"
+#include "hw/intc/ibex_plic.h"
 
 #define TYPE_RISCV_IBEX_SOC "riscv.lowrisc.ibex.soc"
 #define RISCV_IBEX_SOC(obj) \
@@ -31,6 +32,8 @@ typedef struct LowRISCIbexSoCState {
 
     /*< public >*/
     RISCVHartArrayState cpus;
+    IbexPlicState plic;
+
     MemoryRegion flash_mem;
     MemoryRegion rom;
 } LowRISCIbexSoCState;
diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c
index b4fb836466..46a3a93c5e 100644
--- a/hw/riscv/opentitan.c
+++ b/hw/riscv/opentitan.c
@@ -25,6 +25,7 @@
 #include "hw/misc/unimp.h"
 #include "hw/riscv/boot.h"
 #include "exec/address-spaces.h"
+#include "sysemu/sysemu.h"
 
 static const struct MemmapEntry {
     hwaddr base;
@@ -97,6 +98,9 @@ static void riscv_lowrisc_ibex_soc_init(Object *obj)
     object_initialize_child(obj, "cpus", &s->cpus,
                             sizeof(s->cpus), TYPE_RISCV_HART_ARRAY,
                             &error_abort, NULL);
+
+    sysbus_init_child_obj(obj, "plic", &s->plic,
+                          sizeof(s->plic), TYPE_IBEX_PLIC);
 }
 
 static void riscv_lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp)
@@ -105,6 +109,9 @@ static void riscv_lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp)
     MachineState *ms = MACHINE(qdev_get_machine());
     LowRISCIbexSoCState *s = RISCV_IBEX_SOC(dev_soc);
     MemoryRegion *sys_mem = get_system_memory();
+    DeviceState *dev;
+    SysBusDevice *busdev;
+    Error *err = NULL;
 
     object_property_set_str(OBJECT(&s->cpus), ms->cpu_type, "cpu-type",
                             &error_abort);
@@ -125,6 +132,16 @@ static void riscv_lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp)
     memory_region_add_subregion(sys_mem, memmap[IBEX_FLASH].base,
                                 &s->flash_mem);
 
+    /* PLIC */
+    dev = DEVICE(&s->plic);
+    object_property_set_bool(OBJECT(&s->plic), true, "realized", &err);
+    if (err != NULL) {
+        error_propagate(errp, err);
+        return;
+    }
+    busdev = SYS_BUS_DEVICE(dev);
+    sysbus_mmio_map(busdev, 0, memmap[IBEX_PLIC].base);
+
     create_unimplemented_device("riscv.lowrisc.ibex.uart",
         memmap[IBEX_UART].base, memmap[IBEX_UART].size);
     create_unimplemented_device("riscv.lowrisc.ibex.gpio",
@@ -145,8 +162,6 @@ static void riscv_lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp)
         memmap[IBEX_AES].base, memmap[IBEX_AES].size);
     create_unimplemented_device("riscv.lowrisc.ibex.hmac",
         memmap[IBEX_HMAC].base, memmap[IBEX_HMAC].size);
-    create_unimplemented_device("riscv.lowrisc.ibex.plic",
-        memmap[IBEX_PLIC].base, memmap[IBEX_PLIC].size);
     create_unimplemented_device("riscv.lowrisc.ibex.pinmux",
         memmap[IBEX_PINMUX].base, memmap[IBEX_PINMUX].size);
     create_unimplemented_device("riscv.lowrisc.ibex.alert_handler",
-- 
2.26.2



^ permalink raw reply related	[flat|nested] 68+ messages in thread

* [PATCH v5 09/11] riscv/opentitan: Connect the PLIC device
@ 2020-05-28 22:14   ` Alistair Francis
  0 siblings, 0 replies; 68+ messages in thread
From: Alistair Francis @ 2020-05-28 22:14 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv; +Cc: palmer, alistair.francis, alistair23, bmeng.cn

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Bin Meng <bin.meng@windriver.com>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
---
 include/hw/riscv/opentitan.h |  3 +++
 hw/riscv/opentitan.c         | 19 +++++++++++++++++--
 2 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/include/hw/riscv/opentitan.h b/include/hw/riscv/opentitan.h
index a4b6499444..76f72905a8 100644
--- a/include/hw/riscv/opentitan.h
+++ b/include/hw/riscv/opentitan.h
@@ -20,6 +20,7 @@
 #define HW_OPENTITAN_H
 
 #include "hw/riscv/riscv_hart.h"
+#include "hw/intc/ibex_plic.h"
 
 #define TYPE_RISCV_IBEX_SOC "riscv.lowrisc.ibex.soc"
 #define RISCV_IBEX_SOC(obj) \
@@ -31,6 +32,8 @@ typedef struct LowRISCIbexSoCState {
 
     /*< public >*/
     RISCVHartArrayState cpus;
+    IbexPlicState plic;
+
     MemoryRegion flash_mem;
     MemoryRegion rom;
 } LowRISCIbexSoCState;
diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c
index b4fb836466..46a3a93c5e 100644
--- a/hw/riscv/opentitan.c
+++ b/hw/riscv/opentitan.c
@@ -25,6 +25,7 @@
 #include "hw/misc/unimp.h"
 #include "hw/riscv/boot.h"
 #include "exec/address-spaces.h"
+#include "sysemu/sysemu.h"
 
 static const struct MemmapEntry {
     hwaddr base;
@@ -97,6 +98,9 @@ static void riscv_lowrisc_ibex_soc_init(Object *obj)
     object_initialize_child(obj, "cpus", &s->cpus,
                             sizeof(s->cpus), TYPE_RISCV_HART_ARRAY,
                             &error_abort, NULL);
+
+    sysbus_init_child_obj(obj, "plic", &s->plic,
+                          sizeof(s->plic), TYPE_IBEX_PLIC);
 }
 
 static void riscv_lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp)
@@ -105,6 +109,9 @@ static void riscv_lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp)
     MachineState *ms = MACHINE(qdev_get_machine());
     LowRISCIbexSoCState *s = RISCV_IBEX_SOC(dev_soc);
     MemoryRegion *sys_mem = get_system_memory();
+    DeviceState *dev;
+    SysBusDevice *busdev;
+    Error *err = NULL;
 
     object_property_set_str(OBJECT(&s->cpus), ms->cpu_type, "cpu-type",
                             &error_abort);
@@ -125,6 +132,16 @@ static void riscv_lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp)
     memory_region_add_subregion(sys_mem, memmap[IBEX_FLASH].base,
                                 &s->flash_mem);
 
+    /* PLIC */
+    dev = DEVICE(&s->plic);
+    object_property_set_bool(OBJECT(&s->plic), true, "realized", &err);
+    if (err != NULL) {
+        error_propagate(errp, err);
+        return;
+    }
+    busdev = SYS_BUS_DEVICE(dev);
+    sysbus_mmio_map(busdev, 0, memmap[IBEX_PLIC].base);
+
     create_unimplemented_device("riscv.lowrisc.ibex.uart",
         memmap[IBEX_UART].base, memmap[IBEX_UART].size);
     create_unimplemented_device("riscv.lowrisc.ibex.gpio",
@@ -145,8 +162,6 @@ static void riscv_lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp)
         memmap[IBEX_AES].base, memmap[IBEX_AES].size);
     create_unimplemented_device("riscv.lowrisc.ibex.hmac",
         memmap[IBEX_HMAC].base, memmap[IBEX_HMAC].size);
-    create_unimplemented_device("riscv.lowrisc.ibex.plic",
-        memmap[IBEX_PLIC].base, memmap[IBEX_PLIC].size);
     create_unimplemented_device("riscv.lowrisc.ibex.pinmux",
         memmap[IBEX_PINMUX].base, memmap[IBEX_PINMUX].size);
     create_unimplemented_device("riscv.lowrisc.ibex.alert_handler",
-- 
2.26.2



^ permalink raw reply related	[flat|nested] 68+ messages in thread

* [PATCH v5 10/11] riscv/opentitan: Connect the UART device
  2020-05-28 22:14 ` Alistair Francis
@ 2020-05-28 22:14   ` Alistair Francis
  -1 siblings, 0 replies; 68+ messages in thread
From: Alistair Francis @ 2020-05-28 22:14 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv; +Cc: alistair.francis, bmeng.cn, palmer, alistair23

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Bin Meng <bin.meng@windriver.com>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
---
 include/hw/riscv/opentitan.h | 13 +++++++++++++
 hw/riscv/opentitan.c         | 24 ++++++++++++++++++++++--
 2 files changed, 35 insertions(+), 2 deletions(-)

diff --git a/include/hw/riscv/opentitan.h b/include/hw/riscv/opentitan.h
index 76f72905a8..8f29b9cbbf 100644
--- a/include/hw/riscv/opentitan.h
+++ b/include/hw/riscv/opentitan.h
@@ -21,6 +21,7 @@
 
 #include "hw/riscv/riscv_hart.h"
 #include "hw/intc/ibex_plic.h"
+#include "hw/char/ibex_uart.h"
 
 #define TYPE_RISCV_IBEX_SOC "riscv.lowrisc.ibex.soc"
 #define RISCV_IBEX_SOC(obj) \
@@ -33,6 +34,7 @@ typedef struct LowRISCIbexSoCState {
     /*< public >*/
     RISCVHartArrayState cpus;
     IbexPlicState plic;
+    IbexUartState uart;
 
     MemoryRegion flash_mem;
     MemoryRegion rom;
@@ -68,4 +70,15 @@ enum {
     IBEX_PADCTRL,
 };
 
+enum {
+    IBEX_UART_RX_PARITY_ERR_IRQ = 0x28,
+    IBEX_UART_RX_TIMEOUT_IRQ = 0x27,
+    IBEX_UART_RX_BREAK_ERR_IRQ = 0x26,
+    IBEX_UART_RX_FRAME_ERR_IRQ = 0x25,
+    IBEX_UART_RX_OVERFLOW_IRQ = 0x24,
+    IBEX_UART_TX_EMPTY_IRQ = 0x23,
+    IBEX_UART_RX_WATERMARK_IRQ = 0x22,
+    IBEX_UART_TX_WATERMARK_IRQ = 0x21,
+};
+
 #endif
diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c
index 46a3a93c5e..a8844a870b 100644
--- a/hw/riscv/opentitan.c
+++ b/hw/riscv/opentitan.c
@@ -101,6 +101,9 @@ static void riscv_lowrisc_ibex_soc_init(Object *obj)
 
     sysbus_init_child_obj(obj, "plic", &s->plic,
                           sizeof(s->plic), TYPE_IBEX_PLIC);
+
+    sysbus_init_child_obj(obj, "uart", &s->uart,
+                          sizeof(s->uart), TYPE_IBEX_UART);
 }
 
 static void riscv_lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp)
@@ -142,8 +145,25 @@ static void riscv_lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp)
     busdev = SYS_BUS_DEVICE(dev);
     sysbus_mmio_map(busdev, 0, memmap[IBEX_PLIC].base);
 
-    create_unimplemented_device("riscv.lowrisc.ibex.uart",
-        memmap[IBEX_UART].base, memmap[IBEX_UART].size);
+    /* UART */
+    dev = DEVICE(&(s->uart));
+    qdev_prop_set_chr(dev, "chardev", serial_hd(0));
+    object_property_set_bool(OBJECT(&s->uart), true, "realized", &err);
+    if (err != NULL) {
+        error_propagate(errp, err);
+        return;
+    }
+    busdev = SYS_BUS_DEVICE(dev);
+    sysbus_mmio_map(busdev, 0, memmap[IBEX_UART].base);
+    sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(DEVICE(&s->plic),
+                       IBEX_UART_TX_WATERMARK_IRQ));
+    sysbus_connect_irq(busdev, 1, qdev_get_gpio_in(DEVICE(&s->plic),
+                       IBEX_UART_RX_WATERMARK_IRQ));
+    sysbus_connect_irq(busdev, 2, qdev_get_gpio_in(DEVICE(&s->plic),
+                       IBEX_UART_TX_EMPTY_IRQ));
+    sysbus_connect_irq(busdev, 3, qdev_get_gpio_in(DEVICE(&s->plic),
+                       IBEX_UART_RX_OVERFLOW_IRQ));
+
     create_unimplemented_device("riscv.lowrisc.ibex.gpio",
         memmap[IBEX_GPIO].base, memmap[IBEX_GPIO].size);
     create_unimplemented_device("riscv.lowrisc.ibex.spi",
-- 
2.26.2



^ permalink raw reply related	[flat|nested] 68+ messages in thread

* [PATCH v5 10/11] riscv/opentitan: Connect the UART device
@ 2020-05-28 22:14   ` Alistair Francis
  0 siblings, 0 replies; 68+ messages in thread
From: Alistair Francis @ 2020-05-28 22:14 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv; +Cc: palmer, alistair.francis, alistair23, bmeng.cn

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Bin Meng <bin.meng@windriver.com>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
---
 include/hw/riscv/opentitan.h | 13 +++++++++++++
 hw/riscv/opentitan.c         | 24 ++++++++++++++++++++++--
 2 files changed, 35 insertions(+), 2 deletions(-)

diff --git a/include/hw/riscv/opentitan.h b/include/hw/riscv/opentitan.h
index 76f72905a8..8f29b9cbbf 100644
--- a/include/hw/riscv/opentitan.h
+++ b/include/hw/riscv/opentitan.h
@@ -21,6 +21,7 @@
 
 #include "hw/riscv/riscv_hart.h"
 #include "hw/intc/ibex_plic.h"
+#include "hw/char/ibex_uart.h"
 
 #define TYPE_RISCV_IBEX_SOC "riscv.lowrisc.ibex.soc"
 #define RISCV_IBEX_SOC(obj) \
@@ -33,6 +34,7 @@ typedef struct LowRISCIbexSoCState {
     /*< public >*/
     RISCVHartArrayState cpus;
     IbexPlicState plic;
+    IbexUartState uart;
 
     MemoryRegion flash_mem;
     MemoryRegion rom;
@@ -68,4 +70,15 @@ enum {
     IBEX_PADCTRL,
 };
 
+enum {
+    IBEX_UART_RX_PARITY_ERR_IRQ = 0x28,
+    IBEX_UART_RX_TIMEOUT_IRQ = 0x27,
+    IBEX_UART_RX_BREAK_ERR_IRQ = 0x26,
+    IBEX_UART_RX_FRAME_ERR_IRQ = 0x25,
+    IBEX_UART_RX_OVERFLOW_IRQ = 0x24,
+    IBEX_UART_TX_EMPTY_IRQ = 0x23,
+    IBEX_UART_RX_WATERMARK_IRQ = 0x22,
+    IBEX_UART_TX_WATERMARK_IRQ = 0x21,
+};
+
 #endif
diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c
index 46a3a93c5e..a8844a870b 100644
--- a/hw/riscv/opentitan.c
+++ b/hw/riscv/opentitan.c
@@ -101,6 +101,9 @@ static void riscv_lowrisc_ibex_soc_init(Object *obj)
 
     sysbus_init_child_obj(obj, "plic", &s->plic,
                           sizeof(s->plic), TYPE_IBEX_PLIC);
+
+    sysbus_init_child_obj(obj, "uart", &s->uart,
+                          sizeof(s->uart), TYPE_IBEX_UART);
 }
 
 static void riscv_lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp)
@@ -142,8 +145,25 @@ static void riscv_lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp)
     busdev = SYS_BUS_DEVICE(dev);
     sysbus_mmio_map(busdev, 0, memmap[IBEX_PLIC].base);
 
-    create_unimplemented_device("riscv.lowrisc.ibex.uart",
-        memmap[IBEX_UART].base, memmap[IBEX_UART].size);
+    /* UART */
+    dev = DEVICE(&(s->uart));
+    qdev_prop_set_chr(dev, "chardev", serial_hd(0));
+    object_property_set_bool(OBJECT(&s->uart), true, "realized", &err);
+    if (err != NULL) {
+        error_propagate(errp, err);
+        return;
+    }
+    busdev = SYS_BUS_DEVICE(dev);
+    sysbus_mmio_map(busdev, 0, memmap[IBEX_UART].base);
+    sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(DEVICE(&s->plic),
+                       IBEX_UART_TX_WATERMARK_IRQ));
+    sysbus_connect_irq(busdev, 1, qdev_get_gpio_in(DEVICE(&s->plic),
+                       IBEX_UART_RX_WATERMARK_IRQ));
+    sysbus_connect_irq(busdev, 2, qdev_get_gpio_in(DEVICE(&s->plic),
+                       IBEX_UART_TX_EMPTY_IRQ));
+    sysbus_connect_irq(busdev, 3, qdev_get_gpio_in(DEVICE(&s->plic),
+                       IBEX_UART_RX_OVERFLOW_IRQ));
+
     create_unimplemented_device("riscv.lowrisc.ibex.gpio",
         memmap[IBEX_GPIO].base, memmap[IBEX_GPIO].size);
     create_unimplemented_device("riscv.lowrisc.ibex.spi",
-- 
2.26.2



^ permalink raw reply related	[flat|nested] 68+ messages in thread

* [PATCH v5 11/11] target/riscv: Use a smaller guess size for no-MMU PMP
  2020-05-28 22:14 ` Alistair Francis
@ 2020-05-28 22:14   ` Alistair Francis
  -1 siblings, 0 replies; 68+ messages in thread
From: Alistair Francis @ 2020-05-28 22:14 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv; +Cc: alistair.francis, bmeng.cn, palmer, alistair23

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Bin Meng <bin.meng@windriver.com>
---
 target/riscv/pmp.c | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c
index 0e6b640fbd..9418660f1b 100644
--- a/target/riscv/pmp.c
+++ b/target/riscv/pmp.c
@@ -233,12 +233,16 @@ bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr,
         return true;
     }
 
-    /*
-     * if size is unknown (0), assume that all bytes
-     * from addr to the end of the page will be accessed.
-     */
     if (size == 0) {
-        pmp_size = -(addr | TARGET_PAGE_MASK);
+        if (riscv_feature(env, RISCV_FEATURE_MMU)) {
+            /*
+             * If size is unknown (0), assume that all bytes
+             * from addr to the end of the page will be accessed.
+             */
+            pmp_size = -(addr | TARGET_PAGE_MASK);
+        } else {
+            pmp_size = sizeof(target_ulong);
+        }
     } else {
         pmp_size = size;
     }
-- 
2.26.2



^ permalink raw reply related	[flat|nested] 68+ messages in thread

* [PATCH v5 11/11] target/riscv: Use a smaller guess size for no-MMU PMP
@ 2020-05-28 22:14   ` Alistair Francis
  0 siblings, 0 replies; 68+ messages in thread
From: Alistair Francis @ 2020-05-28 22:14 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv; +Cc: palmer, alistair.francis, alistair23, bmeng.cn

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Bin Meng <bin.meng@windriver.com>
---
 target/riscv/pmp.c | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c
index 0e6b640fbd..9418660f1b 100644
--- a/target/riscv/pmp.c
+++ b/target/riscv/pmp.c
@@ -233,12 +233,16 @@ bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr,
         return true;
     }
 
-    /*
-     * if size is unknown (0), assume that all bytes
-     * from addr to the end of the page will be accessed.
-     */
     if (size == 0) {
-        pmp_size = -(addr | TARGET_PAGE_MASK);
+        if (riscv_feature(env, RISCV_FEATURE_MMU)) {
+            /*
+             * If size is unknown (0), assume that all bytes
+             * from addr to the end of the page will be accessed.
+             */
+            pmp_size = -(addr | TARGET_PAGE_MASK);
+        } else {
+            pmp_size = sizeof(target_ulong);
+        }
     } else {
         pmp_size = size;
     }
-- 
2.26.2



^ permalink raw reply related	[flat|nested] 68+ messages in thread

* Re: [PATCH v5 03/11] target/riscv: Disable the MMU correctly
  2020-05-28 22:14   ` Alistair Francis
@ 2020-06-01  5:24     ` Bin Meng
  -1 siblings, 0 replies; 68+ messages in thread
From: Bin Meng @ 2020-06-01  5:24 UTC (permalink / raw)
  To: Alistair Francis
  Cc: Palmer Dabbelt, open list:RISC-V,
	qemu-devel@nongnu.org Developers, Alistair Francis

On Fri, May 29, 2020 at 6:22 AM Alistair Francis
<alistair.francis@wdc.com> wrote:
>
> Previously if we didn't enable the MMU it would be enabled in the
> realize() function anyway. Let's ensure that if we don't want the MMU we
> disable it. We also don't need to enable the MMU as it will be enalbed

typo: enabled

> in realize() by default.
>
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
>  target/riscv/cpu.c | 7 +++----
>  1 file changed, 3 insertions(+), 4 deletions(-)
>

Reviewed-by: Bin Meng <bin.meng@windriver.com>


^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v5 03/11] target/riscv: Disable the MMU correctly
@ 2020-06-01  5:24     ` Bin Meng
  0 siblings, 0 replies; 68+ messages in thread
From: Bin Meng @ 2020-06-01  5:24 UTC (permalink / raw)
  To: Alistair Francis
  Cc: qemu-devel@nongnu.org Developers, open list:RISC-V,
	Palmer Dabbelt, Alistair Francis

On Fri, May 29, 2020 at 6:22 AM Alistair Francis
<alistair.francis@wdc.com> wrote:
>
> Previously if we didn't enable the MMU it would be enabled in the
> realize() function anyway. Let's ensure that if we don't want the MMU we
> disable it. We also don't need to enable the MMU as it will be enalbed

typo: enabled

> in realize() by default.
>
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
>  target/riscv/cpu.c | 7 +++----
>  1 file changed, 3 insertions(+), 4 deletions(-)
>

Reviewed-by: Bin Meng <bin.meng@windriver.com>


^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v5 04/11] target/riscv: Don't set PMP feature in the cpu init
  2020-05-28 22:14   ` Alistair Francis
@ 2020-06-01  5:26     ` Bin Meng
  -1 siblings, 0 replies; 68+ messages in thread
From: Bin Meng @ 2020-06-01  5:26 UTC (permalink / raw)
  To: Alistair Francis
  Cc: Palmer Dabbelt, open list:RISC-V,
	qemu-devel@nongnu.org Developers, Alistair Francis

On Fri, May 29, 2020 at 6:22 AM Alistair Francis
<alistair.francis@wdc.com> wrote:
>
> The PMP is enabled by default via the "pmp" property so there is no need
> for us to set it in the init function. As all CPUs have PMP support just
> remove the set_feature() call in the CPU init functions.
>
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
>  target/riscv/cpu.c | 7 -------
>  1 file changed, 7 deletions(-)
>

Reviewed-by: Bin Meng <bin.meng@windriver.com>


^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v5 04/11] target/riscv: Don't set PMP feature in the cpu init
@ 2020-06-01  5:26     ` Bin Meng
  0 siblings, 0 replies; 68+ messages in thread
From: Bin Meng @ 2020-06-01  5:26 UTC (permalink / raw)
  To: Alistair Francis
  Cc: qemu-devel@nongnu.org Developers, open list:RISC-V,
	Palmer Dabbelt, Alistair Francis

On Fri, May 29, 2020 at 6:22 AM Alistair Francis
<alistair.francis@wdc.com> wrote:
>
> The PMP is enabled by default via the "pmp" property so there is no need
> for us to set it in the init function. As all CPUs have PMP support just
> remove the set_feature() call in the CPU init functions.
>
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
>  target/riscv/cpu.c | 7 -------
>  1 file changed, 7 deletions(-)
>

Reviewed-by: Bin Meng <bin.meng@windriver.com>


^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v5 07/11] hw/char: Initial commit of Ibex UART
  2020-05-28 22:14   ` Alistair Francis
@ 2020-06-01 21:23     ` Alistair Francis
  -1 siblings, 0 replies; 68+ messages in thread
From: Alistair Francis @ 2020-06-01 21:23 UTC (permalink / raw)
  To: Alistair Francis, Philippe Mathieu-Daudé
  Cc: Palmer Dabbelt, Bin Meng, open list:RISC-V,
	qemu-devel@nongnu.org Developers

On Thu, May 28, 2020 at 3:23 PM Alistair Francis
<alistair.francis@wdc.com> wrote:
>
> This is the initial commit of the Ibex UART device. Serial TX is
> working, while RX has been implemeneted but untested.
>
> This is based on the documentation from:
> https://docs.opentitan.org/hw/ip/uart/doc/
>
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>

Ping! This is the last patch not reviewed.

Alistair

> ---
>  include/hw/char/ibex_uart.h | 110 ++++++++
>  hw/char/ibex_uart.c         | 492 ++++++++++++++++++++++++++++++++++++
>  MAINTAINERS                 |   2 +
>  hw/char/Makefile.objs       |   1 +
>  hw/riscv/Kconfig            |   4 +
>  5 files changed, 609 insertions(+)
>  create mode 100644 include/hw/char/ibex_uart.h
>  create mode 100644 hw/char/ibex_uart.c
>
> diff --git a/include/hw/char/ibex_uart.h b/include/hw/char/ibex_uart.h
> new file mode 100644
> index 0000000000..2bec772615
> --- /dev/null
> +++ b/include/hw/char/ibex_uart.h
> @@ -0,0 +1,110 @@
> +/*
> + * QEMU lowRISC Ibex UART device
> + *
> + * Copyright (c) 2020 Western Digital
> + *
> + * 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.
> + */
> +
> +#ifndef HW_IBEX_UART_H
> +#define HW_IBEX_UART_H
> +
> +#include "hw/sysbus.h"
> +#include "chardev/char-fe.h"
> +#include "qemu/timer.h"
> +
> +#define IBEX_UART_INTR_STATE   0x00
> +    #define INTR_STATE_TX_WATERMARK (1 << 0)
> +    #define INTR_STATE_RX_WATERMARK (1 << 1)
> +    #define INTR_STATE_TX_EMPTY     (1 << 2)
> +    #define INTR_STATE_RX_OVERFLOW  (1 << 3)
> +#define IBEX_UART_INTR_ENABLE  0x04
> +#define IBEX_UART_INTR_TEST    0x08
> +
> +#define IBEX_UART_CTRL         0x0c
> +    #define UART_CTRL_TX_ENABLE     (1 << 0)
> +    #define UART_CTRL_RX_ENABLE     (1 << 1)
> +    #define UART_CTRL_NF            (1 << 2)
> +    #define UART_CTRL_SLPBK         (1 << 4)
> +    #define UART_CTRL_LLPBK         (1 << 5)
> +    #define UART_CTRL_PARITY_EN     (1 << 6)
> +    #define UART_CTRL_PARITY_ODD    (1 << 7)
> +    #define UART_CTRL_RXBLVL        (3 << 8)
> +    #define UART_CTRL_NCO           (0xFFFF << 16)
> +
> +#define IBEX_UART_STATUS       0x10
> +    #define UART_STATUS_TXFULL  (1 << 0)
> +    #define UART_STATUS_RXFULL  (1 << 1)
> +    #define UART_STATUS_TXEMPTY (1 << 2)
> +    #define UART_STATUS_RXIDLE  (1 << 4)
> +    #define UART_STATUS_RXEMPTY (1 << 5)
> +
> +#define IBEX_UART_RDATA        0x14
> +#define IBEX_UART_WDATA        0x18
> +
> +#define IBEX_UART_FIFO_CTRL    0x1c
> +    #define FIFO_CTRL_RXRST          (1 << 0)
> +    #define FIFO_CTRL_TXRST          (1 << 1)
> +    #define FIFO_CTRL_RXILVL         (7 << 2)
> +    #define FIFO_CTRL_RXILVL_SHIFT   (2)
> +    #define FIFO_CTRL_TXILVL         (3 << 5)
> +    #define FIFO_CTRL_TXILVL_SHIFT   (5)
> +
> +#define IBEX_UART_FIFO_STATUS  0x20
> +#define IBEX_UART_OVRD         0x24
> +#define IBEX_UART_VAL          0x28
> +#define IBEX_UART_TIMEOUT_CTRL 0x2c
> +
> +#define IBEX_UART_TX_FIFO_SIZE 16
> +
> +#define TYPE_IBEX_UART "ibex-uart"
> +#define IBEX_UART(obj) \
> +    OBJECT_CHECK(IbexUartState, (obj), TYPE_IBEX_UART)
> +
> +typedef struct {
> +    /* <private> */
> +    SysBusDevice parent_obj;
> +
> +    /* <public> */
> +    MemoryRegion mmio;
> +
> +    uint8_t tx_fifo[IBEX_UART_TX_FIFO_SIZE];
> +    uint32_t tx_level;
> +
> +    QEMUTimer *fifo_trigger_handle;
> +    uint64_t char_tx_time;
> +
> +    uint32_t uart_intr_state;
> +    uint32_t uart_intr_enable;
> +    uint32_t uart_ctrl;
> +    uint32_t uart_status;
> +    uint32_t uart_rdata;
> +    uint32_t uart_fifo_ctrl;
> +    uint32_t uart_fifo_status;
> +    uint32_t uart_ovrd;
> +    uint32_t uart_val;
> +    uint32_t uart_timeout_ctrl;
> +
> +    CharBackend chr;
> +    qemu_irq tx_watermark;
> +    qemu_irq rx_watermark;
> +    qemu_irq tx_empty;
> +    qemu_irq rx_overflow;
> +} IbexUartState;
> +#endif /* HW_IBEX_UART_H */
> diff --git a/hw/char/ibex_uart.c b/hw/char/ibex_uart.c
> new file mode 100644
> index 0000000000..c416325d73
> --- /dev/null
> +++ b/hw/char/ibex_uart.c
> @@ -0,0 +1,492 @@
> +/*
> + * QEMU lowRISC Ibex UART device
> + *
> + * Copyright (c) 2020 Western Digital
> + *
> + * For details check the documentation here:
> + *    https://docs.opentitan.org/hw/ip/uart/doc/
> + *
> + * 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.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "hw/char/ibex_uart.h"
> +#include "hw/irq.h"
> +#include "hw/qdev-properties.h"
> +#include "migration/vmstate.h"
> +#include "qemu/log.h"
> +#include "qemu/module.h"
> +
> +static void ibex_uart_update_irqs(IbexUartState *s)
> +{
> +    if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_TX_WATERMARK) {
> +        qemu_set_irq(s->tx_watermark, 1);
> +    } else {
> +        qemu_set_irq(s->tx_watermark, 0);
> +    }
> +
> +    if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_RX_WATERMARK) {
> +        qemu_set_irq(s->rx_watermark, 1);
> +    } else {
> +        qemu_set_irq(s->rx_watermark, 0);
> +    }
> +
> +    if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_TX_EMPTY) {
> +        qemu_set_irq(s->tx_empty, 1);
> +    } else {
> +        qemu_set_irq(s->tx_empty, 0);
> +    }
> +
> +    if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_RX_OVERFLOW) {
> +        qemu_set_irq(s->rx_overflow, 1);
> +    } else {
> +        qemu_set_irq(s->rx_overflow, 0);
> +    }
> +}
> +
> +static int ibex_uart_can_receive(void *opaque)
> +{
> +    IbexUartState *s = opaque;
> +
> +    if (s->uart_ctrl & UART_CTRL_RX_ENABLE) {
> +        return 1;
> +    }
> +
> +    return 0;
> +}
> +
> +static void ibex_uart_receive(void *opaque, const uint8_t *buf, int size)
> +{
> +    IbexUartState *s = opaque;
> +    uint8_t rx_fifo_level = (s->uart_fifo_ctrl & FIFO_CTRL_RXILVL)
> +                            >> FIFO_CTRL_RXILVL_SHIFT;
> +
> +    s->uart_rdata = *buf;
> +
> +    s->uart_status &= ~UART_STATUS_RXIDLE;
> +    s->uart_status &= ~UART_STATUS_RXEMPTY;
> +
> +    if (size > rx_fifo_level) {
> +        s->uart_intr_state |= INTR_STATE_RX_WATERMARK;
> +    }
> +
> +    ibex_uart_update_irqs(s);
> +}
> +
> +static gboolean ibex_uart_xmit(GIOChannel *chan, GIOCondition cond,
> +                               void *opaque)
> +{
> +    IbexUartState *s = opaque;
> +    uint8_t tx_fifo_level = (s->uart_fifo_ctrl & FIFO_CTRL_TXILVL)
> +                            >> FIFO_CTRL_TXILVL_SHIFT;
> +    int ret;
> +
> +    /* instant drain the fifo when there's no back-end */
> +    if (!qemu_chr_fe_backend_connected(&s->chr)) {
> +        s->tx_level = 0;
> +        return FALSE;
> +    }
> +
> +    if (!s->tx_level) {
> +        s->uart_status &= UART_STATUS_TXFULL;
> +        s->uart_status |= UART_STATUS_TXEMPTY;
> +        s->uart_intr_state |= INTR_STATE_TX_EMPTY;
> +        s->uart_intr_state &= ~INTR_STATE_TX_WATERMARK;
> +        ibex_uart_update_irqs(s);
> +        return FALSE;
> +    }
> +
> +    ret = qemu_chr_fe_write(&s->chr, s->tx_fifo, s->tx_level);
> +
> +    if (ret >= 0) {
> +        s->tx_level -= ret;
> +        memmove(s->tx_fifo, s->tx_fifo + ret, s->tx_level);
> +    }
> +
> +    if (s->tx_level) {
> +        guint r = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP,
> +                                        ibex_uart_xmit, s);
> +        if (!r) {
> +            s->tx_level = 0;
> +            return FALSE;
> +        }
> +    }
> +
> +    /* Clear the TX Full bit */
> +    if (s->tx_level != IBEX_UART_TX_FIFO_SIZE) {
> +        s->uart_status &= ~UART_STATUS_TXFULL;
> +    }
> +
> +    /* Disable the TX_WATERMARK IRQ */
> +    if (s->tx_level < tx_fifo_level) {
> +        s->uart_intr_state &= ~INTR_STATE_TX_WATERMARK;
> +    }
> +
> +    /* Set TX empty */
> +    if (s->tx_level == 0) {
> +        s->uart_status |= UART_STATUS_TXEMPTY;
> +        s->uart_intr_state |= INTR_STATE_TX_EMPTY;
> +    }
> +
> +    ibex_uart_update_irqs(s);
> +    return FALSE;
> +}
> +
> +static void uart_write_tx_fifo(IbexUartState *s, const uint8_t *buf,
> +                               int size)
> +{
> +    uint64_t current_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
> +    uint8_t tx_fifo_level = (s->uart_fifo_ctrl & FIFO_CTRL_TXILVL)
> +                            >> FIFO_CTRL_TXILVL_SHIFT;
> +
> +    if (size > IBEX_UART_TX_FIFO_SIZE - s->tx_level) {
> +        size = IBEX_UART_TX_FIFO_SIZE - s->tx_level;
> +        qemu_log_mask(LOG_GUEST_ERROR, "ibex_uart: TX FIFO overflow");
> +    }
> +
> +    memcpy(s->tx_fifo + s->tx_level, buf, size);
> +    s->tx_level += size;
> +
> +    if (s->tx_level > 0) {
> +        s->uart_status &= ~UART_STATUS_TXEMPTY;
> +    }
> +
> +    if (s->tx_level >= tx_fifo_level) {
> +        s->uart_intr_state |= INTR_STATE_TX_WATERMARK;
> +        ibex_uart_update_irqs(s);
> +    }
> +
> +    if (s->tx_level == IBEX_UART_TX_FIFO_SIZE) {
> +        s->uart_status |= UART_STATUS_TXFULL;
> +    }
> +
> +    timer_mod(s->fifo_trigger_handle, current_time +
> +              (s->char_tx_time * 4));
> +}
> +
> +static void ibex_uart_reset(DeviceState *dev)
> +{
> +    IbexUartState *s = IBEX_UART(dev);
> +
> +    s->uart_intr_state = 0x00000000;
> +    s->uart_intr_state = 0x00000000;
> +    s->uart_intr_enable = 0x00000000;
> +    s->uart_ctrl = 0x00000000;
> +    s->uart_status = 0x0000003c;
> +    s->uart_rdata = 0x00000000;
> +    s->uart_fifo_ctrl = 0x00000000;
> +    s->uart_fifo_status = 0x00000000;
> +    s->uart_ovrd = 0x00000000;
> +    s->uart_val = 0x00000000;
> +    s->uart_timeout_ctrl = 0x00000000;
> +
> +    s->tx_level = 0;
> +
> +    s->char_tx_time = (NANOSECONDS_PER_SECOND / 230400) * 10;
> +
> +    ibex_uart_update_irqs(s);
> +}
> +
> +static uint64_t ibex_uart_read(void *opaque, hwaddr addr,
> +                                       unsigned int size)
> +{
> +    IbexUartState *s = opaque;
> +    uint64_t retvalue = 0;
> +
> +    switch (addr) {
> +    case IBEX_UART_INTR_STATE:
> +        retvalue = s->uart_intr_state;
> +        break;
> +    case IBEX_UART_INTR_ENABLE:
> +        retvalue = s->uart_intr_enable;
> +        break;
> +    case IBEX_UART_INTR_TEST:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: wdata is write only\n", __func__);
> +        break;
> +
> +    case IBEX_UART_CTRL:
> +        retvalue = s->uart_ctrl;
> +        break;
> +    case IBEX_UART_STATUS:
> +        retvalue = s->uart_status;
> +        break;
> +
> +    case IBEX_UART_RDATA:
> +        retvalue = s->uart_rdata;
> +        if (s->uart_ctrl & UART_CTRL_RX_ENABLE) {
> +            qemu_chr_fe_accept_input(&s->chr);
> +
> +            s->uart_status |= UART_STATUS_RXIDLE;
> +            s->uart_status |= UART_STATUS_RXEMPTY;
> +        }
> +        break;
> +    case IBEX_UART_WDATA:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: wdata is write only\n", __func__);
> +        break;
> +
> +    case IBEX_UART_FIFO_CTRL:
> +        retvalue = s->uart_fifo_ctrl;
> +        break;
> +    case IBEX_UART_FIFO_STATUS:
> +        retvalue = s->uart_fifo_status;
> +
> +        retvalue |= s->tx_level & 0x1F;
> +
> +        qemu_log_mask(LOG_UNIMP,
> +                      "%s: RX fifos are not supported\n", __func__);
> +        break;
> +
> +    case IBEX_UART_OVRD:
> +        retvalue = s->uart_ovrd;
> +        qemu_log_mask(LOG_UNIMP,
> +                      "%s: ovrd is not supported\n", __func__);
> +        break;
> +    case IBEX_UART_VAL:
> +        retvalue = s->uart_val;
> +        qemu_log_mask(LOG_UNIMP,
> +                      "%s: val is not supported\n", __func__);
> +        break;
> +    case IBEX_UART_TIMEOUT_CTRL:
> +        retvalue = s->uart_timeout_ctrl;
> +        qemu_log_mask(LOG_UNIMP,
> +                      "%s: timeout_ctrl is not supported\n", __func__);
> +        break;
> +    default:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
> +        return 0;
> +    }
> +
> +    return retvalue;
> +}
> +
> +static void ibex_uart_write(void *opaque, hwaddr addr,
> +                                  uint64_t val64, unsigned int size)
> +{
> +    IbexUartState *s = opaque;
> +    uint32_t value = val64;
> +
> +    switch (addr) {
> +    case IBEX_UART_INTR_STATE:
> +        /* Write 1 clear */
> +        s->uart_intr_state &= ~value;
> +        ibex_uart_update_irqs(s);
> +        break;
> +    case IBEX_UART_INTR_ENABLE:
> +        s->uart_intr_enable = value;
> +        ibex_uart_update_irqs(s);
> +        break;
> +    case IBEX_UART_INTR_TEST:
> +        s->uart_intr_state |= value;
> +        ibex_uart_update_irqs(s);
> +        break;
> +
> +    case IBEX_UART_CTRL:
> +        s->uart_ctrl = value;
> +
> +        if (value & UART_CTRL_NF) {
> +            qemu_log_mask(LOG_UNIMP,
> +                          "%s: UART_CTRL_NF is not supported\n", __func__);
> +        }
> +        if (value & UART_CTRL_SLPBK) {
> +            qemu_log_mask(LOG_UNIMP,
> +                          "%s: UART_CTRL_SLPBK is not supported\n", __func__);
> +        }
> +        if (value & UART_CTRL_LLPBK) {
> +            qemu_log_mask(LOG_UNIMP,
> +                          "%s: UART_CTRL_LLPBK is not supported\n", __func__);
> +        }
> +        if (value & UART_CTRL_PARITY_EN) {
> +            qemu_log_mask(LOG_UNIMP,
> +                          "%s: UART_CTRL_PARITY_EN is not supported\n",
> +                          __func__);
> +        }
> +        if (value & UART_CTRL_PARITY_ODD) {
> +            qemu_log_mask(LOG_UNIMP,
> +                          "%s: UART_CTRL_PARITY_ODD is not supported\n",
> +                          __func__);
> +        }
> +        if (value & UART_CTRL_RXBLVL) {
> +            qemu_log_mask(LOG_UNIMP,
> +                          "%s: UART_CTRL_RXBLVL is not supported\n", __func__);
> +        }
> +        if (value & UART_CTRL_NCO) {
> +            uint64_t baud = ((value & UART_CTRL_NCO) >> 16);
> +            baud *= 1000;
> +            baud /= 2 ^ 20;
> +
> +            s->char_tx_time = (NANOSECONDS_PER_SECOND / baud) * 10;
> +        }
> +        break;
> +    case IBEX_UART_STATUS:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: status is read only\n", __func__);
> +        break;
> +
> +    case IBEX_UART_RDATA:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: rdata is read only\n", __func__);
> +        break;
> +    case IBEX_UART_WDATA:
> +        uart_write_tx_fifo(s, (uint8_t *) &value, 1);
> +        break;
> +
> +    case IBEX_UART_FIFO_CTRL:
> +        s->uart_fifo_ctrl = value;
> +
> +        if (value & FIFO_CTRL_RXRST) {
> +            qemu_log_mask(LOG_UNIMP,
> +                          "%s: RX fifos are not supported\n", __func__);
> +        }
> +        if (value & FIFO_CTRL_TXRST) {
> +            s->tx_level = 0;
> +        }
> +        break;
> +    case IBEX_UART_FIFO_STATUS:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: fifo_status is read only\n", __func__);
> +        break;
> +
> +    case IBEX_UART_OVRD:
> +        s->uart_ovrd = value;
> +        qemu_log_mask(LOG_UNIMP,
> +                      "%s: ovrd is not supported\n", __func__);
> +        break;
> +    case IBEX_UART_VAL:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: val is read only\n", __func__);
> +        break;
> +    case IBEX_UART_TIMEOUT_CTRL:
> +        s->uart_timeout_ctrl = value;
> +        qemu_log_mask(LOG_UNIMP,
> +                      "%s: timeout_ctrl is not supported\n", __func__);
> +        break;
> +    default:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
> +    }
> +}
> +
> +static void fifo_trigger_update(void *opaque)
> +{
> +    IbexUartState *s = opaque;
> +
> +    if (s->uart_ctrl & UART_CTRL_TX_ENABLE) {
> +        ibex_uart_xmit(NULL, G_IO_OUT, s);
> +    }
> +}
> +
> +static const MemoryRegionOps ibex_uart_ops = {
> +    .read = ibex_uart_read,
> +    .write = ibex_uart_write,
> +    .endianness = DEVICE_NATIVE_ENDIAN,
> +    .impl.min_access_size = 4,
> +    .impl.max_access_size = 4,
> +};
> +
> +static int cadence_uart_post_load(void *opaque, int version_id)
> +{
> +    IbexUartState *s = opaque;
> +
> +    ibex_uart_update_irqs(s);
> +    return 0;
> +}
> +
> +static const VMStateDescription vmstate_ibex_uart = {
> +    .name = TYPE_IBEX_UART,
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .post_load = cadence_uart_post_load,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT8_ARRAY(tx_fifo, IbexUartState,
> +                            IBEX_UART_TX_FIFO_SIZE),
> +        VMSTATE_UINT32(tx_level, IbexUartState),
> +        VMSTATE_UINT64(char_tx_time, IbexUartState),
> +        VMSTATE_TIMER_PTR(fifo_trigger_handle, IbexUartState),
> +        VMSTATE_UINT32(uart_intr_state, IbexUartState),
> +        VMSTATE_UINT32(uart_intr_enable, IbexUartState),
> +        VMSTATE_UINT32(uart_ctrl, IbexUartState),
> +        VMSTATE_UINT32(uart_status, IbexUartState),
> +        VMSTATE_UINT32(uart_rdata, IbexUartState),
> +        VMSTATE_UINT32(uart_fifo_ctrl, IbexUartState),
> +        VMSTATE_UINT32(uart_fifo_status, IbexUartState),
> +        VMSTATE_UINT32(uart_ovrd, IbexUartState),
> +        VMSTATE_UINT32(uart_val, IbexUartState),
> +        VMSTATE_UINT32(uart_timeout_ctrl, IbexUartState),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static Property ibex_uart_properties[] = {
> +    DEFINE_PROP_CHR("chardev", IbexUartState, chr),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void ibex_uart_init(Object *obj)
> +{
> +    IbexUartState *s = IBEX_UART(obj);
> +
> +    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->tx_watermark);
> +    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->rx_watermark);
> +    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->tx_empty);
> +    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->rx_overflow);
> +
> +    memory_region_init_io(&s->mmio, obj, &ibex_uart_ops, s,
> +                          TYPE_IBEX_UART, 0x400);
> +    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
> +}
> +
> +static void ibex_uart_realize(DeviceState *dev, Error **errp)
> +{
> +    IbexUartState *s = IBEX_UART(dev);
> +
> +    s->fifo_trigger_handle = timer_new_ns(QEMU_CLOCK_VIRTUAL,
> +                                          fifo_trigger_update, s);
> +
> +    qemu_chr_fe_set_handlers(&s->chr, ibex_uart_can_receive,
> +                             ibex_uart_receive, NULL, NULL,
> +                             s, NULL, true);
> +}
> +
> +static void ibex_uart_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->reset = ibex_uart_reset;
> +    dc->realize = ibex_uart_realize;
> +    dc->vmsd = &vmstate_ibex_uart;
> +    device_class_set_props(dc, ibex_uart_properties);
> +}
> +
> +static const TypeInfo ibex_uart_info = {
> +    .name          = TYPE_IBEX_UART,
> +    .parent        = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(IbexUartState),
> +    .instance_init = ibex_uart_init,
> +    .class_init    = ibex_uart_class_init,
> +};
> +
> +static void ibex_uart_register_types(void)
> +{
> +    type_register_static(&ibex_uart_info);
> +}
> +
> +type_init(ibex_uart_register_types)
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 3e7d9cb0a5..a1ce186a7e 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1245,7 +1245,9 @@ M: Alistair Francis <Alistair.Francis@wdc.com>
>  L: qemu-riscv@nongnu.org
>  S: Supported
>  F: hw/riscv/opentitan.c
> +F: hw/char/ibex_uart.c
>  F: include/hw/riscv/opentitan.h
> +F: include/hw/char/ibex_uart.h
>
>  SH4 Machines
>  ------------
> diff --git a/hw/char/Makefile.objs b/hw/char/Makefile.objs
> index 9e9a6c1aff..633996be5b 100644
> --- a/hw/char/Makefile.objs
> +++ b/hw/char/Makefile.objs
> @@ -12,6 +12,7 @@ common-obj-$(CONFIG_VIRTIO_SERIAL) += virtio-console.o
>  common-obj-$(CONFIG_XILINX) += xilinx_uartlite.o
>  common-obj-$(CONFIG_XEN) += xen_console.o
>  common-obj-$(CONFIG_CADENCE) += cadence_uart.o
> +common-obj-$(CONFIG_IBEX) += ibex_uart.o
>
>  common-obj-$(CONFIG_EXYNOS4) += exynos4210_uart.o
>  common-obj-$(CONFIG_COLDFIRE) += mcf_uart.o
> diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
> index 94d19571f7..28947ef3e0 100644
> --- a/hw/riscv/Kconfig
> +++ b/hw/riscv/Kconfig
> @@ -4,6 +4,9 @@ config HTIF
>  config HART
>      bool
>
> +config IBEX
> +    bool
> +
>  config SIFIVE
>      bool
>      select MSI_NONBROKEN
> @@ -29,6 +32,7 @@ config SPIKE
>
>  config OPENTITAN
>      bool
> +    select IBEX
>      select HART
>      select UNIMP
>
> --
> 2.26.2
>


^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v5 07/11] hw/char: Initial commit of Ibex UART
@ 2020-06-01 21:23     ` Alistair Francis
  0 siblings, 0 replies; 68+ messages in thread
From: Alistair Francis @ 2020-06-01 21:23 UTC (permalink / raw)
  To: Alistair Francis, Philippe Mathieu-Daudé
  Cc: qemu-devel@nongnu.org Developers, open list:RISC-V,
	Palmer Dabbelt, Bin Meng

On Thu, May 28, 2020 at 3:23 PM Alistair Francis
<alistair.francis@wdc.com> wrote:
>
> This is the initial commit of the Ibex UART device. Serial TX is
> working, while RX has been implemeneted but untested.
>
> This is based on the documentation from:
> https://docs.opentitan.org/hw/ip/uart/doc/
>
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>

Ping! This is the last patch not reviewed.

Alistair

> ---
>  include/hw/char/ibex_uart.h | 110 ++++++++
>  hw/char/ibex_uart.c         | 492 ++++++++++++++++++++++++++++++++++++
>  MAINTAINERS                 |   2 +
>  hw/char/Makefile.objs       |   1 +
>  hw/riscv/Kconfig            |   4 +
>  5 files changed, 609 insertions(+)
>  create mode 100644 include/hw/char/ibex_uart.h
>  create mode 100644 hw/char/ibex_uart.c
>
> diff --git a/include/hw/char/ibex_uart.h b/include/hw/char/ibex_uart.h
> new file mode 100644
> index 0000000000..2bec772615
> --- /dev/null
> +++ b/include/hw/char/ibex_uart.h
> @@ -0,0 +1,110 @@
> +/*
> + * QEMU lowRISC Ibex UART device
> + *
> + * Copyright (c) 2020 Western Digital
> + *
> + * 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.
> + */
> +
> +#ifndef HW_IBEX_UART_H
> +#define HW_IBEX_UART_H
> +
> +#include "hw/sysbus.h"
> +#include "chardev/char-fe.h"
> +#include "qemu/timer.h"
> +
> +#define IBEX_UART_INTR_STATE   0x00
> +    #define INTR_STATE_TX_WATERMARK (1 << 0)
> +    #define INTR_STATE_RX_WATERMARK (1 << 1)
> +    #define INTR_STATE_TX_EMPTY     (1 << 2)
> +    #define INTR_STATE_RX_OVERFLOW  (1 << 3)
> +#define IBEX_UART_INTR_ENABLE  0x04
> +#define IBEX_UART_INTR_TEST    0x08
> +
> +#define IBEX_UART_CTRL         0x0c
> +    #define UART_CTRL_TX_ENABLE     (1 << 0)
> +    #define UART_CTRL_RX_ENABLE     (1 << 1)
> +    #define UART_CTRL_NF            (1 << 2)
> +    #define UART_CTRL_SLPBK         (1 << 4)
> +    #define UART_CTRL_LLPBK         (1 << 5)
> +    #define UART_CTRL_PARITY_EN     (1 << 6)
> +    #define UART_CTRL_PARITY_ODD    (1 << 7)
> +    #define UART_CTRL_RXBLVL        (3 << 8)
> +    #define UART_CTRL_NCO           (0xFFFF << 16)
> +
> +#define IBEX_UART_STATUS       0x10
> +    #define UART_STATUS_TXFULL  (1 << 0)
> +    #define UART_STATUS_RXFULL  (1 << 1)
> +    #define UART_STATUS_TXEMPTY (1 << 2)
> +    #define UART_STATUS_RXIDLE  (1 << 4)
> +    #define UART_STATUS_RXEMPTY (1 << 5)
> +
> +#define IBEX_UART_RDATA        0x14
> +#define IBEX_UART_WDATA        0x18
> +
> +#define IBEX_UART_FIFO_CTRL    0x1c
> +    #define FIFO_CTRL_RXRST          (1 << 0)
> +    #define FIFO_CTRL_TXRST          (1 << 1)
> +    #define FIFO_CTRL_RXILVL         (7 << 2)
> +    #define FIFO_CTRL_RXILVL_SHIFT   (2)
> +    #define FIFO_CTRL_TXILVL         (3 << 5)
> +    #define FIFO_CTRL_TXILVL_SHIFT   (5)
> +
> +#define IBEX_UART_FIFO_STATUS  0x20
> +#define IBEX_UART_OVRD         0x24
> +#define IBEX_UART_VAL          0x28
> +#define IBEX_UART_TIMEOUT_CTRL 0x2c
> +
> +#define IBEX_UART_TX_FIFO_SIZE 16
> +
> +#define TYPE_IBEX_UART "ibex-uart"
> +#define IBEX_UART(obj) \
> +    OBJECT_CHECK(IbexUartState, (obj), TYPE_IBEX_UART)
> +
> +typedef struct {
> +    /* <private> */
> +    SysBusDevice parent_obj;
> +
> +    /* <public> */
> +    MemoryRegion mmio;
> +
> +    uint8_t tx_fifo[IBEX_UART_TX_FIFO_SIZE];
> +    uint32_t tx_level;
> +
> +    QEMUTimer *fifo_trigger_handle;
> +    uint64_t char_tx_time;
> +
> +    uint32_t uart_intr_state;
> +    uint32_t uart_intr_enable;
> +    uint32_t uart_ctrl;
> +    uint32_t uart_status;
> +    uint32_t uart_rdata;
> +    uint32_t uart_fifo_ctrl;
> +    uint32_t uart_fifo_status;
> +    uint32_t uart_ovrd;
> +    uint32_t uart_val;
> +    uint32_t uart_timeout_ctrl;
> +
> +    CharBackend chr;
> +    qemu_irq tx_watermark;
> +    qemu_irq rx_watermark;
> +    qemu_irq tx_empty;
> +    qemu_irq rx_overflow;
> +} IbexUartState;
> +#endif /* HW_IBEX_UART_H */
> diff --git a/hw/char/ibex_uart.c b/hw/char/ibex_uart.c
> new file mode 100644
> index 0000000000..c416325d73
> --- /dev/null
> +++ b/hw/char/ibex_uart.c
> @@ -0,0 +1,492 @@
> +/*
> + * QEMU lowRISC Ibex UART device
> + *
> + * Copyright (c) 2020 Western Digital
> + *
> + * For details check the documentation here:
> + *    https://docs.opentitan.org/hw/ip/uart/doc/
> + *
> + * 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.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "hw/char/ibex_uart.h"
> +#include "hw/irq.h"
> +#include "hw/qdev-properties.h"
> +#include "migration/vmstate.h"
> +#include "qemu/log.h"
> +#include "qemu/module.h"
> +
> +static void ibex_uart_update_irqs(IbexUartState *s)
> +{
> +    if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_TX_WATERMARK) {
> +        qemu_set_irq(s->tx_watermark, 1);
> +    } else {
> +        qemu_set_irq(s->tx_watermark, 0);
> +    }
> +
> +    if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_RX_WATERMARK) {
> +        qemu_set_irq(s->rx_watermark, 1);
> +    } else {
> +        qemu_set_irq(s->rx_watermark, 0);
> +    }
> +
> +    if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_TX_EMPTY) {
> +        qemu_set_irq(s->tx_empty, 1);
> +    } else {
> +        qemu_set_irq(s->tx_empty, 0);
> +    }
> +
> +    if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_RX_OVERFLOW) {
> +        qemu_set_irq(s->rx_overflow, 1);
> +    } else {
> +        qemu_set_irq(s->rx_overflow, 0);
> +    }
> +}
> +
> +static int ibex_uart_can_receive(void *opaque)
> +{
> +    IbexUartState *s = opaque;
> +
> +    if (s->uart_ctrl & UART_CTRL_RX_ENABLE) {
> +        return 1;
> +    }
> +
> +    return 0;
> +}
> +
> +static void ibex_uart_receive(void *opaque, const uint8_t *buf, int size)
> +{
> +    IbexUartState *s = opaque;
> +    uint8_t rx_fifo_level = (s->uart_fifo_ctrl & FIFO_CTRL_RXILVL)
> +                            >> FIFO_CTRL_RXILVL_SHIFT;
> +
> +    s->uart_rdata = *buf;
> +
> +    s->uart_status &= ~UART_STATUS_RXIDLE;
> +    s->uart_status &= ~UART_STATUS_RXEMPTY;
> +
> +    if (size > rx_fifo_level) {
> +        s->uart_intr_state |= INTR_STATE_RX_WATERMARK;
> +    }
> +
> +    ibex_uart_update_irqs(s);
> +}
> +
> +static gboolean ibex_uart_xmit(GIOChannel *chan, GIOCondition cond,
> +                               void *opaque)
> +{
> +    IbexUartState *s = opaque;
> +    uint8_t tx_fifo_level = (s->uart_fifo_ctrl & FIFO_CTRL_TXILVL)
> +                            >> FIFO_CTRL_TXILVL_SHIFT;
> +    int ret;
> +
> +    /* instant drain the fifo when there's no back-end */
> +    if (!qemu_chr_fe_backend_connected(&s->chr)) {
> +        s->tx_level = 0;
> +        return FALSE;
> +    }
> +
> +    if (!s->tx_level) {
> +        s->uart_status &= UART_STATUS_TXFULL;
> +        s->uart_status |= UART_STATUS_TXEMPTY;
> +        s->uart_intr_state |= INTR_STATE_TX_EMPTY;
> +        s->uart_intr_state &= ~INTR_STATE_TX_WATERMARK;
> +        ibex_uart_update_irqs(s);
> +        return FALSE;
> +    }
> +
> +    ret = qemu_chr_fe_write(&s->chr, s->tx_fifo, s->tx_level);
> +
> +    if (ret >= 0) {
> +        s->tx_level -= ret;
> +        memmove(s->tx_fifo, s->tx_fifo + ret, s->tx_level);
> +    }
> +
> +    if (s->tx_level) {
> +        guint r = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP,
> +                                        ibex_uart_xmit, s);
> +        if (!r) {
> +            s->tx_level = 0;
> +            return FALSE;
> +        }
> +    }
> +
> +    /* Clear the TX Full bit */
> +    if (s->tx_level != IBEX_UART_TX_FIFO_SIZE) {
> +        s->uart_status &= ~UART_STATUS_TXFULL;
> +    }
> +
> +    /* Disable the TX_WATERMARK IRQ */
> +    if (s->tx_level < tx_fifo_level) {
> +        s->uart_intr_state &= ~INTR_STATE_TX_WATERMARK;
> +    }
> +
> +    /* Set TX empty */
> +    if (s->tx_level == 0) {
> +        s->uart_status |= UART_STATUS_TXEMPTY;
> +        s->uart_intr_state |= INTR_STATE_TX_EMPTY;
> +    }
> +
> +    ibex_uart_update_irqs(s);
> +    return FALSE;
> +}
> +
> +static void uart_write_tx_fifo(IbexUartState *s, const uint8_t *buf,
> +                               int size)
> +{
> +    uint64_t current_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
> +    uint8_t tx_fifo_level = (s->uart_fifo_ctrl & FIFO_CTRL_TXILVL)
> +                            >> FIFO_CTRL_TXILVL_SHIFT;
> +
> +    if (size > IBEX_UART_TX_FIFO_SIZE - s->tx_level) {
> +        size = IBEX_UART_TX_FIFO_SIZE - s->tx_level;
> +        qemu_log_mask(LOG_GUEST_ERROR, "ibex_uart: TX FIFO overflow");
> +    }
> +
> +    memcpy(s->tx_fifo + s->tx_level, buf, size);
> +    s->tx_level += size;
> +
> +    if (s->tx_level > 0) {
> +        s->uart_status &= ~UART_STATUS_TXEMPTY;
> +    }
> +
> +    if (s->tx_level >= tx_fifo_level) {
> +        s->uart_intr_state |= INTR_STATE_TX_WATERMARK;
> +        ibex_uart_update_irqs(s);
> +    }
> +
> +    if (s->tx_level == IBEX_UART_TX_FIFO_SIZE) {
> +        s->uart_status |= UART_STATUS_TXFULL;
> +    }
> +
> +    timer_mod(s->fifo_trigger_handle, current_time +
> +              (s->char_tx_time * 4));
> +}
> +
> +static void ibex_uart_reset(DeviceState *dev)
> +{
> +    IbexUartState *s = IBEX_UART(dev);
> +
> +    s->uart_intr_state = 0x00000000;
> +    s->uart_intr_state = 0x00000000;
> +    s->uart_intr_enable = 0x00000000;
> +    s->uart_ctrl = 0x00000000;
> +    s->uart_status = 0x0000003c;
> +    s->uart_rdata = 0x00000000;
> +    s->uart_fifo_ctrl = 0x00000000;
> +    s->uart_fifo_status = 0x00000000;
> +    s->uart_ovrd = 0x00000000;
> +    s->uart_val = 0x00000000;
> +    s->uart_timeout_ctrl = 0x00000000;
> +
> +    s->tx_level = 0;
> +
> +    s->char_tx_time = (NANOSECONDS_PER_SECOND / 230400) * 10;
> +
> +    ibex_uart_update_irqs(s);
> +}
> +
> +static uint64_t ibex_uart_read(void *opaque, hwaddr addr,
> +                                       unsigned int size)
> +{
> +    IbexUartState *s = opaque;
> +    uint64_t retvalue = 0;
> +
> +    switch (addr) {
> +    case IBEX_UART_INTR_STATE:
> +        retvalue = s->uart_intr_state;
> +        break;
> +    case IBEX_UART_INTR_ENABLE:
> +        retvalue = s->uart_intr_enable;
> +        break;
> +    case IBEX_UART_INTR_TEST:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: wdata is write only\n", __func__);
> +        break;
> +
> +    case IBEX_UART_CTRL:
> +        retvalue = s->uart_ctrl;
> +        break;
> +    case IBEX_UART_STATUS:
> +        retvalue = s->uart_status;
> +        break;
> +
> +    case IBEX_UART_RDATA:
> +        retvalue = s->uart_rdata;
> +        if (s->uart_ctrl & UART_CTRL_RX_ENABLE) {
> +            qemu_chr_fe_accept_input(&s->chr);
> +
> +            s->uart_status |= UART_STATUS_RXIDLE;
> +            s->uart_status |= UART_STATUS_RXEMPTY;
> +        }
> +        break;
> +    case IBEX_UART_WDATA:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: wdata is write only\n", __func__);
> +        break;
> +
> +    case IBEX_UART_FIFO_CTRL:
> +        retvalue = s->uart_fifo_ctrl;
> +        break;
> +    case IBEX_UART_FIFO_STATUS:
> +        retvalue = s->uart_fifo_status;
> +
> +        retvalue |= s->tx_level & 0x1F;
> +
> +        qemu_log_mask(LOG_UNIMP,
> +                      "%s: RX fifos are not supported\n", __func__);
> +        break;
> +
> +    case IBEX_UART_OVRD:
> +        retvalue = s->uart_ovrd;
> +        qemu_log_mask(LOG_UNIMP,
> +                      "%s: ovrd is not supported\n", __func__);
> +        break;
> +    case IBEX_UART_VAL:
> +        retvalue = s->uart_val;
> +        qemu_log_mask(LOG_UNIMP,
> +                      "%s: val is not supported\n", __func__);
> +        break;
> +    case IBEX_UART_TIMEOUT_CTRL:
> +        retvalue = s->uart_timeout_ctrl;
> +        qemu_log_mask(LOG_UNIMP,
> +                      "%s: timeout_ctrl is not supported\n", __func__);
> +        break;
> +    default:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
> +        return 0;
> +    }
> +
> +    return retvalue;
> +}
> +
> +static void ibex_uart_write(void *opaque, hwaddr addr,
> +                                  uint64_t val64, unsigned int size)
> +{
> +    IbexUartState *s = opaque;
> +    uint32_t value = val64;
> +
> +    switch (addr) {
> +    case IBEX_UART_INTR_STATE:
> +        /* Write 1 clear */
> +        s->uart_intr_state &= ~value;
> +        ibex_uart_update_irqs(s);
> +        break;
> +    case IBEX_UART_INTR_ENABLE:
> +        s->uart_intr_enable = value;
> +        ibex_uart_update_irqs(s);
> +        break;
> +    case IBEX_UART_INTR_TEST:
> +        s->uart_intr_state |= value;
> +        ibex_uart_update_irqs(s);
> +        break;
> +
> +    case IBEX_UART_CTRL:
> +        s->uart_ctrl = value;
> +
> +        if (value & UART_CTRL_NF) {
> +            qemu_log_mask(LOG_UNIMP,
> +                          "%s: UART_CTRL_NF is not supported\n", __func__);
> +        }
> +        if (value & UART_CTRL_SLPBK) {
> +            qemu_log_mask(LOG_UNIMP,
> +                          "%s: UART_CTRL_SLPBK is not supported\n", __func__);
> +        }
> +        if (value & UART_CTRL_LLPBK) {
> +            qemu_log_mask(LOG_UNIMP,
> +                          "%s: UART_CTRL_LLPBK is not supported\n", __func__);
> +        }
> +        if (value & UART_CTRL_PARITY_EN) {
> +            qemu_log_mask(LOG_UNIMP,
> +                          "%s: UART_CTRL_PARITY_EN is not supported\n",
> +                          __func__);
> +        }
> +        if (value & UART_CTRL_PARITY_ODD) {
> +            qemu_log_mask(LOG_UNIMP,
> +                          "%s: UART_CTRL_PARITY_ODD is not supported\n",
> +                          __func__);
> +        }
> +        if (value & UART_CTRL_RXBLVL) {
> +            qemu_log_mask(LOG_UNIMP,
> +                          "%s: UART_CTRL_RXBLVL is not supported\n", __func__);
> +        }
> +        if (value & UART_CTRL_NCO) {
> +            uint64_t baud = ((value & UART_CTRL_NCO) >> 16);
> +            baud *= 1000;
> +            baud /= 2 ^ 20;
> +
> +            s->char_tx_time = (NANOSECONDS_PER_SECOND / baud) * 10;
> +        }
> +        break;
> +    case IBEX_UART_STATUS:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: status is read only\n", __func__);
> +        break;
> +
> +    case IBEX_UART_RDATA:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: rdata is read only\n", __func__);
> +        break;
> +    case IBEX_UART_WDATA:
> +        uart_write_tx_fifo(s, (uint8_t *) &value, 1);
> +        break;
> +
> +    case IBEX_UART_FIFO_CTRL:
> +        s->uart_fifo_ctrl = value;
> +
> +        if (value & FIFO_CTRL_RXRST) {
> +            qemu_log_mask(LOG_UNIMP,
> +                          "%s: RX fifos are not supported\n", __func__);
> +        }
> +        if (value & FIFO_CTRL_TXRST) {
> +            s->tx_level = 0;
> +        }
> +        break;
> +    case IBEX_UART_FIFO_STATUS:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: fifo_status is read only\n", __func__);
> +        break;
> +
> +    case IBEX_UART_OVRD:
> +        s->uart_ovrd = value;
> +        qemu_log_mask(LOG_UNIMP,
> +                      "%s: ovrd is not supported\n", __func__);
> +        break;
> +    case IBEX_UART_VAL:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: val is read only\n", __func__);
> +        break;
> +    case IBEX_UART_TIMEOUT_CTRL:
> +        s->uart_timeout_ctrl = value;
> +        qemu_log_mask(LOG_UNIMP,
> +                      "%s: timeout_ctrl is not supported\n", __func__);
> +        break;
> +    default:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
> +    }
> +}
> +
> +static void fifo_trigger_update(void *opaque)
> +{
> +    IbexUartState *s = opaque;
> +
> +    if (s->uart_ctrl & UART_CTRL_TX_ENABLE) {
> +        ibex_uart_xmit(NULL, G_IO_OUT, s);
> +    }
> +}
> +
> +static const MemoryRegionOps ibex_uart_ops = {
> +    .read = ibex_uart_read,
> +    .write = ibex_uart_write,
> +    .endianness = DEVICE_NATIVE_ENDIAN,
> +    .impl.min_access_size = 4,
> +    .impl.max_access_size = 4,
> +};
> +
> +static int cadence_uart_post_load(void *opaque, int version_id)
> +{
> +    IbexUartState *s = opaque;
> +
> +    ibex_uart_update_irqs(s);
> +    return 0;
> +}
> +
> +static const VMStateDescription vmstate_ibex_uart = {
> +    .name = TYPE_IBEX_UART,
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .post_load = cadence_uart_post_load,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT8_ARRAY(tx_fifo, IbexUartState,
> +                            IBEX_UART_TX_FIFO_SIZE),
> +        VMSTATE_UINT32(tx_level, IbexUartState),
> +        VMSTATE_UINT64(char_tx_time, IbexUartState),
> +        VMSTATE_TIMER_PTR(fifo_trigger_handle, IbexUartState),
> +        VMSTATE_UINT32(uart_intr_state, IbexUartState),
> +        VMSTATE_UINT32(uart_intr_enable, IbexUartState),
> +        VMSTATE_UINT32(uart_ctrl, IbexUartState),
> +        VMSTATE_UINT32(uart_status, IbexUartState),
> +        VMSTATE_UINT32(uart_rdata, IbexUartState),
> +        VMSTATE_UINT32(uart_fifo_ctrl, IbexUartState),
> +        VMSTATE_UINT32(uart_fifo_status, IbexUartState),
> +        VMSTATE_UINT32(uart_ovrd, IbexUartState),
> +        VMSTATE_UINT32(uart_val, IbexUartState),
> +        VMSTATE_UINT32(uart_timeout_ctrl, IbexUartState),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static Property ibex_uart_properties[] = {
> +    DEFINE_PROP_CHR("chardev", IbexUartState, chr),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void ibex_uart_init(Object *obj)
> +{
> +    IbexUartState *s = IBEX_UART(obj);
> +
> +    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->tx_watermark);
> +    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->rx_watermark);
> +    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->tx_empty);
> +    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->rx_overflow);
> +
> +    memory_region_init_io(&s->mmio, obj, &ibex_uart_ops, s,
> +                          TYPE_IBEX_UART, 0x400);
> +    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
> +}
> +
> +static void ibex_uart_realize(DeviceState *dev, Error **errp)
> +{
> +    IbexUartState *s = IBEX_UART(dev);
> +
> +    s->fifo_trigger_handle = timer_new_ns(QEMU_CLOCK_VIRTUAL,
> +                                          fifo_trigger_update, s);
> +
> +    qemu_chr_fe_set_handlers(&s->chr, ibex_uart_can_receive,
> +                             ibex_uart_receive, NULL, NULL,
> +                             s, NULL, true);
> +}
> +
> +static void ibex_uart_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->reset = ibex_uart_reset;
> +    dc->realize = ibex_uart_realize;
> +    dc->vmsd = &vmstate_ibex_uart;
> +    device_class_set_props(dc, ibex_uart_properties);
> +}
> +
> +static const TypeInfo ibex_uart_info = {
> +    .name          = TYPE_IBEX_UART,
> +    .parent        = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(IbexUartState),
> +    .instance_init = ibex_uart_init,
> +    .class_init    = ibex_uart_class_init,
> +};
> +
> +static void ibex_uart_register_types(void)
> +{
> +    type_register_static(&ibex_uart_info);
> +}
> +
> +type_init(ibex_uart_register_types)
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 3e7d9cb0a5..a1ce186a7e 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1245,7 +1245,9 @@ M: Alistair Francis <Alistair.Francis@wdc.com>
>  L: qemu-riscv@nongnu.org
>  S: Supported
>  F: hw/riscv/opentitan.c
> +F: hw/char/ibex_uart.c
>  F: include/hw/riscv/opentitan.h
> +F: include/hw/char/ibex_uart.h
>
>  SH4 Machines
>  ------------
> diff --git a/hw/char/Makefile.objs b/hw/char/Makefile.objs
> index 9e9a6c1aff..633996be5b 100644
> --- a/hw/char/Makefile.objs
> +++ b/hw/char/Makefile.objs
> @@ -12,6 +12,7 @@ common-obj-$(CONFIG_VIRTIO_SERIAL) += virtio-console.o
>  common-obj-$(CONFIG_XILINX) += xilinx_uartlite.o
>  common-obj-$(CONFIG_XEN) += xen_console.o
>  common-obj-$(CONFIG_CADENCE) += cadence_uart.o
> +common-obj-$(CONFIG_IBEX) += ibex_uart.o
>
>  common-obj-$(CONFIG_EXYNOS4) += exynos4210_uart.o
>  common-obj-$(CONFIG_COLDFIRE) += mcf_uart.o
> diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
> index 94d19571f7..28947ef3e0 100644
> --- a/hw/riscv/Kconfig
> +++ b/hw/riscv/Kconfig
> @@ -4,6 +4,9 @@ config HTIF
>  config HART
>      bool
>
> +config IBEX
> +    bool
> +
>  config SIFIVE
>      bool
>      select MSI_NONBROKEN
> @@ -29,6 +32,7 @@ config SPIKE
>
>  config OPENTITAN
>      bool
> +    select IBEX
>      select HART
>      select UNIMP
>
> --
> 2.26.2
>


^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v5 07/11] hw/char: Initial commit of Ibex UART
  2020-05-28 22:14   ` Alistair Francis
@ 2020-06-02 11:22     ` LIU Zhiwei
  -1 siblings, 0 replies; 68+ messages in thread
From: LIU Zhiwei @ 2020-06-02 11:22 UTC (permalink / raw)
  To: Alistair Francis
  Cc: open list:RISC-V, Bin Meng, Palmer Dabbelt,
	qemu-devel@nongnu.org Developers



On 2020/5/29 6:14, Alistair Francis wrote:
> This is the initial commit of the Ibex UART device. Serial TX is
> working, while RX has been implemeneted but untested.
>
> This is based on the documentation from:
> https://docs.opentitan.org/hw/ip/uart/doc/
>
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
>   include/hw/char/ibex_uart.h | 110 ++++++++
>   hw/char/ibex_uart.c         | 492 ++++++++++++++++++++++++++++++++++++
>   MAINTAINERS                 |   2 +
>   hw/char/Makefile.objs       |   1 +
>   hw/riscv/Kconfig            |   4 +
>   5 files changed, 609 insertions(+)
>   create mode 100644 include/hw/char/ibex_uart.h
>   create mode 100644 hw/char/ibex_uart.c
>
> diff --git a/include/hw/char/ibex_uart.h b/include/hw/char/ibex_uart.h
> new file mode 100644
> index 0000000000..2bec772615
> --- /dev/null
> +++ b/include/hw/char/ibex_uart.h
> @@ -0,0 +1,110 @@
> +/*
> + * QEMU lowRISC Ibex UART device
> + *
> + * Copyright (c) 2020 Western Digital
> + *
> + * 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.
> + */
> +
> +#ifndef HW_IBEX_UART_H
> +#define HW_IBEX_UART_H
> +
> +#include "hw/sysbus.h"
> +#include "chardev/char-fe.h"
> +#include "qemu/timer.h"
> +
> +#define IBEX_UART_INTR_STATE   0x00
> +    #define INTR_STATE_TX_WATERMARK (1 << 0)
> +    #define INTR_STATE_RX_WATERMARK (1 << 1)
> +    #define INTR_STATE_TX_EMPTY     (1 << 2)
> +    #define INTR_STATE_RX_OVERFLOW  (1 << 3)
> +#define IBEX_UART_INTR_ENABLE  0x04
> +#define IBEX_UART_INTR_TEST    0x08
> +
> +#define IBEX_UART_CTRL         0x0c
> +    #define UART_CTRL_TX_ENABLE     (1 << 0)
> +    #define UART_CTRL_RX_ENABLE     (1 << 1)
> +    #define UART_CTRL_NF            (1 << 2)
> +    #define UART_CTRL_SLPBK         (1 << 4)
> +    #define UART_CTRL_LLPBK         (1 << 5)
> +    #define UART_CTRL_PARITY_EN     (1 << 6)
> +    #define UART_CTRL_PARITY_ODD    (1 << 7)
> +    #define UART_CTRL_RXBLVL        (3 << 8)
> +    #define UART_CTRL_NCO           (0xFFFF << 16)
> +
> +#define IBEX_UART_STATUS       0x10
> +    #define UART_STATUS_TXFULL  (1 << 0)
> +    #define UART_STATUS_RXFULL  (1 << 1)
> +    #define UART_STATUS_TXEMPTY (1 << 2)
> +    #define UART_STATUS_RXIDLE  (1 << 4)
> +    #define UART_STATUS_RXEMPTY (1 << 5)
> +
> +#define IBEX_UART_RDATA        0x14
> +#define IBEX_UART_WDATA        0x18
> +
> +#define IBEX_UART_FIFO_CTRL    0x1c
> +    #define FIFO_CTRL_RXRST          (1 << 0)
> +    #define FIFO_CTRL_TXRST          (1 << 1)
> +    #define FIFO_CTRL_RXILVL         (7 << 2)
> +    #define FIFO_CTRL_RXILVL_SHIFT   (2)
> +    #define FIFO_CTRL_TXILVL         (3 << 5)
> +    #define FIFO_CTRL_TXILVL_SHIFT   (5)
> +
> +#define IBEX_UART_FIFO_STATUS  0x20
> +#define IBEX_UART_OVRD         0x24
> +#define IBEX_UART_VAL          0x28
> +#define IBEX_UART_TIMEOUT_CTRL 0x2c
> +
> +#define IBEX_UART_TX_FIFO_SIZE 16
> +
> +#define TYPE_IBEX_UART "ibex-uart"
> +#define IBEX_UART(obj) \
> +    OBJECT_CHECK(IbexUartState, (obj), TYPE_IBEX_UART)
> +
> +typedef struct {
> +    /* <private> */
> +    SysBusDevice parent_obj;
> +
> +    /* <public> */
> +    MemoryRegion mmio;
> +
> +    uint8_t tx_fifo[IBEX_UART_TX_FIFO_SIZE];
> +    uint32_t tx_level;
> +
> +    QEMUTimer *fifo_trigger_handle;
> +    uint64_t char_tx_time;
> +
> +    uint32_t uart_intr_state;
> +    uint32_t uart_intr_enable;
> +    uint32_t uart_ctrl;
> +    uint32_t uart_status;
> +    uint32_t uart_rdata;
> +    uint32_t uart_fifo_ctrl;
> +    uint32_t uart_fifo_status;
> +    uint32_t uart_ovrd;
> +    uint32_t uart_val;
> +    uint32_t uart_timeout_ctrl;
> +
> +    CharBackend chr;
> +    qemu_irq tx_watermark;
> +    qemu_irq rx_watermark;
> +    qemu_irq tx_empty;
> +    qemu_irq rx_overflow;
> +} IbexUartState;
> +#endif /* HW_IBEX_UART_H */
> diff --git a/hw/char/ibex_uart.c b/hw/char/ibex_uart.c
> new file mode 100644
> index 0000000000..c416325d73
> --- /dev/null
> +++ b/hw/char/ibex_uart.c
> @@ -0,0 +1,492 @@
> +/*
> + * QEMU lowRISC Ibex UART device
> + *
> + * Copyright (c) 2020 Western Digital
> + *
> + * For details check the documentation here:
> + *    https://docs.opentitan.org/hw/ip/uart/doc/
> + *
> + * 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.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "hw/char/ibex_uart.h"
> +#include "hw/irq.h"
> +#include "hw/qdev-properties.h"
> +#include "migration/vmstate.h"
> +#include "qemu/log.h"
> +#include "qemu/module.h"
> +
> +static void ibex_uart_update_irqs(IbexUartState *s)
> +{
> +    if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_TX_WATERMARK) {
> +        qemu_set_irq(s->tx_watermark, 1);
> +    } else {
> +        qemu_set_irq(s->tx_watermark, 0);
> +    }
> +
> +    if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_RX_WATERMARK) {
> +        qemu_set_irq(s->rx_watermark, 1);
> +    } else {
> +        qemu_set_irq(s->rx_watermark, 0);
> +    }
> +
> +    if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_TX_EMPTY) {
> +        qemu_set_irq(s->tx_empty, 1);
> +    } else {
> +        qemu_set_irq(s->tx_empty, 0);
> +    }
> +
> +    if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_RX_OVERFLOW) {
> +        qemu_set_irq(s->rx_overflow, 1);
> +    } else {
> +        qemu_set_irq(s->rx_overflow, 0);
> +    }
> +}
> +
> +static int ibex_uart_can_receive(void *opaque)
> +{
> +    IbexUartState *s = opaque;
> +
> +    if (s->uart_ctrl & UART_CTRL_RX_ENABLE) {
> +        return 1;
> +    }
> +
> +    return 0;
> +}
> +
> +static void ibex_uart_receive(void *opaque, const uint8_t *buf, int size)
> +{
> +    IbexUartState *s = opaque;
> +    uint8_t rx_fifo_level = (s->uart_fifo_ctrl & FIFO_CTRL_RXILVL)
> +                            >> FIFO_CTRL_RXILVL_SHIFT;
> +
> +    s->uart_rdata = *buf;
> +
> +    s->uart_status &= ~UART_STATUS_RXIDLE;
> +    s->uart_status &= ~UART_STATUS_RXEMPTY;
> +
> +    if (size > rx_fifo_level) {
> +        s->uart_intr_state |= INTR_STATE_RX_WATERMARK;
> +    }
> +
> +    ibex_uart_update_irqs(s);
> +}
> +
> +static gboolean ibex_uart_xmit(GIOChannel *chan, GIOCondition cond,
> +                               void *opaque)
> +{
> +    IbexUartState *s = opaque;
> +    uint8_t tx_fifo_level = (s->uart_fifo_ctrl & FIFO_CTRL_TXILVL)
> +                            >> FIFO_CTRL_TXILVL_SHIFT;
> +    int ret;
> +
> +    /* instant drain the fifo when there's no back-end */
> +    if (!qemu_chr_fe_backend_connected(&s->chr)) {
> +        s->tx_level = 0;
> +        return FALSE;
> +    }
> +
> +    if (!s->tx_level) {
> +        s->uart_status &= UART_STATUS_TXFULL;
Maybe  s->uart_status &= ~UART_STATUS_TXFULL;
> +        s->uart_status |= UART_STATUS_TXEMPTY;
> +        s->uart_intr_state |= INTR_STATE_TX_EMPTY;
> +        s->uart_intr_state &= ~INTR_STATE_TX_WATERMARK;
> +        ibex_uart_update_irqs(s);
> +        return FALSE;
> +    }
> +
> +    ret = qemu_chr_fe_write(&s->chr, s->tx_fifo, s->tx_level);
> +
> +    if (ret >= 0) {
> +        s->tx_level -= ret;
> +        memmove(s->tx_fifo, s->tx_fifo + ret, s->tx_level);
> +    }
> +
> +    if (s->tx_level) {
> +        guint r = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP,
> +                                        ibex_uart_xmit, s);
> +        if (!r) {
> +            s->tx_level = 0;
> +            return FALSE;
> +        }
> +    }
> +
> +    /* Clear the TX Full bit */
> +    if (s->tx_level != IBEX_UART_TX_FIFO_SIZE) {
> +        s->uart_status &= ~UART_STATUS_TXFULL;
> +    }
> +
> +    /* Disable the TX_WATERMARK IRQ */
> +    if (s->tx_level < tx_fifo_level) {
> +        s->uart_intr_state &= ~INTR_STATE_TX_WATERMARK;
> +    }
> +
> +    /* Set TX empty */
> +    if (s->tx_level == 0) {
> +        s->uart_status |= UART_STATUS_TXEMPTY;
> +        s->uart_intr_state |= INTR_STATE_TX_EMPTY;
> +    }
> +
> +    ibex_uart_update_irqs(s);
> +    return FALSE;
> +}
> +
> +static void uart_write_tx_fifo(IbexUartState *s, const uint8_t *buf,
> +                               int size)
> +{
> +    uint64_t current_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
> +    uint8_t tx_fifo_level = (s->uart_fifo_ctrl & FIFO_CTRL_TXILVL)
> +                            >> FIFO_CTRL_TXILVL_SHIFT;
> +
> +    if (size > IBEX_UART_TX_FIFO_SIZE - s->tx_level) {
> +        size = IBEX_UART_TX_FIFO_SIZE - s->tx_level;
> +        qemu_log_mask(LOG_GUEST_ERROR, "ibex_uart: TX FIFO overflow");
> +    }
> +
> +    memcpy(s->tx_fifo + s->tx_level, buf, size);
> +    s->tx_level += size;
> +
> +    if (s->tx_level > 0) {
> +        s->uart_status &= ~UART_STATUS_TXEMPTY;
> +    }
> +
> +    if (s->tx_level >= tx_fifo_level) {
> +        s->uart_intr_state |= INTR_STATE_TX_WATERMARK;
> +        ibex_uart_update_irqs(s);
> +    }
> +
> +    if (s->tx_level == IBEX_UART_TX_FIFO_SIZE) {
> +        s->uart_status |= UART_STATUS_TXFULL;
> +    }
> +
> +    timer_mod(s->fifo_trigger_handle, current_time +
> +              (s->char_tx_time * 4));
> +}
> +
> +static void ibex_uart_reset(DeviceState *dev)
> +{
> +    IbexUartState *s = IBEX_UART(dev);
> +
> +    s->uart_intr_state = 0x00000000;
> +    s->uart_intr_state = 0x00000000;
> +    s->uart_intr_enable = 0x00000000;
> +    s->uart_ctrl = 0x00000000;
> +    s->uart_status = 0x0000003c;
> +    s->uart_rdata = 0x00000000;
> +    s->uart_fifo_ctrl = 0x00000000;
> +    s->uart_fifo_status = 0x00000000;
> +    s->uart_ovrd = 0x00000000;
> +    s->uart_val = 0x00000000;
> +    s->uart_timeout_ctrl = 0x00000000;
> +
> +    s->tx_level = 0;
> +
> +    s->char_tx_time = (NANOSECONDS_PER_SECOND / 230400) * 10;
> +
> +    ibex_uart_update_irqs(s);
> +}
> +
> +static uint64_t ibex_uart_read(void *opaque, hwaddr addr,
> +                                       unsigned int size)
> +{
> +    IbexUartState *s = opaque;
> +    uint64_t retvalue = 0;
> +
> +    switch (addr) {
> +    case IBEX_UART_INTR_STATE:
> +        retvalue = s->uart_intr_state;
> +        break;
> +    case IBEX_UART_INTR_ENABLE:
> +        retvalue = s->uart_intr_enable;
> +        break;
> +    case IBEX_UART_INTR_TEST:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: wdata is write only\n", __func__);
> +        break;
> +
> +    case IBEX_UART_CTRL:
> +        retvalue = s->uart_ctrl;
> +        break;
> +    case IBEX_UART_STATUS:
> +        retvalue = s->uart_status;
> +        break;
> +
> +    case IBEX_UART_RDATA:
> +        retvalue = s->uart_rdata;
> +        if (s->uart_ctrl & UART_CTRL_RX_ENABLE) {
> +            qemu_chr_fe_accept_input(&s->chr);
> +
> +            s->uart_status |= UART_STATUS_RXIDLE;
> +            s->uart_status |= UART_STATUS_RXEMPTY;
> +        }
> +        break;
> +    case IBEX_UART_WDATA:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: wdata is write only\n", __func__);
> +        break;
> +
> +    case IBEX_UART_FIFO_CTRL:
> +        retvalue = s->uart_fifo_ctrl;
> +        break;
> +    case IBEX_UART_FIFO_STATUS:
> +        retvalue = s->uart_fifo_status;
> +
> +        retvalue |= s->tx_level & 0x1F;
> +
> +        qemu_log_mask(LOG_UNIMP,
> +                      "%s: RX fifos are not supported\n", __func__);
> +        break;
> +
> +    case IBEX_UART_OVRD:
> +        retvalue = s->uart_ovrd;
> +        qemu_log_mask(LOG_UNIMP,
> +                      "%s: ovrd is not supported\n", __func__);
> +        break;
> +    case IBEX_UART_VAL:
> +        retvalue = s->uart_val;
> +        qemu_log_mask(LOG_UNIMP,
> +                      "%s: val is not supported\n", __func__);
> +        break;
> +    case IBEX_UART_TIMEOUT_CTRL:
> +        retvalue = s->uart_timeout_ctrl;
> +        qemu_log_mask(LOG_UNIMP,
> +                      "%s: timeout_ctrl is not supported\n", __func__);
> +        break;
> +    default:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
> +        return 0;
> +    }
> +
> +    return retvalue;
> +}
> +
> +static void ibex_uart_write(void *opaque, hwaddr addr,
> +                                  uint64_t val64, unsigned int size)
> +{
> +    IbexUartState *s = opaque;
> +    uint32_t value = val64;
> +
> +    switch (addr) {
> +    case IBEX_UART_INTR_STATE:
> +        /* Write 1 clear */
> +        s->uart_intr_state &= ~value;
> +        ibex_uart_update_irqs(s);
> +        break;
> +    case IBEX_UART_INTR_ENABLE:
> +        s->uart_intr_enable = value;
> +        ibex_uart_update_irqs(s);
> +        break;
> +    case IBEX_UART_INTR_TEST:
> +        s->uart_intr_state |= value;
> +        ibex_uart_update_irqs(s);
> +        break;
> +
> +    case IBEX_UART_CTRL:
> +        s->uart_ctrl = value;
> +
> +        if (value & UART_CTRL_NF) {
> +            qemu_log_mask(LOG_UNIMP,
> +                          "%s: UART_CTRL_NF is not supported\n", __func__);
> +        }
> +        if (value & UART_CTRL_SLPBK) {
> +            qemu_log_mask(LOG_UNIMP,
> +                          "%s: UART_CTRL_SLPBK is not supported\n", __func__);
> +        }
> +        if (value & UART_CTRL_LLPBK) {
> +            qemu_log_mask(LOG_UNIMP,
> +                          "%s: UART_CTRL_LLPBK is not supported\n", __func__);
> +        }
> +        if (value & UART_CTRL_PARITY_EN) {
> +            qemu_log_mask(LOG_UNIMP,
> +                          "%s: UART_CTRL_PARITY_EN is not supported\n",
> +                          __func__);
> +        }
> +        if (value & UART_CTRL_PARITY_ODD) {
> +            qemu_log_mask(LOG_UNIMP,
> +                          "%s: UART_CTRL_PARITY_ODD is not supported\n",
> +                          __func__);
> +        }
> +        if (value & UART_CTRL_RXBLVL) {
> +            qemu_log_mask(LOG_UNIMP,
> +                          "%s: UART_CTRL_RXBLVL is not supported\n", __func__);
> +        }
> +        if (value & UART_CTRL_NCO) {
> +            uint64_t baud = ((value & UART_CTRL_NCO) >> 16);
> +            baud *= 1000;
> +            baud /= 2 ^ 20;
> +
> +            s->char_tx_time = (NANOSECONDS_PER_SECOND / baud) * 10;
> +        }
> +        break;
> +    case IBEX_UART_STATUS:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: status is read only\n", __func__);
> +        break;
> +
> +    case IBEX_UART_RDATA:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: rdata is read only\n", __func__);
> +        break;
> +    case IBEX_UART_WDATA:
> +        uart_write_tx_fifo(s, (uint8_t *) &value, 1);
> +        break;
> +
> +    case IBEX_UART_FIFO_CTRL:
> +        s->uart_fifo_ctrl = value;
> +
> +        if (value & FIFO_CTRL_RXRST) {
> +            qemu_log_mask(LOG_UNIMP,
> +                          "%s: RX fifos are not supported\n", __func__);
> +        }
> +        if (value & FIFO_CTRL_TXRST) {
> +            s->tx_level = 0;
> +        }
> +        break;
> +    case IBEX_UART_FIFO_STATUS:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: fifo_status is read only\n", __func__);
> +        break;
> +
> +    case IBEX_UART_OVRD:
> +        s->uart_ovrd = value;
> +        qemu_log_mask(LOG_UNIMP,
> +                      "%s: ovrd is not supported\n", __func__);
> +        break;
> +    case IBEX_UART_VAL:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: val is read only\n", __func__);
> +        break;
> +    case IBEX_UART_TIMEOUT_CTRL:
> +        s->uart_timeout_ctrl = value;
> +        qemu_log_mask(LOG_UNIMP,
> +                      "%s: timeout_ctrl is not supported\n", __func__);
> +        break;
> +    default:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
> +    }
> +}
> +
> +static void fifo_trigger_update(void *opaque)
> +{
> +    IbexUartState *s = opaque;
> +
> +    if (s->uart_ctrl & UART_CTRL_TX_ENABLE) {
> +        ibex_uart_xmit(NULL, G_IO_OUT, s);
> +    }
> +}
> +
> +static const MemoryRegionOps ibex_uart_ops = {
> +    .read = ibex_uart_read,
> +    .write = ibex_uart_write,
> +    .endianness = DEVICE_NATIVE_ENDIAN,
> +    .impl.min_access_size = 4,
> +    .impl.max_access_size = 4,
> +};
> +
> +static int cadence_uart_post_load(void *opaque, int version_id)
Not a good name.
> +{
> +    IbexUartState *s = opaque;
> +
> +    ibex_uart_update_irqs(s);
> +    return 0;
> +}
> +
> +static const VMStateDescription vmstate_ibex_uart = {
> +    .name = TYPE_IBEX_UART,
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .post_load = cadence_uart_post_load,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT8_ARRAY(tx_fifo, IbexUartState,
> +                            IBEX_UART_TX_FIFO_SIZE),
> +        VMSTATE_UINT32(tx_level, IbexUartState),
> +        VMSTATE_UINT64(char_tx_time, IbexUartState),
> +        VMSTATE_TIMER_PTR(fifo_trigger_handle, IbexUartState),
> +        VMSTATE_UINT32(uart_intr_state, IbexUartState),
> +        VMSTATE_UINT32(uart_intr_enable, IbexUartState),
> +        VMSTATE_UINT32(uart_ctrl, IbexUartState),
> +        VMSTATE_UINT32(uart_status, IbexUartState),
> +        VMSTATE_UINT32(uart_rdata, IbexUartState),
> +        VMSTATE_UINT32(uart_fifo_ctrl, IbexUartState),
> +        VMSTATE_UINT32(uart_fifo_status, IbexUartState),
> +        VMSTATE_UINT32(uart_ovrd, IbexUartState),
> +        VMSTATE_UINT32(uart_val, IbexUartState),
> +        VMSTATE_UINT32(uart_timeout_ctrl, IbexUartState),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static Property ibex_uart_properties[] = {
> +    DEFINE_PROP_CHR("chardev", IbexUartState, chr),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void ibex_uart_init(Object *obj)
> +{
> +    IbexUartState *s = IBEX_UART(obj);
> +
> +    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->tx_watermark);
> +    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->rx_watermark);
> +    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->tx_empty);
> +    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->rx_overflow);
> +
> +    memory_region_init_io(&s->mmio, obj, &ibex_uart_ops, s,
> +                          TYPE_IBEX_UART, 0x400);
> +    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
> +}
> +
> +static void ibex_uart_realize(DeviceState *dev, Error **errp)
> +{
> +    IbexUartState *s = IBEX_UART(dev);
> +
> +    s->fifo_trigger_handle = timer_new_ns(QEMU_CLOCK_VIRTUAL,
> +                                          fifo_trigger_update, s);
> +
> +    qemu_chr_fe_set_handlers(&s->chr, ibex_uart_can_receive,
> +                             ibex_uart_receive, NULL, NULL,
> +                             s, NULL, true);
> +}
> +
> +static void ibex_uart_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->reset = ibex_uart_reset;
> +    dc->realize = ibex_uart_realize;
> +    dc->vmsd = &vmstate_ibex_uart;
> +    device_class_set_props(dc, ibex_uart_properties);
> +}
> +
> +static const TypeInfo ibex_uart_info = {
> +    .name          = TYPE_IBEX_UART,
> +    .parent        = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(IbexUartState),
> +    .instance_init = ibex_uart_init,
> +    .class_init    = ibex_uart_class_init,
> +};
> +
> +static void ibex_uart_register_types(void)
> +{
> +    type_register_static(&ibex_uart_info);
> +}
> +
> +type_init(ibex_uart_register_types)
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 3e7d9cb0a5..a1ce186a7e 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1245,7 +1245,9 @@ M: Alistair Francis <Alistair.Francis@wdc.com>
>   L: qemu-riscv@nongnu.org
>   S: Supported
>   F: hw/riscv/opentitan.c
> +F: hw/char/ibex_uart.c
>   F: include/hw/riscv/opentitan.h
> +F: include/hw/char/ibex_uart.h
>   
>   SH4 Machines
>   ------------
> diff --git a/hw/char/Makefile.objs b/hw/char/Makefile.objs
> index 9e9a6c1aff..633996be5b 100644
> --- a/hw/char/Makefile.objs
> +++ b/hw/char/Makefile.objs
> @@ -12,6 +12,7 @@ common-obj-$(CONFIG_VIRTIO_SERIAL) += virtio-console.o
>   common-obj-$(CONFIG_XILINX) += xilinx_uartlite.o
>   common-obj-$(CONFIG_XEN) += xen_console.o
>   common-obj-$(CONFIG_CADENCE) += cadence_uart.o
> +common-obj-$(CONFIG_IBEX) += ibex_uart.o
>   
>   common-obj-$(CONFIG_EXYNOS4) += exynos4210_uart.o
>   common-obj-$(CONFIG_COLDFIRE) += mcf_uart.o
> diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
> index 94d19571f7..28947ef3e0 100644
> --- a/hw/riscv/Kconfig
> +++ b/hw/riscv/Kconfig
> @@ -4,6 +4,9 @@ config HTIF
>   config HART
>       bool
>   
> +config IBEX
> +    bool
> +
>   config SIFIVE
>       bool
>       select MSI_NONBROKEN
> @@ -29,6 +32,7 @@ config SPIKE
>   
>   config OPENTITAN
>       bool
> +    select IBEX
>       select HART
>       select UNIMP
>   



^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v5 07/11] hw/char: Initial commit of Ibex UART
@ 2020-06-02 11:22     ` LIU Zhiwei
  0 siblings, 0 replies; 68+ messages in thread
From: LIU Zhiwei @ 2020-06-02 11:22 UTC (permalink / raw)
  To: Alistair Francis
  Cc: Bin Meng, Palmer Dabbelt, qemu-devel@nongnu.org Developers,
	open list:RISC-V



On 2020/5/29 6:14, Alistair Francis wrote:
> This is the initial commit of the Ibex UART device. Serial TX is
> working, while RX has been implemeneted but untested.
>
> This is based on the documentation from:
> https://docs.opentitan.org/hw/ip/uart/doc/
>
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
>   include/hw/char/ibex_uart.h | 110 ++++++++
>   hw/char/ibex_uart.c         | 492 ++++++++++++++++++++++++++++++++++++
>   MAINTAINERS                 |   2 +
>   hw/char/Makefile.objs       |   1 +
>   hw/riscv/Kconfig            |   4 +
>   5 files changed, 609 insertions(+)
>   create mode 100644 include/hw/char/ibex_uart.h
>   create mode 100644 hw/char/ibex_uart.c
>
> diff --git a/include/hw/char/ibex_uart.h b/include/hw/char/ibex_uart.h
> new file mode 100644
> index 0000000000..2bec772615
> --- /dev/null
> +++ b/include/hw/char/ibex_uart.h
> @@ -0,0 +1,110 @@
> +/*
> + * QEMU lowRISC Ibex UART device
> + *
> + * Copyright (c) 2020 Western Digital
> + *
> + * 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.
> + */
> +
> +#ifndef HW_IBEX_UART_H
> +#define HW_IBEX_UART_H
> +
> +#include "hw/sysbus.h"
> +#include "chardev/char-fe.h"
> +#include "qemu/timer.h"
> +
> +#define IBEX_UART_INTR_STATE   0x00
> +    #define INTR_STATE_TX_WATERMARK (1 << 0)
> +    #define INTR_STATE_RX_WATERMARK (1 << 1)
> +    #define INTR_STATE_TX_EMPTY     (1 << 2)
> +    #define INTR_STATE_RX_OVERFLOW  (1 << 3)
> +#define IBEX_UART_INTR_ENABLE  0x04
> +#define IBEX_UART_INTR_TEST    0x08
> +
> +#define IBEX_UART_CTRL         0x0c
> +    #define UART_CTRL_TX_ENABLE     (1 << 0)
> +    #define UART_CTRL_RX_ENABLE     (1 << 1)
> +    #define UART_CTRL_NF            (1 << 2)
> +    #define UART_CTRL_SLPBK         (1 << 4)
> +    #define UART_CTRL_LLPBK         (1 << 5)
> +    #define UART_CTRL_PARITY_EN     (1 << 6)
> +    #define UART_CTRL_PARITY_ODD    (1 << 7)
> +    #define UART_CTRL_RXBLVL        (3 << 8)
> +    #define UART_CTRL_NCO           (0xFFFF << 16)
> +
> +#define IBEX_UART_STATUS       0x10
> +    #define UART_STATUS_TXFULL  (1 << 0)
> +    #define UART_STATUS_RXFULL  (1 << 1)
> +    #define UART_STATUS_TXEMPTY (1 << 2)
> +    #define UART_STATUS_RXIDLE  (1 << 4)
> +    #define UART_STATUS_RXEMPTY (1 << 5)
> +
> +#define IBEX_UART_RDATA        0x14
> +#define IBEX_UART_WDATA        0x18
> +
> +#define IBEX_UART_FIFO_CTRL    0x1c
> +    #define FIFO_CTRL_RXRST          (1 << 0)
> +    #define FIFO_CTRL_TXRST          (1 << 1)
> +    #define FIFO_CTRL_RXILVL         (7 << 2)
> +    #define FIFO_CTRL_RXILVL_SHIFT   (2)
> +    #define FIFO_CTRL_TXILVL         (3 << 5)
> +    #define FIFO_CTRL_TXILVL_SHIFT   (5)
> +
> +#define IBEX_UART_FIFO_STATUS  0x20
> +#define IBEX_UART_OVRD         0x24
> +#define IBEX_UART_VAL          0x28
> +#define IBEX_UART_TIMEOUT_CTRL 0x2c
> +
> +#define IBEX_UART_TX_FIFO_SIZE 16
> +
> +#define TYPE_IBEX_UART "ibex-uart"
> +#define IBEX_UART(obj) \
> +    OBJECT_CHECK(IbexUartState, (obj), TYPE_IBEX_UART)
> +
> +typedef struct {
> +    /* <private> */
> +    SysBusDevice parent_obj;
> +
> +    /* <public> */
> +    MemoryRegion mmio;
> +
> +    uint8_t tx_fifo[IBEX_UART_TX_FIFO_SIZE];
> +    uint32_t tx_level;
> +
> +    QEMUTimer *fifo_trigger_handle;
> +    uint64_t char_tx_time;
> +
> +    uint32_t uart_intr_state;
> +    uint32_t uart_intr_enable;
> +    uint32_t uart_ctrl;
> +    uint32_t uart_status;
> +    uint32_t uart_rdata;
> +    uint32_t uart_fifo_ctrl;
> +    uint32_t uart_fifo_status;
> +    uint32_t uart_ovrd;
> +    uint32_t uart_val;
> +    uint32_t uart_timeout_ctrl;
> +
> +    CharBackend chr;
> +    qemu_irq tx_watermark;
> +    qemu_irq rx_watermark;
> +    qemu_irq tx_empty;
> +    qemu_irq rx_overflow;
> +} IbexUartState;
> +#endif /* HW_IBEX_UART_H */
> diff --git a/hw/char/ibex_uart.c b/hw/char/ibex_uart.c
> new file mode 100644
> index 0000000000..c416325d73
> --- /dev/null
> +++ b/hw/char/ibex_uart.c
> @@ -0,0 +1,492 @@
> +/*
> + * QEMU lowRISC Ibex UART device
> + *
> + * Copyright (c) 2020 Western Digital
> + *
> + * For details check the documentation here:
> + *    https://docs.opentitan.org/hw/ip/uart/doc/
> + *
> + * 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.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "hw/char/ibex_uart.h"
> +#include "hw/irq.h"
> +#include "hw/qdev-properties.h"
> +#include "migration/vmstate.h"
> +#include "qemu/log.h"
> +#include "qemu/module.h"
> +
> +static void ibex_uart_update_irqs(IbexUartState *s)
> +{
> +    if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_TX_WATERMARK) {
> +        qemu_set_irq(s->tx_watermark, 1);
> +    } else {
> +        qemu_set_irq(s->tx_watermark, 0);
> +    }
> +
> +    if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_RX_WATERMARK) {
> +        qemu_set_irq(s->rx_watermark, 1);
> +    } else {
> +        qemu_set_irq(s->rx_watermark, 0);
> +    }
> +
> +    if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_TX_EMPTY) {
> +        qemu_set_irq(s->tx_empty, 1);
> +    } else {
> +        qemu_set_irq(s->tx_empty, 0);
> +    }
> +
> +    if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_RX_OVERFLOW) {
> +        qemu_set_irq(s->rx_overflow, 1);
> +    } else {
> +        qemu_set_irq(s->rx_overflow, 0);
> +    }
> +}
> +
> +static int ibex_uart_can_receive(void *opaque)
> +{
> +    IbexUartState *s = opaque;
> +
> +    if (s->uart_ctrl & UART_CTRL_RX_ENABLE) {
> +        return 1;
> +    }
> +
> +    return 0;
> +}
> +
> +static void ibex_uart_receive(void *opaque, const uint8_t *buf, int size)
> +{
> +    IbexUartState *s = opaque;
> +    uint8_t rx_fifo_level = (s->uart_fifo_ctrl & FIFO_CTRL_RXILVL)
> +                            >> FIFO_CTRL_RXILVL_SHIFT;
> +
> +    s->uart_rdata = *buf;
> +
> +    s->uart_status &= ~UART_STATUS_RXIDLE;
> +    s->uart_status &= ~UART_STATUS_RXEMPTY;
> +
> +    if (size > rx_fifo_level) {
> +        s->uart_intr_state |= INTR_STATE_RX_WATERMARK;
> +    }
> +
> +    ibex_uart_update_irqs(s);
> +}
> +
> +static gboolean ibex_uart_xmit(GIOChannel *chan, GIOCondition cond,
> +                               void *opaque)
> +{
> +    IbexUartState *s = opaque;
> +    uint8_t tx_fifo_level = (s->uart_fifo_ctrl & FIFO_CTRL_TXILVL)
> +                            >> FIFO_CTRL_TXILVL_SHIFT;
> +    int ret;
> +
> +    /* instant drain the fifo when there's no back-end */
> +    if (!qemu_chr_fe_backend_connected(&s->chr)) {
> +        s->tx_level = 0;
> +        return FALSE;
> +    }
> +
> +    if (!s->tx_level) {
> +        s->uart_status &= UART_STATUS_TXFULL;
Maybe  s->uart_status &= ~UART_STATUS_TXFULL;
> +        s->uart_status |= UART_STATUS_TXEMPTY;
> +        s->uart_intr_state |= INTR_STATE_TX_EMPTY;
> +        s->uart_intr_state &= ~INTR_STATE_TX_WATERMARK;
> +        ibex_uart_update_irqs(s);
> +        return FALSE;
> +    }
> +
> +    ret = qemu_chr_fe_write(&s->chr, s->tx_fifo, s->tx_level);
> +
> +    if (ret >= 0) {
> +        s->tx_level -= ret;
> +        memmove(s->tx_fifo, s->tx_fifo + ret, s->tx_level);
> +    }
> +
> +    if (s->tx_level) {
> +        guint r = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP,
> +                                        ibex_uart_xmit, s);
> +        if (!r) {
> +            s->tx_level = 0;
> +            return FALSE;
> +        }
> +    }
> +
> +    /* Clear the TX Full bit */
> +    if (s->tx_level != IBEX_UART_TX_FIFO_SIZE) {
> +        s->uart_status &= ~UART_STATUS_TXFULL;
> +    }
> +
> +    /* Disable the TX_WATERMARK IRQ */
> +    if (s->tx_level < tx_fifo_level) {
> +        s->uart_intr_state &= ~INTR_STATE_TX_WATERMARK;
> +    }
> +
> +    /* Set TX empty */
> +    if (s->tx_level == 0) {
> +        s->uart_status |= UART_STATUS_TXEMPTY;
> +        s->uart_intr_state |= INTR_STATE_TX_EMPTY;
> +    }
> +
> +    ibex_uart_update_irqs(s);
> +    return FALSE;
> +}
> +
> +static void uart_write_tx_fifo(IbexUartState *s, const uint8_t *buf,
> +                               int size)
> +{
> +    uint64_t current_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
> +    uint8_t tx_fifo_level = (s->uart_fifo_ctrl & FIFO_CTRL_TXILVL)
> +                            >> FIFO_CTRL_TXILVL_SHIFT;
> +
> +    if (size > IBEX_UART_TX_FIFO_SIZE - s->tx_level) {
> +        size = IBEX_UART_TX_FIFO_SIZE - s->tx_level;
> +        qemu_log_mask(LOG_GUEST_ERROR, "ibex_uart: TX FIFO overflow");
> +    }
> +
> +    memcpy(s->tx_fifo + s->tx_level, buf, size);
> +    s->tx_level += size;
> +
> +    if (s->tx_level > 0) {
> +        s->uart_status &= ~UART_STATUS_TXEMPTY;
> +    }
> +
> +    if (s->tx_level >= tx_fifo_level) {
> +        s->uart_intr_state |= INTR_STATE_TX_WATERMARK;
> +        ibex_uart_update_irqs(s);
> +    }
> +
> +    if (s->tx_level == IBEX_UART_TX_FIFO_SIZE) {
> +        s->uart_status |= UART_STATUS_TXFULL;
> +    }
> +
> +    timer_mod(s->fifo_trigger_handle, current_time +
> +              (s->char_tx_time * 4));
> +}
> +
> +static void ibex_uart_reset(DeviceState *dev)
> +{
> +    IbexUartState *s = IBEX_UART(dev);
> +
> +    s->uart_intr_state = 0x00000000;
> +    s->uart_intr_state = 0x00000000;
> +    s->uart_intr_enable = 0x00000000;
> +    s->uart_ctrl = 0x00000000;
> +    s->uart_status = 0x0000003c;
> +    s->uart_rdata = 0x00000000;
> +    s->uart_fifo_ctrl = 0x00000000;
> +    s->uart_fifo_status = 0x00000000;
> +    s->uart_ovrd = 0x00000000;
> +    s->uart_val = 0x00000000;
> +    s->uart_timeout_ctrl = 0x00000000;
> +
> +    s->tx_level = 0;
> +
> +    s->char_tx_time = (NANOSECONDS_PER_SECOND / 230400) * 10;
> +
> +    ibex_uart_update_irqs(s);
> +}
> +
> +static uint64_t ibex_uart_read(void *opaque, hwaddr addr,
> +                                       unsigned int size)
> +{
> +    IbexUartState *s = opaque;
> +    uint64_t retvalue = 0;
> +
> +    switch (addr) {
> +    case IBEX_UART_INTR_STATE:
> +        retvalue = s->uart_intr_state;
> +        break;
> +    case IBEX_UART_INTR_ENABLE:
> +        retvalue = s->uart_intr_enable;
> +        break;
> +    case IBEX_UART_INTR_TEST:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: wdata is write only\n", __func__);
> +        break;
> +
> +    case IBEX_UART_CTRL:
> +        retvalue = s->uart_ctrl;
> +        break;
> +    case IBEX_UART_STATUS:
> +        retvalue = s->uart_status;
> +        break;
> +
> +    case IBEX_UART_RDATA:
> +        retvalue = s->uart_rdata;
> +        if (s->uart_ctrl & UART_CTRL_RX_ENABLE) {
> +            qemu_chr_fe_accept_input(&s->chr);
> +
> +            s->uart_status |= UART_STATUS_RXIDLE;
> +            s->uart_status |= UART_STATUS_RXEMPTY;
> +        }
> +        break;
> +    case IBEX_UART_WDATA:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: wdata is write only\n", __func__);
> +        break;
> +
> +    case IBEX_UART_FIFO_CTRL:
> +        retvalue = s->uart_fifo_ctrl;
> +        break;
> +    case IBEX_UART_FIFO_STATUS:
> +        retvalue = s->uart_fifo_status;
> +
> +        retvalue |= s->tx_level & 0x1F;
> +
> +        qemu_log_mask(LOG_UNIMP,
> +                      "%s: RX fifos are not supported\n", __func__);
> +        break;
> +
> +    case IBEX_UART_OVRD:
> +        retvalue = s->uart_ovrd;
> +        qemu_log_mask(LOG_UNIMP,
> +                      "%s: ovrd is not supported\n", __func__);
> +        break;
> +    case IBEX_UART_VAL:
> +        retvalue = s->uart_val;
> +        qemu_log_mask(LOG_UNIMP,
> +                      "%s: val is not supported\n", __func__);
> +        break;
> +    case IBEX_UART_TIMEOUT_CTRL:
> +        retvalue = s->uart_timeout_ctrl;
> +        qemu_log_mask(LOG_UNIMP,
> +                      "%s: timeout_ctrl is not supported\n", __func__);
> +        break;
> +    default:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
> +        return 0;
> +    }
> +
> +    return retvalue;
> +}
> +
> +static void ibex_uart_write(void *opaque, hwaddr addr,
> +                                  uint64_t val64, unsigned int size)
> +{
> +    IbexUartState *s = opaque;
> +    uint32_t value = val64;
> +
> +    switch (addr) {
> +    case IBEX_UART_INTR_STATE:
> +        /* Write 1 clear */
> +        s->uart_intr_state &= ~value;
> +        ibex_uart_update_irqs(s);
> +        break;
> +    case IBEX_UART_INTR_ENABLE:
> +        s->uart_intr_enable = value;
> +        ibex_uart_update_irqs(s);
> +        break;
> +    case IBEX_UART_INTR_TEST:
> +        s->uart_intr_state |= value;
> +        ibex_uart_update_irqs(s);
> +        break;
> +
> +    case IBEX_UART_CTRL:
> +        s->uart_ctrl = value;
> +
> +        if (value & UART_CTRL_NF) {
> +            qemu_log_mask(LOG_UNIMP,
> +                          "%s: UART_CTRL_NF is not supported\n", __func__);
> +        }
> +        if (value & UART_CTRL_SLPBK) {
> +            qemu_log_mask(LOG_UNIMP,
> +                          "%s: UART_CTRL_SLPBK is not supported\n", __func__);
> +        }
> +        if (value & UART_CTRL_LLPBK) {
> +            qemu_log_mask(LOG_UNIMP,
> +                          "%s: UART_CTRL_LLPBK is not supported\n", __func__);
> +        }
> +        if (value & UART_CTRL_PARITY_EN) {
> +            qemu_log_mask(LOG_UNIMP,
> +                          "%s: UART_CTRL_PARITY_EN is not supported\n",
> +                          __func__);
> +        }
> +        if (value & UART_CTRL_PARITY_ODD) {
> +            qemu_log_mask(LOG_UNIMP,
> +                          "%s: UART_CTRL_PARITY_ODD is not supported\n",
> +                          __func__);
> +        }
> +        if (value & UART_CTRL_RXBLVL) {
> +            qemu_log_mask(LOG_UNIMP,
> +                          "%s: UART_CTRL_RXBLVL is not supported\n", __func__);
> +        }
> +        if (value & UART_CTRL_NCO) {
> +            uint64_t baud = ((value & UART_CTRL_NCO) >> 16);
> +            baud *= 1000;
> +            baud /= 2 ^ 20;
> +
> +            s->char_tx_time = (NANOSECONDS_PER_SECOND / baud) * 10;
> +        }
> +        break;
> +    case IBEX_UART_STATUS:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: status is read only\n", __func__);
> +        break;
> +
> +    case IBEX_UART_RDATA:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: rdata is read only\n", __func__);
> +        break;
> +    case IBEX_UART_WDATA:
> +        uart_write_tx_fifo(s, (uint8_t *) &value, 1);
> +        break;
> +
> +    case IBEX_UART_FIFO_CTRL:
> +        s->uart_fifo_ctrl = value;
> +
> +        if (value & FIFO_CTRL_RXRST) {
> +            qemu_log_mask(LOG_UNIMP,
> +                          "%s: RX fifos are not supported\n", __func__);
> +        }
> +        if (value & FIFO_CTRL_TXRST) {
> +            s->tx_level = 0;
> +        }
> +        break;
> +    case IBEX_UART_FIFO_STATUS:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: fifo_status is read only\n", __func__);
> +        break;
> +
> +    case IBEX_UART_OVRD:
> +        s->uart_ovrd = value;
> +        qemu_log_mask(LOG_UNIMP,
> +                      "%s: ovrd is not supported\n", __func__);
> +        break;
> +    case IBEX_UART_VAL:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: val is read only\n", __func__);
> +        break;
> +    case IBEX_UART_TIMEOUT_CTRL:
> +        s->uart_timeout_ctrl = value;
> +        qemu_log_mask(LOG_UNIMP,
> +                      "%s: timeout_ctrl is not supported\n", __func__);
> +        break;
> +    default:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
> +    }
> +}
> +
> +static void fifo_trigger_update(void *opaque)
> +{
> +    IbexUartState *s = opaque;
> +
> +    if (s->uart_ctrl & UART_CTRL_TX_ENABLE) {
> +        ibex_uart_xmit(NULL, G_IO_OUT, s);
> +    }
> +}
> +
> +static const MemoryRegionOps ibex_uart_ops = {
> +    .read = ibex_uart_read,
> +    .write = ibex_uart_write,
> +    .endianness = DEVICE_NATIVE_ENDIAN,
> +    .impl.min_access_size = 4,
> +    .impl.max_access_size = 4,
> +};
> +
> +static int cadence_uart_post_load(void *opaque, int version_id)
Not a good name.
> +{
> +    IbexUartState *s = opaque;
> +
> +    ibex_uart_update_irqs(s);
> +    return 0;
> +}
> +
> +static const VMStateDescription vmstate_ibex_uart = {
> +    .name = TYPE_IBEX_UART,
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .post_load = cadence_uart_post_load,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT8_ARRAY(tx_fifo, IbexUartState,
> +                            IBEX_UART_TX_FIFO_SIZE),
> +        VMSTATE_UINT32(tx_level, IbexUartState),
> +        VMSTATE_UINT64(char_tx_time, IbexUartState),
> +        VMSTATE_TIMER_PTR(fifo_trigger_handle, IbexUartState),
> +        VMSTATE_UINT32(uart_intr_state, IbexUartState),
> +        VMSTATE_UINT32(uart_intr_enable, IbexUartState),
> +        VMSTATE_UINT32(uart_ctrl, IbexUartState),
> +        VMSTATE_UINT32(uart_status, IbexUartState),
> +        VMSTATE_UINT32(uart_rdata, IbexUartState),
> +        VMSTATE_UINT32(uart_fifo_ctrl, IbexUartState),
> +        VMSTATE_UINT32(uart_fifo_status, IbexUartState),
> +        VMSTATE_UINT32(uart_ovrd, IbexUartState),
> +        VMSTATE_UINT32(uart_val, IbexUartState),
> +        VMSTATE_UINT32(uart_timeout_ctrl, IbexUartState),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static Property ibex_uart_properties[] = {
> +    DEFINE_PROP_CHR("chardev", IbexUartState, chr),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void ibex_uart_init(Object *obj)
> +{
> +    IbexUartState *s = IBEX_UART(obj);
> +
> +    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->tx_watermark);
> +    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->rx_watermark);
> +    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->tx_empty);
> +    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->rx_overflow);
> +
> +    memory_region_init_io(&s->mmio, obj, &ibex_uart_ops, s,
> +                          TYPE_IBEX_UART, 0x400);
> +    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
> +}
> +
> +static void ibex_uart_realize(DeviceState *dev, Error **errp)
> +{
> +    IbexUartState *s = IBEX_UART(dev);
> +
> +    s->fifo_trigger_handle = timer_new_ns(QEMU_CLOCK_VIRTUAL,
> +                                          fifo_trigger_update, s);
> +
> +    qemu_chr_fe_set_handlers(&s->chr, ibex_uart_can_receive,
> +                             ibex_uart_receive, NULL, NULL,
> +                             s, NULL, true);
> +}
> +
> +static void ibex_uart_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->reset = ibex_uart_reset;
> +    dc->realize = ibex_uart_realize;
> +    dc->vmsd = &vmstate_ibex_uart;
> +    device_class_set_props(dc, ibex_uart_properties);
> +}
> +
> +static const TypeInfo ibex_uart_info = {
> +    .name          = TYPE_IBEX_UART,
> +    .parent        = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(IbexUartState),
> +    .instance_init = ibex_uart_init,
> +    .class_init    = ibex_uart_class_init,
> +};
> +
> +static void ibex_uart_register_types(void)
> +{
> +    type_register_static(&ibex_uart_info);
> +}
> +
> +type_init(ibex_uart_register_types)
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 3e7d9cb0a5..a1ce186a7e 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1245,7 +1245,9 @@ M: Alistair Francis <Alistair.Francis@wdc.com>
>   L: qemu-riscv@nongnu.org
>   S: Supported
>   F: hw/riscv/opentitan.c
> +F: hw/char/ibex_uart.c
>   F: include/hw/riscv/opentitan.h
> +F: include/hw/char/ibex_uart.h
>   
>   SH4 Machines
>   ------------
> diff --git a/hw/char/Makefile.objs b/hw/char/Makefile.objs
> index 9e9a6c1aff..633996be5b 100644
> --- a/hw/char/Makefile.objs
> +++ b/hw/char/Makefile.objs
> @@ -12,6 +12,7 @@ common-obj-$(CONFIG_VIRTIO_SERIAL) += virtio-console.o
>   common-obj-$(CONFIG_XILINX) += xilinx_uartlite.o
>   common-obj-$(CONFIG_XEN) += xen_console.o
>   common-obj-$(CONFIG_CADENCE) += cadence_uart.o
> +common-obj-$(CONFIG_IBEX) += ibex_uart.o
>   
>   common-obj-$(CONFIG_EXYNOS4) += exynos4210_uart.o
>   common-obj-$(CONFIG_COLDFIRE) += mcf_uart.o
> diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
> index 94d19571f7..28947ef3e0 100644
> --- a/hw/riscv/Kconfig
> +++ b/hw/riscv/Kconfig
> @@ -4,6 +4,9 @@ config HTIF
>   config HART
>       bool
>   
> +config IBEX
> +    bool
> +
>   config SIFIVE
>       bool
>       select MSI_NONBROKEN
> @@ -29,6 +32,7 @@ config SPIKE
>   
>   config OPENTITAN
>       bool
> +    select IBEX
>       select HART
>       select UNIMP
>   



^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v5 07/11] hw/char: Initial commit of Ibex UART
  2020-06-02 11:22     ` LIU Zhiwei
@ 2020-06-02 12:28       ` LIU Zhiwei
  -1 siblings, 0 replies; 68+ messages in thread
From: LIU Zhiwei @ 2020-06-02 12:28 UTC (permalink / raw)
  To: Alistair Francis
  Cc: open list:RISC-V, Bin Meng, Palmer Dabbelt,
	qemu-devel@nongnu.org Developers

Hi Alistair,

There are still some questions I don't understand.

1. Is the baud rate  or fifo a necessary feature to simulate?
As you can see, qemu_chr_fe_write will send the byte as soon as possible.
When you want to transmit a byte through WDATA,  you can call 
qemu_chr_fe_write directly.

2.  The baud rate calculation method is not strictly right.
I think when a byte write to FIFO,  char_tx_time * 8 is the correct time 
to send the byte instead of
char_tx_time * 4.

3.  Why add a watch here?
> +        s->uart_status |= UART_STATUS_TXEMPTY;
> +        s->uart_intr_state |= INTR_STATE_TX_EMPTY;
> +        s->uart_intr_state &= ~INTR_STATE_TX_WATERMARK;
> +        ibex_uart_update_irqs(s);
> +        return FALSE;
> +    }
> +
> +    ret = qemu_chr_fe_write(&s->chr, s->tx_fifo, s->tx_level);
> +
> +    if (ret >= 0) {
> +        s->tx_level -= ret;
> +        memmove(s->tx_fifo, s->tx_fifo + ret, s->tx_level);
> +    }
> +
> +    if (s->tx_level) {
> +        guint r = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP,
> +                                        ibex_uart_xmit, s);
> +        if (!r) {
> +            s->tx_level = 0;
> +            return FALSE;
> +        }
> +    }
> + 

Zhiwei



^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v5 07/11] hw/char: Initial commit of Ibex UART
@ 2020-06-02 12:28       ` LIU Zhiwei
  0 siblings, 0 replies; 68+ messages in thread
From: LIU Zhiwei @ 2020-06-02 12:28 UTC (permalink / raw)
  To: Alistair Francis
  Cc: Bin Meng, Palmer Dabbelt, qemu-devel@nongnu.org Developers,
	open list:RISC-V

Hi Alistair,

There are still some questions I don't understand.

1. Is the baud rate  or fifo a necessary feature to simulate?
As you can see, qemu_chr_fe_write will send the byte as soon as possible.
When you want to transmit a byte through WDATA,  you can call 
qemu_chr_fe_write directly.

2.  The baud rate calculation method is not strictly right.
I think when a byte write to FIFO,  char_tx_time * 8 is the correct time 
to send the byte instead of
char_tx_time * 4.

3.  Why add a watch here?
> +        s->uart_status |= UART_STATUS_TXEMPTY;
> +        s->uart_intr_state |= INTR_STATE_TX_EMPTY;
> +        s->uart_intr_state &= ~INTR_STATE_TX_WATERMARK;
> +        ibex_uart_update_irqs(s);
> +        return FALSE;
> +    }
> +
> +    ret = qemu_chr_fe_write(&s->chr, s->tx_fifo, s->tx_level);
> +
> +    if (ret >= 0) {
> +        s->tx_level -= ret;
> +        memmove(s->tx_fifo, s->tx_fifo + ret, s->tx_level);
> +    }
> +
> +    if (s->tx_level) {
> +        guint r = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP,
> +                                        ibex_uart_xmit, s);
> +        if (!r) {
> +            s->tx_level = 0;
> +            return FALSE;
> +        }
> +    }
> + 

Zhiwei



^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v5 07/11] hw/char: Initial commit of Ibex UART
  2020-06-02 11:22     ` LIU Zhiwei
@ 2020-06-02 17:46       ` Alistair Francis
  -1 siblings, 0 replies; 68+ messages in thread
From: Alistair Francis @ 2020-06-02 17:46 UTC (permalink / raw)
  To: LIU Zhiwei
  Cc: open list:RISC-V, Bin Meng, Alistair Francis, Palmer Dabbelt,
	qemu-devel@nongnu.org Developers

On Tue, Jun 2, 2020 at 4:22 AM LIU Zhiwei <zhiwei_liu@c-sky.com> wrote:
>
>
>
> On 2020/5/29 6:14, Alistair Francis wrote:
> > This is the initial commit of the Ibex UART device. Serial TX is
> > working, while RX has been implemeneted but untested.
> >
> > This is based on the documentation from:
> > https://docs.opentitan.org/hw/ip/uart/doc/
> >
> > Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> > ---
> >   include/hw/char/ibex_uart.h | 110 ++++++++
> >   hw/char/ibex_uart.c         | 492 ++++++++++++++++++++++++++++++++++++
> >   MAINTAINERS                 |   2 +
> >   hw/char/Makefile.objs       |   1 +
> >   hw/riscv/Kconfig            |   4 +
> >   5 files changed, 609 insertions(+)
> >   create mode 100644 include/hw/char/ibex_uart.h
> >   create mode 100644 hw/char/ibex_uart.c
> >
> > diff --git a/include/hw/char/ibex_uart.h b/include/hw/char/ibex_uart.h
> > new file mode 100644
> > index 0000000000..2bec772615
> > --- /dev/null
> > +++ b/include/hw/char/ibex_uart.h
> > @@ -0,0 +1,110 @@
> > +/*
> > + * QEMU lowRISC Ibex UART device
> > + *
> > + * Copyright (c) 2020 Western Digital
> > + *
> > + * 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.
> > + */
> > +
> > +#ifndef HW_IBEX_UART_H
> > +#define HW_IBEX_UART_H
> > +
> > +#include "hw/sysbus.h"
> > +#include "chardev/char-fe.h"
> > +#include "qemu/timer.h"
> > +
> > +#define IBEX_UART_INTR_STATE   0x00
> > +    #define INTR_STATE_TX_WATERMARK (1 << 0)
> > +    #define INTR_STATE_RX_WATERMARK (1 << 1)
> > +    #define INTR_STATE_TX_EMPTY     (1 << 2)
> > +    #define INTR_STATE_RX_OVERFLOW  (1 << 3)
> > +#define IBEX_UART_INTR_ENABLE  0x04
> > +#define IBEX_UART_INTR_TEST    0x08
> > +
> > +#define IBEX_UART_CTRL         0x0c
> > +    #define UART_CTRL_TX_ENABLE     (1 << 0)
> > +    #define UART_CTRL_RX_ENABLE     (1 << 1)
> > +    #define UART_CTRL_NF            (1 << 2)
> > +    #define UART_CTRL_SLPBK         (1 << 4)
> > +    #define UART_CTRL_LLPBK         (1 << 5)
> > +    #define UART_CTRL_PARITY_EN     (1 << 6)
> > +    #define UART_CTRL_PARITY_ODD    (1 << 7)
> > +    #define UART_CTRL_RXBLVL        (3 << 8)
> > +    #define UART_CTRL_NCO           (0xFFFF << 16)
> > +
> > +#define IBEX_UART_STATUS       0x10
> > +    #define UART_STATUS_TXFULL  (1 << 0)
> > +    #define UART_STATUS_RXFULL  (1 << 1)
> > +    #define UART_STATUS_TXEMPTY (1 << 2)
> > +    #define UART_STATUS_RXIDLE  (1 << 4)
> > +    #define UART_STATUS_RXEMPTY (1 << 5)
> > +
> > +#define IBEX_UART_RDATA        0x14
> > +#define IBEX_UART_WDATA        0x18
> > +
> > +#define IBEX_UART_FIFO_CTRL    0x1c
> > +    #define FIFO_CTRL_RXRST          (1 << 0)
> > +    #define FIFO_CTRL_TXRST          (1 << 1)
> > +    #define FIFO_CTRL_RXILVL         (7 << 2)
> > +    #define FIFO_CTRL_RXILVL_SHIFT   (2)
> > +    #define FIFO_CTRL_TXILVL         (3 << 5)
> > +    #define FIFO_CTRL_TXILVL_SHIFT   (5)
> > +
> > +#define IBEX_UART_FIFO_STATUS  0x20
> > +#define IBEX_UART_OVRD         0x24
> > +#define IBEX_UART_VAL          0x28
> > +#define IBEX_UART_TIMEOUT_CTRL 0x2c
> > +
> > +#define IBEX_UART_TX_FIFO_SIZE 16
> > +
> > +#define TYPE_IBEX_UART "ibex-uart"
> > +#define IBEX_UART(obj) \
> > +    OBJECT_CHECK(IbexUartState, (obj), TYPE_IBEX_UART)
> > +
> > +typedef struct {
> > +    /* <private> */
> > +    SysBusDevice parent_obj;
> > +
> > +    /* <public> */
> > +    MemoryRegion mmio;
> > +
> > +    uint8_t tx_fifo[IBEX_UART_TX_FIFO_SIZE];
> > +    uint32_t tx_level;
> > +
> > +    QEMUTimer *fifo_trigger_handle;
> > +    uint64_t char_tx_time;
> > +
> > +    uint32_t uart_intr_state;
> > +    uint32_t uart_intr_enable;
> > +    uint32_t uart_ctrl;
> > +    uint32_t uart_status;
> > +    uint32_t uart_rdata;
> > +    uint32_t uart_fifo_ctrl;
> > +    uint32_t uart_fifo_status;
> > +    uint32_t uart_ovrd;
> > +    uint32_t uart_val;
> > +    uint32_t uart_timeout_ctrl;
> > +
> > +    CharBackend chr;
> > +    qemu_irq tx_watermark;
> > +    qemu_irq rx_watermark;
> > +    qemu_irq tx_empty;
> > +    qemu_irq rx_overflow;
> > +} IbexUartState;
> > +#endif /* HW_IBEX_UART_H */
> > diff --git a/hw/char/ibex_uart.c b/hw/char/ibex_uart.c
> > new file mode 100644
> > index 0000000000..c416325d73
> > --- /dev/null
> > +++ b/hw/char/ibex_uart.c
> > @@ -0,0 +1,492 @@
> > +/*
> > + * QEMU lowRISC Ibex UART device
> > + *
> > + * Copyright (c) 2020 Western Digital
> > + *
> > + * For details check the documentation here:
> > + *    https://docs.opentitan.org/hw/ip/uart/doc/
> > + *
> > + * 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.
> > + */
> > +
> > +#include "qemu/osdep.h"
> > +#include "hw/char/ibex_uart.h"
> > +#include "hw/irq.h"
> > +#include "hw/qdev-properties.h"
> > +#include "migration/vmstate.h"
> > +#include "qemu/log.h"
> > +#include "qemu/module.h"
> > +
> > +static void ibex_uart_update_irqs(IbexUartState *s)
> > +{
> > +    if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_TX_WATERMARK) {
> > +        qemu_set_irq(s->tx_watermark, 1);
> > +    } else {
> > +        qemu_set_irq(s->tx_watermark, 0);
> > +    }
> > +
> > +    if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_RX_WATERMARK) {
> > +        qemu_set_irq(s->rx_watermark, 1);
> > +    } else {
> > +        qemu_set_irq(s->rx_watermark, 0);
> > +    }
> > +
> > +    if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_TX_EMPTY) {
> > +        qemu_set_irq(s->tx_empty, 1);
> > +    } else {
> > +        qemu_set_irq(s->tx_empty, 0);
> > +    }
> > +
> > +    if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_RX_OVERFLOW) {
> > +        qemu_set_irq(s->rx_overflow, 1);
> > +    } else {
> > +        qemu_set_irq(s->rx_overflow, 0);
> > +    }
> > +}
> > +
> > +static int ibex_uart_can_receive(void *opaque)
> > +{
> > +    IbexUartState *s = opaque;
> > +
> > +    if (s->uart_ctrl & UART_CTRL_RX_ENABLE) {
> > +        return 1;
> > +    }
> > +
> > +    return 0;
> > +}
> > +
> > +static void ibex_uart_receive(void *opaque, const uint8_t *buf, int size)
> > +{
> > +    IbexUartState *s = opaque;
> > +    uint8_t rx_fifo_level = (s->uart_fifo_ctrl & FIFO_CTRL_RXILVL)
> > +                            >> FIFO_CTRL_RXILVL_SHIFT;
> > +
> > +    s->uart_rdata = *buf;
> > +
> > +    s->uart_status &= ~UART_STATUS_RXIDLE;
> > +    s->uart_status &= ~UART_STATUS_RXEMPTY;
> > +
> > +    if (size > rx_fifo_level) {
> > +        s->uart_intr_state |= INTR_STATE_RX_WATERMARK;
> > +    }
> > +
> > +    ibex_uart_update_irqs(s);
> > +}
> > +
> > +static gboolean ibex_uart_xmit(GIOChannel *chan, GIOCondition cond,
> > +                               void *opaque)
> > +{
> > +    IbexUartState *s = opaque;
> > +    uint8_t tx_fifo_level = (s->uart_fifo_ctrl & FIFO_CTRL_TXILVL)
> > +                            >> FIFO_CTRL_TXILVL_SHIFT;
> > +    int ret;
> > +
> > +    /* instant drain the fifo when there's no back-end */
> > +    if (!qemu_chr_fe_backend_connected(&s->chr)) {
> > +        s->tx_level = 0;
> > +        return FALSE;
> > +    }
> > +
> > +    if (!s->tx_level) {
> > +        s->uart_status &= UART_STATUS_TXFULL;
> Maybe  s->uart_status &= ~UART_STATUS_TXFULL;

Good spot, fixed.

> > +        s->uart_status |= UART_STATUS_TXEMPTY;
> > +        s->uart_intr_state |= INTR_STATE_TX_EMPTY;
> > +        s->uart_intr_state &= ~INTR_STATE_TX_WATERMARK;
> > +        ibex_uart_update_irqs(s);
> > +        return FALSE;
> > +    }
> > +
> > +    ret = qemu_chr_fe_write(&s->chr, s->tx_fifo, s->tx_level);
> > +
> > +    if (ret >= 0) {
> > +        s->tx_level -= ret;
> > +        memmove(s->tx_fifo, s->tx_fifo + ret, s->tx_level);
> > +    }
> > +
> > +    if (s->tx_level) {
> > +        guint r = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP,
> > +                                        ibex_uart_xmit, s);
> > +        if (!r) {
> > +            s->tx_level = 0;
> > +            return FALSE;
> > +        }
> > +    }
> > +
> > +    /* Clear the TX Full bit */
> > +    if (s->tx_level != IBEX_UART_TX_FIFO_SIZE) {
> > +        s->uart_status &= ~UART_STATUS_TXFULL;
> > +    }
> > +
> > +    /* Disable the TX_WATERMARK IRQ */
> > +    if (s->tx_level < tx_fifo_level) {
> > +        s->uart_intr_state &= ~INTR_STATE_TX_WATERMARK;
> > +    }
> > +
> > +    /* Set TX empty */
> > +    if (s->tx_level == 0) {
> > +        s->uart_status |= UART_STATUS_TXEMPTY;
> > +        s->uart_intr_state |= INTR_STATE_TX_EMPTY;
> > +    }
> > +
> > +    ibex_uart_update_irqs(s);
> > +    return FALSE;
> > +}
> > +
> > +static void uart_write_tx_fifo(IbexUartState *s, const uint8_t *buf,
> > +                               int size)
> > +{
> > +    uint64_t current_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
> > +    uint8_t tx_fifo_level = (s->uart_fifo_ctrl & FIFO_CTRL_TXILVL)
> > +                            >> FIFO_CTRL_TXILVL_SHIFT;
> > +
> > +    if (size > IBEX_UART_TX_FIFO_SIZE - s->tx_level) {
> > +        size = IBEX_UART_TX_FIFO_SIZE - s->tx_level;
> > +        qemu_log_mask(LOG_GUEST_ERROR, "ibex_uart: TX FIFO overflow");
> > +    }
> > +
> > +    memcpy(s->tx_fifo + s->tx_level, buf, size);
> > +    s->tx_level += size;
> > +
> > +    if (s->tx_level > 0) {
> > +        s->uart_status &= ~UART_STATUS_TXEMPTY;
> > +    }
> > +
> > +    if (s->tx_level >= tx_fifo_level) {
> > +        s->uart_intr_state |= INTR_STATE_TX_WATERMARK;
> > +        ibex_uart_update_irqs(s);
> > +    }
> > +
> > +    if (s->tx_level == IBEX_UART_TX_FIFO_SIZE) {
> > +        s->uart_status |= UART_STATUS_TXFULL;
> > +    }
> > +
> > +    timer_mod(s->fifo_trigger_handle, current_time +
> > +              (s->char_tx_time * 4));
> > +}
> > +
> > +static void ibex_uart_reset(DeviceState *dev)
> > +{
> > +    IbexUartState *s = IBEX_UART(dev);
> > +
> > +    s->uart_intr_state = 0x00000000;
> > +    s->uart_intr_state = 0x00000000;
> > +    s->uart_intr_enable = 0x00000000;
> > +    s->uart_ctrl = 0x00000000;
> > +    s->uart_status = 0x0000003c;
> > +    s->uart_rdata = 0x00000000;
> > +    s->uart_fifo_ctrl = 0x00000000;
> > +    s->uart_fifo_status = 0x00000000;
> > +    s->uart_ovrd = 0x00000000;
> > +    s->uart_val = 0x00000000;
> > +    s->uart_timeout_ctrl = 0x00000000;
> > +
> > +    s->tx_level = 0;
> > +
> > +    s->char_tx_time = (NANOSECONDS_PER_SECOND / 230400) * 10;
> > +
> > +    ibex_uart_update_irqs(s);
> > +}
> > +
> > +static uint64_t ibex_uart_read(void *opaque, hwaddr addr,
> > +                                       unsigned int size)
> > +{
> > +    IbexUartState *s = opaque;
> > +    uint64_t retvalue = 0;
> > +
> > +    switch (addr) {
> > +    case IBEX_UART_INTR_STATE:
> > +        retvalue = s->uart_intr_state;
> > +        break;
> > +    case IBEX_UART_INTR_ENABLE:
> > +        retvalue = s->uart_intr_enable;
> > +        break;
> > +    case IBEX_UART_INTR_TEST:
> > +        qemu_log_mask(LOG_GUEST_ERROR,
> > +                      "%s: wdata is write only\n", __func__);
> > +        break;
> > +
> > +    case IBEX_UART_CTRL:
> > +        retvalue = s->uart_ctrl;
> > +        break;
> > +    case IBEX_UART_STATUS:
> > +        retvalue = s->uart_status;
> > +        break;
> > +
> > +    case IBEX_UART_RDATA:
> > +        retvalue = s->uart_rdata;
> > +        if (s->uart_ctrl & UART_CTRL_RX_ENABLE) {
> > +            qemu_chr_fe_accept_input(&s->chr);
> > +
> > +            s->uart_status |= UART_STATUS_RXIDLE;
> > +            s->uart_status |= UART_STATUS_RXEMPTY;
> > +        }
> > +        break;
> > +    case IBEX_UART_WDATA:
> > +        qemu_log_mask(LOG_GUEST_ERROR,
> > +                      "%s: wdata is write only\n", __func__);
> > +        break;
> > +
> > +    case IBEX_UART_FIFO_CTRL:
> > +        retvalue = s->uart_fifo_ctrl;
> > +        break;
> > +    case IBEX_UART_FIFO_STATUS:
> > +        retvalue = s->uart_fifo_status;
> > +
> > +        retvalue |= s->tx_level & 0x1F;
> > +
> > +        qemu_log_mask(LOG_UNIMP,
> > +                      "%s: RX fifos are not supported\n", __func__);
> > +        break;
> > +
> > +    case IBEX_UART_OVRD:
> > +        retvalue = s->uart_ovrd;
> > +        qemu_log_mask(LOG_UNIMP,
> > +                      "%s: ovrd is not supported\n", __func__);
> > +        break;
> > +    case IBEX_UART_VAL:
> > +        retvalue = s->uart_val;
> > +        qemu_log_mask(LOG_UNIMP,
> > +                      "%s: val is not supported\n", __func__);
> > +        break;
> > +    case IBEX_UART_TIMEOUT_CTRL:
> > +        retvalue = s->uart_timeout_ctrl;
> > +        qemu_log_mask(LOG_UNIMP,
> > +                      "%s: timeout_ctrl is not supported\n", __func__);
> > +        break;
> > +    default:
> > +        qemu_log_mask(LOG_GUEST_ERROR,
> > +                      "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
> > +        return 0;
> > +    }
> > +
> > +    return retvalue;
> > +}
> > +
> > +static void ibex_uart_write(void *opaque, hwaddr addr,
> > +                                  uint64_t val64, unsigned int size)
> > +{
> > +    IbexUartState *s = opaque;
> > +    uint32_t value = val64;
> > +
> > +    switch (addr) {
> > +    case IBEX_UART_INTR_STATE:
> > +        /* Write 1 clear */
> > +        s->uart_intr_state &= ~value;
> > +        ibex_uart_update_irqs(s);
> > +        break;
> > +    case IBEX_UART_INTR_ENABLE:
> > +        s->uart_intr_enable = value;
> > +        ibex_uart_update_irqs(s);
> > +        break;
> > +    case IBEX_UART_INTR_TEST:
> > +        s->uart_intr_state |= value;
> > +        ibex_uart_update_irqs(s);
> > +        break;
> > +
> > +    case IBEX_UART_CTRL:
> > +        s->uart_ctrl = value;
> > +
> > +        if (value & UART_CTRL_NF) {
> > +            qemu_log_mask(LOG_UNIMP,
> > +                          "%s: UART_CTRL_NF is not supported\n", __func__);
> > +        }
> > +        if (value & UART_CTRL_SLPBK) {
> > +            qemu_log_mask(LOG_UNIMP,
> > +                          "%s: UART_CTRL_SLPBK is not supported\n", __func__);
> > +        }
> > +        if (value & UART_CTRL_LLPBK) {
> > +            qemu_log_mask(LOG_UNIMP,
> > +                          "%s: UART_CTRL_LLPBK is not supported\n", __func__);
> > +        }
> > +        if (value & UART_CTRL_PARITY_EN) {
> > +            qemu_log_mask(LOG_UNIMP,
> > +                          "%s: UART_CTRL_PARITY_EN is not supported\n",
> > +                          __func__);
> > +        }
> > +        if (value & UART_CTRL_PARITY_ODD) {
> > +            qemu_log_mask(LOG_UNIMP,
> > +                          "%s: UART_CTRL_PARITY_ODD is not supported\n",
> > +                          __func__);
> > +        }
> > +        if (value & UART_CTRL_RXBLVL) {
> > +            qemu_log_mask(LOG_UNIMP,
> > +                          "%s: UART_CTRL_RXBLVL is not supported\n", __func__);
> > +        }
> > +        if (value & UART_CTRL_NCO) {
> > +            uint64_t baud = ((value & UART_CTRL_NCO) >> 16);
> > +            baud *= 1000;
> > +            baud /= 2 ^ 20;
> > +
> > +            s->char_tx_time = (NANOSECONDS_PER_SECOND / baud) * 10;
> > +        }
> > +        break;
> > +    case IBEX_UART_STATUS:
> > +        qemu_log_mask(LOG_GUEST_ERROR,
> > +                      "%s: status is read only\n", __func__);
> > +        break;
> > +
> > +    case IBEX_UART_RDATA:
> > +        qemu_log_mask(LOG_GUEST_ERROR,
> > +                      "%s: rdata is read only\n", __func__);
> > +        break;
> > +    case IBEX_UART_WDATA:
> > +        uart_write_tx_fifo(s, (uint8_t *) &value, 1);
> > +        break;
> > +
> > +    case IBEX_UART_FIFO_CTRL:
> > +        s->uart_fifo_ctrl = value;
> > +
> > +        if (value & FIFO_CTRL_RXRST) {
> > +            qemu_log_mask(LOG_UNIMP,
> > +                          "%s: RX fifos are not supported\n", __func__);
> > +        }
> > +        if (value & FIFO_CTRL_TXRST) {
> > +            s->tx_level = 0;
> > +        }
> > +        break;
> > +    case IBEX_UART_FIFO_STATUS:
> > +        qemu_log_mask(LOG_GUEST_ERROR,
> > +                      "%s: fifo_status is read only\n", __func__);
> > +        break;
> > +
> > +    case IBEX_UART_OVRD:
> > +        s->uart_ovrd = value;
> > +        qemu_log_mask(LOG_UNIMP,
> > +                      "%s: ovrd is not supported\n", __func__);
> > +        break;
> > +    case IBEX_UART_VAL:
> > +        qemu_log_mask(LOG_GUEST_ERROR,
> > +                      "%s: val is read only\n", __func__);
> > +        break;
> > +    case IBEX_UART_TIMEOUT_CTRL:
> > +        s->uart_timeout_ctrl = value;
> > +        qemu_log_mask(LOG_UNIMP,
> > +                      "%s: timeout_ctrl is not supported\n", __func__);
> > +        break;
> > +    default:
> > +        qemu_log_mask(LOG_GUEST_ERROR,
> > +                      "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
> > +    }
> > +}
> > +
> > +static void fifo_trigger_update(void *opaque)
> > +{
> > +    IbexUartState *s = opaque;
> > +
> > +    if (s->uart_ctrl & UART_CTRL_TX_ENABLE) {
> > +        ibex_uart_xmit(NULL, G_IO_OUT, s);
> > +    }
> > +}
> > +
> > +static const MemoryRegionOps ibex_uart_ops = {
> > +    .read = ibex_uart_read,
> > +    .write = ibex_uart_write,
> > +    .endianness = DEVICE_NATIVE_ENDIAN,
> > +    .impl.min_access_size = 4,
> > +    .impl.max_access_size = 4,
> > +};
> > +
> > +static int cadence_uart_post_load(void *opaque, int version_id)
> Not a good name.

Also fixed.

Alistair

> > +{
> > +    IbexUartState *s = opaque;
> > +
> > +    ibex_uart_update_irqs(s);
> > +    return 0;
> > +}
> > +
> > +static const VMStateDescription vmstate_ibex_uart = {
> > +    .name = TYPE_IBEX_UART,
> > +    .version_id = 1,
> > +    .minimum_version_id = 1,
> > +    .post_load = cadence_uart_post_load,
> > +    .fields = (VMStateField[]) {
> > +        VMSTATE_UINT8_ARRAY(tx_fifo, IbexUartState,
> > +                            IBEX_UART_TX_FIFO_SIZE),
> > +        VMSTATE_UINT32(tx_level, IbexUartState),
> > +        VMSTATE_UINT64(char_tx_time, IbexUartState),
> > +        VMSTATE_TIMER_PTR(fifo_trigger_handle, IbexUartState),
> > +        VMSTATE_UINT32(uart_intr_state, IbexUartState),
> > +        VMSTATE_UINT32(uart_intr_enable, IbexUartState),
> > +        VMSTATE_UINT32(uart_ctrl, IbexUartState),
> > +        VMSTATE_UINT32(uart_status, IbexUartState),
> > +        VMSTATE_UINT32(uart_rdata, IbexUartState),
> > +        VMSTATE_UINT32(uart_fifo_ctrl, IbexUartState),
> > +        VMSTATE_UINT32(uart_fifo_status, IbexUartState),
> > +        VMSTATE_UINT32(uart_ovrd, IbexUartState),
> > +        VMSTATE_UINT32(uart_val, IbexUartState),
> > +        VMSTATE_UINT32(uart_timeout_ctrl, IbexUartState),
> > +        VMSTATE_END_OF_LIST()
> > +    }
> > +};
> > +
> > +static Property ibex_uart_properties[] = {
> > +    DEFINE_PROP_CHR("chardev", IbexUartState, chr),
> > +    DEFINE_PROP_END_OF_LIST(),
> > +};
> > +
> > +static void ibex_uart_init(Object *obj)
> > +{
> > +    IbexUartState *s = IBEX_UART(obj);
> > +
> > +    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->tx_watermark);
> > +    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->rx_watermark);
> > +    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->tx_empty);
> > +    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->rx_overflow);
> > +
> > +    memory_region_init_io(&s->mmio, obj, &ibex_uart_ops, s,
> > +                          TYPE_IBEX_UART, 0x400);
> > +    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
> > +}
> > +
> > +static void ibex_uart_realize(DeviceState *dev, Error **errp)
> > +{
> > +    IbexUartState *s = IBEX_UART(dev);
> > +
> > +    s->fifo_trigger_handle = timer_new_ns(QEMU_CLOCK_VIRTUAL,
> > +                                          fifo_trigger_update, s);
> > +
> > +    qemu_chr_fe_set_handlers(&s->chr, ibex_uart_can_receive,
> > +                             ibex_uart_receive, NULL, NULL,
> > +                             s, NULL, true);
> > +}
> > +
> > +static void ibex_uart_class_init(ObjectClass *klass, void *data)
> > +{
> > +    DeviceClass *dc = DEVICE_CLASS(klass);
> > +
> > +    dc->reset = ibex_uart_reset;
> > +    dc->realize = ibex_uart_realize;
> > +    dc->vmsd = &vmstate_ibex_uart;
> > +    device_class_set_props(dc, ibex_uart_properties);
> > +}
> > +
> > +static const TypeInfo ibex_uart_info = {
> > +    .name          = TYPE_IBEX_UART,
> > +    .parent        = TYPE_SYS_BUS_DEVICE,
> > +    .instance_size = sizeof(IbexUartState),
> > +    .instance_init = ibex_uart_init,
> > +    .class_init    = ibex_uart_class_init,
> > +};
> > +
> > +static void ibex_uart_register_types(void)
> > +{
> > +    type_register_static(&ibex_uart_info);
> > +}
> > +
> > +type_init(ibex_uart_register_types)
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index 3e7d9cb0a5..a1ce186a7e 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -1245,7 +1245,9 @@ M: Alistair Francis <Alistair.Francis@wdc.com>
> >   L: qemu-riscv@nongnu.org
> >   S: Supported
> >   F: hw/riscv/opentitan.c
> > +F: hw/char/ibex_uart.c
> >   F: include/hw/riscv/opentitan.h
> > +F: include/hw/char/ibex_uart.h
> >
> >   SH4 Machines
> >   ------------
> > diff --git a/hw/char/Makefile.objs b/hw/char/Makefile.objs
> > index 9e9a6c1aff..633996be5b 100644
> > --- a/hw/char/Makefile.objs
> > +++ b/hw/char/Makefile.objs
> > @@ -12,6 +12,7 @@ common-obj-$(CONFIG_VIRTIO_SERIAL) += virtio-console.o
> >   common-obj-$(CONFIG_XILINX) += xilinx_uartlite.o
> >   common-obj-$(CONFIG_XEN) += xen_console.o
> >   common-obj-$(CONFIG_CADENCE) += cadence_uart.o
> > +common-obj-$(CONFIG_IBEX) += ibex_uart.o
> >
> >   common-obj-$(CONFIG_EXYNOS4) += exynos4210_uart.o
> >   common-obj-$(CONFIG_COLDFIRE) += mcf_uart.o
> > diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
> > index 94d19571f7..28947ef3e0 100644
> > --- a/hw/riscv/Kconfig
> > +++ b/hw/riscv/Kconfig
> > @@ -4,6 +4,9 @@ config HTIF
> >   config HART
> >       bool
> >
> > +config IBEX
> > +    bool
> > +
> >   config SIFIVE
> >       bool
> >       select MSI_NONBROKEN
> > @@ -29,6 +32,7 @@ config SPIKE
> >
> >   config OPENTITAN
> >       bool
> > +    select IBEX
> >       select HART
> >       select UNIMP
> >
>
>


^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v5 07/11] hw/char: Initial commit of Ibex UART
@ 2020-06-02 17:46       ` Alistair Francis
  0 siblings, 0 replies; 68+ messages in thread
From: Alistair Francis @ 2020-06-02 17:46 UTC (permalink / raw)
  To: LIU Zhiwei
  Cc: Alistair Francis, open list:RISC-V, Bin Meng, Palmer Dabbelt,
	qemu-devel@nongnu.org Developers

On Tue, Jun 2, 2020 at 4:22 AM LIU Zhiwei <zhiwei_liu@c-sky.com> wrote:
>
>
>
> On 2020/5/29 6:14, Alistair Francis wrote:
> > This is the initial commit of the Ibex UART device. Serial TX is
> > working, while RX has been implemeneted but untested.
> >
> > This is based on the documentation from:
> > https://docs.opentitan.org/hw/ip/uart/doc/
> >
> > Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> > ---
> >   include/hw/char/ibex_uart.h | 110 ++++++++
> >   hw/char/ibex_uart.c         | 492 ++++++++++++++++++++++++++++++++++++
> >   MAINTAINERS                 |   2 +
> >   hw/char/Makefile.objs       |   1 +
> >   hw/riscv/Kconfig            |   4 +
> >   5 files changed, 609 insertions(+)
> >   create mode 100644 include/hw/char/ibex_uart.h
> >   create mode 100644 hw/char/ibex_uart.c
> >
> > diff --git a/include/hw/char/ibex_uart.h b/include/hw/char/ibex_uart.h
> > new file mode 100644
> > index 0000000000..2bec772615
> > --- /dev/null
> > +++ b/include/hw/char/ibex_uart.h
> > @@ -0,0 +1,110 @@
> > +/*
> > + * QEMU lowRISC Ibex UART device
> > + *
> > + * Copyright (c) 2020 Western Digital
> > + *
> > + * 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.
> > + */
> > +
> > +#ifndef HW_IBEX_UART_H
> > +#define HW_IBEX_UART_H
> > +
> > +#include "hw/sysbus.h"
> > +#include "chardev/char-fe.h"
> > +#include "qemu/timer.h"
> > +
> > +#define IBEX_UART_INTR_STATE   0x00
> > +    #define INTR_STATE_TX_WATERMARK (1 << 0)
> > +    #define INTR_STATE_RX_WATERMARK (1 << 1)
> > +    #define INTR_STATE_TX_EMPTY     (1 << 2)
> > +    #define INTR_STATE_RX_OVERFLOW  (1 << 3)
> > +#define IBEX_UART_INTR_ENABLE  0x04
> > +#define IBEX_UART_INTR_TEST    0x08
> > +
> > +#define IBEX_UART_CTRL         0x0c
> > +    #define UART_CTRL_TX_ENABLE     (1 << 0)
> > +    #define UART_CTRL_RX_ENABLE     (1 << 1)
> > +    #define UART_CTRL_NF            (1 << 2)
> > +    #define UART_CTRL_SLPBK         (1 << 4)
> > +    #define UART_CTRL_LLPBK         (1 << 5)
> > +    #define UART_CTRL_PARITY_EN     (1 << 6)
> > +    #define UART_CTRL_PARITY_ODD    (1 << 7)
> > +    #define UART_CTRL_RXBLVL        (3 << 8)
> > +    #define UART_CTRL_NCO           (0xFFFF << 16)
> > +
> > +#define IBEX_UART_STATUS       0x10
> > +    #define UART_STATUS_TXFULL  (1 << 0)
> > +    #define UART_STATUS_RXFULL  (1 << 1)
> > +    #define UART_STATUS_TXEMPTY (1 << 2)
> > +    #define UART_STATUS_RXIDLE  (1 << 4)
> > +    #define UART_STATUS_RXEMPTY (1 << 5)
> > +
> > +#define IBEX_UART_RDATA        0x14
> > +#define IBEX_UART_WDATA        0x18
> > +
> > +#define IBEX_UART_FIFO_CTRL    0x1c
> > +    #define FIFO_CTRL_RXRST          (1 << 0)
> > +    #define FIFO_CTRL_TXRST          (1 << 1)
> > +    #define FIFO_CTRL_RXILVL         (7 << 2)
> > +    #define FIFO_CTRL_RXILVL_SHIFT   (2)
> > +    #define FIFO_CTRL_TXILVL         (3 << 5)
> > +    #define FIFO_CTRL_TXILVL_SHIFT   (5)
> > +
> > +#define IBEX_UART_FIFO_STATUS  0x20
> > +#define IBEX_UART_OVRD         0x24
> > +#define IBEX_UART_VAL          0x28
> > +#define IBEX_UART_TIMEOUT_CTRL 0x2c
> > +
> > +#define IBEX_UART_TX_FIFO_SIZE 16
> > +
> > +#define TYPE_IBEX_UART "ibex-uart"
> > +#define IBEX_UART(obj) \
> > +    OBJECT_CHECK(IbexUartState, (obj), TYPE_IBEX_UART)
> > +
> > +typedef struct {
> > +    /* <private> */
> > +    SysBusDevice parent_obj;
> > +
> > +    /* <public> */
> > +    MemoryRegion mmio;
> > +
> > +    uint8_t tx_fifo[IBEX_UART_TX_FIFO_SIZE];
> > +    uint32_t tx_level;
> > +
> > +    QEMUTimer *fifo_trigger_handle;
> > +    uint64_t char_tx_time;
> > +
> > +    uint32_t uart_intr_state;
> > +    uint32_t uart_intr_enable;
> > +    uint32_t uart_ctrl;
> > +    uint32_t uart_status;
> > +    uint32_t uart_rdata;
> > +    uint32_t uart_fifo_ctrl;
> > +    uint32_t uart_fifo_status;
> > +    uint32_t uart_ovrd;
> > +    uint32_t uart_val;
> > +    uint32_t uart_timeout_ctrl;
> > +
> > +    CharBackend chr;
> > +    qemu_irq tx_watermark;
> > +    qemu_irq rx_watermark;
> > +    qemu_irq tx_empty;
> > +    qemu_irq rx_overflow;
> > +} IbexUartState;
> > +#endif /* HW_IBEX_UART_H */
> > diff --git a/hw/char/ibex_uart.c b/hw/char/ibex_uart.c
> > new file mode 100644
> > index 0000000000..c416325d73
> > --- /dev/null
> > +++ b/hw/char/ibex_uart.c
> > @@ -0,0 +1,492 @@
> > +/*
> > + * QEMU lowRISC Ibex UART device
> > + *
> > + * Copyright (c) 2020 Western Digital
> > + *
> > + * For details check the documentation here:
> > + *    https://docs.opentitan.org/hw/ip/uart/doc/
> > + *
> > + * 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.
> > + */
> > +
> > +#include "qemu/osdep.h"
> > +#include "hw/char/ibex_uart.h"
> > +#include "hw/irq.h"
> > +#include "hw/qdev-properties.h"
> > +#include "migration/vmstate.h"
> > +#include "qemu/log.h"
> > +#include "qemu/module.h"
> > +
> > +static void ibex_uart_update_irqs(IbexUartState *s)
> > +{
> > +    if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_TX_WATERMARK) {
> > +        qemu_set_irq(s->tx_watermark, 1);
> > +    } else {
> > +        qemu_set_irq(s->tx_watermark, 0);
> > +    }
> > +
> > +    if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_RX_WATERMARK) {
> > +        qemu_set_irq(s->rx_watermark, 1);
> > +    } else {
> > +        qemu_set_irq(s->rx_watermark, 0);
> > +    }
> > +
> > +    if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_TX_EMPTY) {
> > +        qemu_set_irq(s->tx_empty, 1);
> > +    } else {
> > +        qemu_set_irq(s->tx_empty, 0);
> > +    }
> > +
> > +    if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_RX_OVERFLOW) {
> > +        qemu_set_irq(s->rx_overflow, 1);
> > +    } else {
> > +        qemu_set_irq(s->rx_overflow, 0);
> > +    }
> > +}
> > +
> > +static int ibex_uart_can_receive(void *opaque)
> > +{
> > +    IbexUartState *s = opaque;
> > +
> > +    if (s->uart_ctrl & UART_CTRL_RX_ENABLE) {
> > +        return 1;
> > +    }
> > +
> > +    return 0;
> > +}
> > +
> > +static void ibex_uart_receive(void *opaque, const uint8_t *buf, int size)
> > +{
> > +    IbexUartState *s = opaque;
> > +    uint8_t rx_fifo_level = (s->uart_fifo_ctrl & FIFO_CTRL_RXILVL)
> > +                            >> FIFO_CTRL_RXILVL_SHIFT;
> > +
> > +    s->uart_rdata = *buf;
> > +
> > +    s->uart_status &= ~UART_STATUS_RXIDLE;
> > +    s->uart_status &= ~UART_STATUS_RXEMPTY;
> > +
> > +    if (size > rx_fifo_level) {
> > +        s->uart_intr_state |= INTR_STATE_RX_WATERMARK;
> > +    }
> > +
> > +    ibex_uart_update_irqs(s);
> > +}
> > +
> > +static gboolean ibex_uart_xmit(GIOChannel *chan, GIOCondition cond,
> > +                               void *opaque)
> > +{
> > +    IbexUartState *s = opaque;
> > +    uint8_t tx_fifo_level = (s->uart_fifo_ctrl & FIFO_CTRL_TXILVL)
> > +                            >> FIFO_CTRL_TXILVL_SHIFT;
> > +    int ret;
> > +
> > +    /* instant drain the fifo when there's no back-end */
> > +    if (!qemu_chr_fe_backend_connected(&s->chr)) {
> > +        s->tx_level = 0;
> > +        return FALSE;
> > +    }
> > +
> > +    if (!s->tx_level) {
> > +        s->uart_status &= UART_STATUS_TXFULL;
> Maybe  s->uart_status &= ~UART_STATUS_TXFULL;

Good spot, fixed.

> > +        s->uart_status |= UART_STATUS_TXEMPTY;
> > +        s->uart_intr_state |= INTR_STATE_TX_EMPTY;
> > +        s->uart_intr_state &= ~INTR_STATE_TX_WATERMARK;
> > +        ibex_uart_update_irqs(s);
> > +        return FALSE;
> > +    }
> > +
> > +    ret = qemu_chr_fe_write(&s->chr, s->tx_fifo, s->tx_level);
> > +
> > +    if (ret >= 0) {
> > +        s->tx_level -= ret;
> > +        memmove(s->tx_fifo, s->tx_fifo + ret, s->tx_level);
> > +    }
> > +
> > +    if (s->tx_level) {
> > +        guint r = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP,
> > +                                        ibex_uart_xmit, s);
> > +        if (!r) {
> > +            s->tx_level = 0;
> > +            return FALSE;
> > +        }
> > +    }
> > +
> > +    /* Clear the TX Full bit */
> > +    if (s->tx_level != IBEX_UART_TX_FIFO_SIZE) {
> > +        s->uart_status &= ~UART_STATUS_TXFULL;
> > +    }
> > +
> > +    /* Disable the TX_WATERMARK IRQ */
> > +    if (s->tx_level < tx_fifo_level) {
> > +        s->uart_intr_state &= ~INTR_STATE_TX_WATERMARK;
> > +    }
> > +
> > +    /* Set TX empty */
> > +    if (s->tx_level == 0) {
> > +        s->uart_status |= UART_STATUS_TXEMPTY;
> > +        s->uart_intr_state |= INTR_STATE_TX_EMPTY;
> > +    }
> > +
> > +    ibex_uart_update_irqs(s);
> > +    return FALSE;
> > +}
> > +
> > +static void uart_write_tx_fifo(IbexUartState *s, const uint8_t *buf,
> > +                               int size)
> > +{
> > +    uint64_t current_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
> > +    uint8_t tx_fifo_level = (s->uart_fifo_ctrl & FIFO_CTRL_TXILVL)
> > +                            >> FIFO_CTRL_TXILVL_SHIFT;
> > +
> > +    if (size > IBEX_UART_TX_FIFO_SIZE - s->tx_level) {
> > +        size = IBEX_UART_TX_FIFO_SIZE - s->tx_level;
> > +        qemu_log_mask(LOG_GUEST_ERROR, "ibex_uart: TX FIFO overflow");
> > +    }
> > +
> > +    memcpy(s->tx_fifo + s->tx_level, buf, size);
> > +    s->tx_level += size;
> > +
> > +    if (s->tx_level > 0) {
> > +        s->uart_status &= ~UART_STATUS_TXEMPTY;
> > +    }
> > +
> > +    if (s->tx_level >= tx_fifo_level) {
> > +        s->uart_intr_state |= INTR_STATE_TX_WATERMARK;
> > +        ibex_uart_update_irqs(s);
> > +    }
> > +
> > +    if (s->tx_level == IBEX_UART_TX_FIFO_SIZE) {
> > +        s->uart_status |= UART_STATUS_TXFULL;
> > +    }
> > +
> > +    timer_mod(s->fifo_trigger_handle, current_time +
> > +              (s->char_tx_time * 4));
> > +}
> > +
> > +static void ibex_uart_reset(DeviceState *dev)
> > +{
> > +    IbexUartState *s = IBEX_UART(dev);
> > +
> > +    s->uart_intr_state = 0x00000000;
> > +    s->uart_intr_state = 0x00000000;
> > +    s->uart_intr_enable = 0x00000000;
> > +    s->uart_ctrl = 0x00000000;
> > +    s->uart_status = 0x0000003c;
> > +    s->uart_rdata = 0x00000000;
> > +    s->uart_fifo_ctrl = 0x00000000;
> > +    s->uart_fifo_status = 0x00000000;
> > +    s->uart_ovrd = 0x00000000;
> > +    s->uart_val = 0x00000000;
> > +    s->uart_timeout_ctrl = 0x00000000;
> > +
> > +    s->tx_level = 0;
> > +
> > +    s->char_tx_time = (NANOSECONDS_PER_SECOND / 230400) * 10;
> > +
> > +    ibex_uart_update_irqs(s);
> > +}
> > +
> > +static uint64_t ibex_uart_read(void *opaque, hwaddr addr,
> > +                                       unsigned int size)
> > +{
> > +    IbexUartState *s = opaque;
> > +    uint64_t retvalue = 0;
> > +
> > +    switch (addr) {
> > +    case IBEX_UART_INTR_STATE:
> > +        retvalue = s->uart_intr_state;
> > +        break;
> > +    case IBEX_UART_INTR_ENABLE:
> > +        retvalue = s->uart_intr_enable;
> > +        break;
> > +    case IBEX_UART_INTR_TEST:
> > +        qemu_log_mask(LOG_GUEST_ERROR,
> > +                      "%s: wdata is write only\n", __func__);
> > +        break;
> > +
> > +    case IBEX_UART_CTRL:
> > +        retvalue = s->uart_ctrl;
> > +        break;
> > +    case IBEX_UART_STATUS:
> > +        retvalue = s->uart_status;
> > +        break;
> > +
> > +    case IBEX_UART_RDATA:
> > +        retvalue = s->uart_rdata;
> > +        if (s->uart_ctrl & UART_CTRL_RX_ENABLE) {
> > +            qemu_chr_fe_accept_input(&s->chr);
> > +
> > +            s->uart_status |= UART_STATUS_RXIDLE;
> > +            s->uart_status |= UART_STATUS_RXEMPTY;
> > +        }
> > +        break;
> > +    case IBEX_UART_WDATA:
> > +        qemu_log_mask(LOG_GUEST_ERROR,
> > +                      "%s: wdata is write only\n", __func__);
> > +        break;
> > +
> > +    case IBEX_UART_FIFO_CTRL:
> > +        retvalue = s->uart_fifo_ctrl;
> > +        break;
> > +    case IBEX_UART_FIFO_STATUS:
> > +        retvalue = s->uart_fifo_status;
> > +
> > +        retvalue |= s->tx_level & 0x1F;
> > +
> > +        qemu_log_mask(LOG_UNIMP,
> > +                      "%s: RX fifos are not supported\n", __func__);
> > +        break;
> > +
> > +    case IBEX_UART_OVRD:
> > +        retvalue = s->uart_ovrd;
> > +        qemu_log_mask(LOG_UNIMP,
> > +                      "%s: ovrd is not supported\n", __func__);
> > +        break;
> > +    case IBEX_UART_VAL:
> > +        retvalue = s->uart_val;
> > +        qemu_log_mask(LOG_UNIMP,
> > +                      "%s: val is not supported\n", __func__);
> > +        break;
> > +    case IBEX_UART_TIMEOUT_CTRL:
> > +        retvalue = s->uart_timeout_ctrl;
> > +        qemu_log_mask(LOG_UNIMP,
> > +                      "%s: timeout_ctrl is not supported\n", __func__);
> > +        break;
> > +    default:
> > +        qemu_log_mask(LOG_GUEST_ERROR,
> > +                      "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
> > +        return 0;
> > +    }
> > +
> > +    return retvalue;
> > +}
> > +
> > +static void ibex_uart_write(void *opaque, hwaddr addr,
> > +                                  uint64_t val64, unsigned int size)
> > +{
> > +    IbexUartState *s = opaque;
> > +    uint32_t value = val64;
> > +
> > +    switch (addr) {
> > +    case IBEX_UART_INTR_STATE:
> > +        /* Write 1 clear */
> > +        s->uart_intr_state &= ~value;
> > +        ibex_uart_update_irqs(s);
> > +        break;
> > +    case IBEX_UART_INTR_ENABLE:
> > +        s->uart_intr_enable = value;
> > +        ibex_uart_update_irqs(s);
> > +        break;
> > +    case IBEX_UART_INTR_TEST:
> > +        s->uart_intr_state |= value;
> > +        ibex_uart_update_irqs(s);
> > +        break;
> > +
> > +    case IBEX_UART_CTRL:
> > +        s->uart_ctrl = value;
> > +
> > +        if (value & UART_CTRL_NF) {
> > +            qemu_log_mask(LOG_UNIMP,
> > +                          "%s: UART_CTRL_NF is not supported\n", __func__);
> > +        }
> > +        if (value & UART_CTRL_SLPBK) {
> > +            qemu_log_mask(LOG_UNIMP,
> > +                          "%s: UART_CTRL_SLPBK is not supported\n", __func__);
> > +        }
> > +        if (value & UART_CTRL_LLPBK) {
> > +            qemu_log_mask(LOG_UNIMP,
> > +                          "%s: UART_CTRL_LLPBK is not supported\n", __func__);
> > +        }
> > +        if (value & UART_CTRL_PARITY_EN) {
> > +            qemu_log_mask(LOG_UNIMP,
> > +                          "%s: UART_CTRL_PARITY_EN is not supported\n",
> > +                          __func__);
> > +        }
> > +        if (value & UART_CTRL_PARITY_ODD) {
> > +            qemu_log_mask(LOG_UNIMP,
> > +                          "%s: UART_CTRL_PARITY_ODD is not supported\n",
> > +                          __func__);
> > +        }
> > +        if (value & UART_CTRL_RXBLVL) {
> > +            qemu_log_mask(LOG_UNIMP,
> > +                          "%s: UART_CTRL_RXBLVL is not supported\n", __func__);
> > +        }
> > +        if (value & UART_CTRL_NCO) {
> > +            uint64_t baud = ((value & UART_CTRL_NCO) >> 16);
> > +            baud *= 1000;
> > +            baud /= 2 ^ 20;
> > +
> > +            s->char_tx_time = (NANOSECONDS_PER_SECOND / baud) * 10;
> > +        }
> > +        break;
> > +    case IBEX_UART_STATUS:
> > +        qemu_log_mask(LOG_GUEST_ERROR,
> > +                      "%s: status is read only\n", __func__);
> > +        break;
> > +
> > +    case IBEX_UART_RDATA:
> > +        qemu_log_mask(LOG_GUEST_ERROR,
> > +                      "%s: rdata is read only\n", __func__);
> > +        break;
> > +    case IBEX_UART_WDATA:
> > +        uart_write_tx_fifo(s, (uint8_t *) &value, 1);
> > +        break;
> > +
> > +    case IBEX_UART_FIFO_CTRL:
> > +        s->uart_fifo_ctrl = value;
> > +
> > +        if (value & FIFO_CTRL_RXRST) {
> > +            qemu_log_mask(LOG_UNIMP,
> > +                          "%s: RX fifos are not supported\n", __func__);
> > +        }
> > +        if (value & FIFO_CTRL_TXRST) {
> > +            s->tx_level = 0;
> > +        }
> > +        break;
> > +    case IBEX_UART_FIFO_STATUS:
> > +        qemu_log_mask(LOG_GUEST_ERROR,
> > +                      "%s: fifo_status is read only\n", __func__);
> > +        break;
> > +
> > +    case IBEX_UART_OVRD:
> > +        s->uart_ovrd = value;
> > +        qemu_log_mask(LOG_UNIMP,
> > +                      "%s: ovrd is not supported\n", __func__);
> > +        break;
> > +    case IBEX_UART_VAL:
> > +        qemu_log_mask(LOG_GUEST_ERROR,
> > +                      "%s: val is read only\n", __func__);
> > +        break;
> > +    case IBEX_UART_TIMEOUT_CTRL:
> > +        s->uart_timeout_ctrl = value;
> > +        qemu_log_mask(LOG_UNIMP,
> > +                      "%s: timeout_ctrl is not supported\n", __func__);
> > +        break;
> > +    default:
> > +        qemu_log_mask(LOG_GUEST_ERROR,
> > +                      "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
> > +    }
> > +}
> > +
> > +static void fifo_trigger_update(void *opaque)
> > +{
> > +    IbexUartState *s = opaque;
> > +
> > +    if (s->uart_ctrl & UART_CTRL_TX_ENABLE) {
> > +        ibex_uart_xmit(NULL, G_IO_OUT, s);
> > +    }
> > +}
> > +
> > +static const MemoryRegionOps ibex_uart_ops = {
> > +    .read = ibex_uart_read,
> > +    .write = ibex_uart_write,
> > +    .endianness = DEVICE_NATIVE_ENDIAN,
> > +    .impl.min_access_size = 4,
> > +    .impl.max_access_size = 4,
> > +};
> > +
> > +static int cadence_uart_post_load(void *opaque, int version_id)
> Not a good name.

Also fixed.

Alistair

> > +{
> > +    IbexUartState *s = opaque;
> > +
> > +    ibex_uart_update_irqs(s);
> > +    return 0;
> > +}
> > +
> > +static const VMStateDescription vmstate_ibex_uart = {
> > +    .name = TYPE_IBEX_UART,
> > +    .version_id = 1,
> > +    .minimum_version_id = 1,
> > +    .post_load = cadence_uart_post_load,
> > +    .fields = (VMStateField[]) {
> > +        VMSTATE_UINT8_ARRAY(tx_fifo, IbexUartState,
> > +                            IBEX_UART_TX_FIFO_SIZE),
> > +        VMSTATE_UINT32(tx_level, IbexUartState),
> > +        VMSTATE_UINT64(char_tx_time, IbexUartState),
> > +        VMSTATE_TIMER_PTR(fifo_trigger_handle, IbexUartState),
> > +        VMSTATE_UINT32(uart_intr_state, IbexUartState),
> > +        VMSTATE_UINT32(uart_intr_enable, IbexUartState),
> > +        VMSTATE_UINT32(uart_ctrl, IbexUartState),
> > +        VMSTATE_UINT32(uart_status, IbexUartState),
> > +        VMSTATE_UINT32(uart_rdata, IbexUartState),
> > +        VMSTATE_UINT32(uart_fifo_ctrl, IbexUartState),
> > +        VMSTATE_UINT32(uart_fifo_status, IbexUartState),
> > +        VMSTATE_UINT32(uart_ovrd, IbexUartState),
> > +        VMSTATE_UINT32(uart_val, IbexUartState),
> > +        VMSTATE_UINT32(uart_timeout_ctrl, IbexUartState),
> > +        VMSTATE_END_OF_LIST()
> > +    }
> > +};
> > +
> > +static Property ibex_uart_properties[] = {
> > +    DEFINE_PROP_CHR("chardev", IbexUartState, chr),
> > +    DEFINE_PROP_END_OF_LIST(),
> > +};
> > +
> > +static void ibex_uart_init(Object *obj)
> > +{
> > +    IbexUartState *s = IBEX_UART(obj);
> > +
> > +    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->tx_watermark);
> > +    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->rx_watermark);
> > +    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->tx_empty);
> > +    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->rx_overflow);
> > +
> > +    memory_region_init_io(&s->mmio, obj, &ibex_uart_ops, s,
> > +                          TYPE_IBEX_UART, 0x400);
> > +    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
> > +}
> > +
> > +static void ibex_uart_realize(DeviceState *dev, Error **errp)
> > +{
> > +    IbexUartState *s = IBEX_UART(dev);
> > +
> > +    s->fifo_trigger_handle = timer_new_ns(QEMU_CLOCK_VIRTUAL,
> > +                                          fifo_trigger_update, s);
> > +
> > +    qemu_chr_fe_set_handlers(&s->chr, ibex_uart_can_receive,
> > +                             ibex_uart_receive, NULL, NULL,
> > +                             s, NULL, true);
> > +}
> > +
> > +static void ibex_uart_class_init(ObjectClass *klass, void *data)
> > +{
> > +    DeviceClass *dc = DEVICE_CLASS(klass);
> > +
> > +    dc->reset = ibex_uart_reset;
> > +    dc->realize = ibex_uart_realize;
> > +    dc->vmsd = &vmstate_ibex_uart;
> > +    device_class_set_props(dc, ibex_uart_properties);
> > +}
> > +
> > +static const TypeInfo ibex_uart_info = {
> > +    .name          = TYPE_IBEX_UART,
> > +    .parent        = TYPE_SYS_BUS_DEVICE,
> > +    .instance_size = sizeof(IbexUartState),
> > +    .instance_init = ibex_uart_init,
> > +    .class_init    = ibex_uart_class_init,
> > +};
> > +
> > +static void ibex_uart_register_types(void)
> > +{
> > +    type_register_static(&ibex_uart_info);
> > +}
> > +
> > +type_init(ibex_uart_register_types)
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index 3e7d9cb0a5..a1ce186a7e 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -1245,7 +1245,9 @@ M: Alistair Francis <Alistair.Francis@wdc.com>
> >   L: qemu-riscv@nongnu.org
> >   S: Supported
> >   F: hw/riscv/opentitan.c
> > +F: hw/char/ibex_uart.c
> >   F: include/hw/riscv/opentitan.h
> > +F: include/hw/char/ibex_uart.h
> >
> >   SH4 Machines
> >   ------------
> > diff --git a/hw/char/Makefile.objs b/hw/char/Makefile.objs
> > index 9e9a6c1aff..633996be5b 100644
> > --- a/hw/char/Makefile.objs
> > +++ b/hw/char/Makefile.objs
> > @@ -12,6 +12,7 @@ common-obj-$(CONFIG_VIRTIO_SERIAL) += virtio-console.o
> >   common-obj-$(CONFIG_XILINX) += xilinx_uartlite.o
> >   common-obj-$(CONFIG_XEN) += xen_console.o
> >   common-obj-$(CONFIG_CADENCE) += cadence_uart.o
> > +common-obj-$(CONFIG_IBEX) += ibex_uart.o
> >
> >   common-obj-$(CONFIG_EXYNOS4) += exynos4210_uart.o
> >   common-obj-$(CONFIG_COLDFIRE) += mcf_uart.o
> > diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
> > index 94d19571f7..28947ef3e0 100644
> > --- a/hw/riscv/Kconfig
> > +++ b/hw/riscv/Kconfig
> > @@ -4,6 +4,9 @@ config HTIF
> >   config HART
> >       bool
> >
> > +config IBEX
> > +    bool
> > +
> >   config SIFIVE
> >       bool
> >       select MSI_NONBROKEN
> > @@ -29,6 +32,7 @@ config SPIKE
> >
> >   config OPENTITAN
> >       bool
> > +    select IBEX
> >       select HART
> >       select UNIMP
> >
>
>


^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v5 07/11] hw/char: Initial commit of Ibex UART
  2020-06-02 12:28       ` LIU Zhiwei
@ 2020-06-02 17:54         ` Alistair Francis
  -1 siblings, 0 replies; 68+ messages in thread
From: Alistair Francis @ 2020-06-02 17:54 UTC (permalink / raw)
  To: LIU Zhiwei
  Cc: open list:RISC-V, Bin Meng, Alistair Francis, Palmer Dabbelt,
	qemu-devel@nongnu.org Developers

On Tue, Jun 2, 2020 at 5:28 AM LIU Zhiwei <zhiwei_liu@c-sky.com> wrote:
>
> Hi Alistair,
>
> There are still some questions I don't understand.
>
> 1. Is the baud rate  or fifo a necessary feature to simulate?
> As you can see, qemu_chr_fe_write will send the byte as soon as possible.
> When you want to transmit a byte through WDATA,  you can call
> qemu_chr_fe_write directly.

So qemu_chr_fe_write() will send the data straight away. This doesn't
match what teh hardware does though. So by modelling a FIFO and a
delay in sending we can better match the hardware.

>
> 2.  The baud rate calculation method is not strictly right.
> I think when a byte write to FIFO,  char_tx_time * 8 is the correct time
> to send the byte instead of
> char_tx_time * 4.

Do you mind explaining why 8 is correct instead of 4?

>
> 3.  Why add a watch here?

This is based on the Cadence UART implementation in QEMU (which does
the same thing). This will trigger a callback when we can write more
data or when the backend has hung up.

Alistair

> > +        s->uart_status |= UART_STATUS_TXEMPTY;
> > +        s->uart_intr_state |= INTR_STATE_TX_EMPTY;
> > +        s->uart_intr_state &= ~INTR_STATE_TX_WATERMARK;
> > +        ibex_uart_update_irqs(s);
> > +        return FALSE;
> > +    }
> > +
> > +    ret = qemu_chr_fe_write(&s->chr, s->tx_fifo, s->tx_level);
> > +
> > +    if (ret >= 0) {
> > +        s->tx_level -= ret;
> > +        memmove(s->tx_fifo, s->tx_fifo + ret, s->tx_level);
> > +    }
> > +
> > +    if (s->tx_level) {
> > +        guint r = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP,
> > +                                        ibex_uart_xmit, s);
> > +        if (!r) {
> > +            s->tx_level = 0;
> > +            return FALSE;
> > +        }
> > +    }
> > +
>
> Zhiwei
>
>


^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v5 07/11] hw/char: Initial commit of Ibex UART
@ 2020-06-02 17:54         ` Alistair Francis
  0 siblings, 0 replies; 68+ messages in thread
From: Alistair Francis @ 2020-06-02 17:54 UTC (permalink / raw)
  To: LIU Zhiwei
  Cc: Alistair Francis, open list:RISC-V, Bin Meng, Palmer Dabbelt,
	qemu-devel@nongnu.org Developers

On Tue, Jun 2, 2020 at 5:28 AM LIU Zhiwei <zhiwei_liu@c-sky.com> wrote:
>
> Hi Alistair,
>
> There are still some questions I don't understand.
>
> 1. Is the baud rate  or fifo a necessary feature to simulate?
> As you can see, qemu_chr_fe_write will send the byte as soon as possible.
> When you want to transmit a byte through WDATA,  you can call
> qemu_chr_fe_write directly.

So qemu_chr_fe_write() will send the data straight away. This doesn't
match what teh hardware does though. So by modelling a FIFO and a
delay in sending we can better match the hardware.

>
> 2.  The baud rate calculation method is not strictly right.
> I think when a byte write to FIFO,  char_tx_time * 8 is the correct time
> to send the byte instead of
> char_tx_time * 4.

Do you mind explaining why 8 is correct instead of 4?

>
> 3.  Why add a watch here?

This is based on the Cadence UART implementation in QEMU (which does
the same thing). This will trigger a callback when we can write more
data or when the backend has hung up.

Alistair

> > +        s->uart_status |= UART_STATUS_TXEMPTY;
> > +        s->uart_intr_state |= INTR_STATE_TX_EMPTY;
> > +        s->uart_intr_state &= ~INTR_STATE_TX_WATERMARK;
> > +        ibex_uart_update_irqs(s);
> > +        return FALSE;
> > +    }
> > +
> > +    ret = qemu_chr_fe_write(&s->chr, s->tx_fifo, s->tx_level);
> > +
> > +    if (ret >= 0) {
> > +        s->tx_level -= ret;
> > +        memmove(s->tx_fifo, s->tx_fifo + ret, s->tx_level);
> > +    }
> > +
> > +    if (s->tx_level) {
> > +        guint r = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP,
> > +                                        ibex_uart_xmit, s);
> > +        if (!r) {
> > +            s->tx_level = 0;
> > +            return FALSE;
> > +        }
> > +    }
> > +
>
> Zhiwei
>
>


^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v5 07/11] hw/char: Initial commit of Ibex UART
  2020-06-02 17:54         ` Alistair Francis
@ 2020-06-03 10:33           ` LIU Zhiwei
  -1 siblings, 0 replies; 68+ messages in thread
From: LIU Zhiwei @ 2020-06-03 10:33 UTC (permalink / raw)
  To: Alistair Francis
  Cc: open list:RISC-V, Bin Meng, Alistair Francis, Palmer Dabbelt,
	qemu-devel@nongnu.org Developers

On 2020/6/3 1:54, Alistair Francis wrote:
> On Tue, Jun 2, 2020 at 5:28 AM LIU Zhiwei<zhiwei_liu@c-sky.com>  wrote:
>> Hi Alistair,
>>
>> There are still some questions I don't understand.
>>
>> 1. Is the baud rate  or fifo a necessary feature to simulate?
>> As you can see, qemu_chr_fe_write will send the byte as soon as possible.
>> When you want to transmit a byte through WDATA,  you can call
>> qemu_chr_fe_write directly.
> So qemu_chr_fe_write() will send the data straight away. This doesn't
> match what teh hardware does though. So by modelling a FIFO and a
> delay in sending we can better match the hardware.
I see many UARTs have similar features. Does the software really care about
these features? Usually I just want to print something to the terminal 
through UART.
Most simulation in QEMU is for running software, not exactly the details 
of hardware.
For example, we will not simulate the 16x oversamples in this UART.

There is no error here. Personally I  think it is necessary to simulate 
the FIFO and baud rate,
maybe for supporting some backends.

Can someone give a reasonable answer for this question?
>> 2.  The baud rate calculation method is not strictly right.
>> I think when a byte write to FIFO,  char_tx_time * 8 is the correct time
>> to send the byte instead of
>> char_tx_time * 4.
> Do you mind explaining why 8 is correct instead of 4?
Usually write a byte to WDATA will trigger a uart_write_tx_fifo. 
Translate a bit will take
char_tx_time. So it will take char_tx_time * 8 to transmit a byte.
>> 3.  Why add a watch here?
> This is based on the Cadence UART implementation in QEMU (which does
> the same thing). This will trigger a callback when we can write more
> data or when the backend has hung up.
Many other serials do the same thing, like virtio-console and serial. So 
it may be a common
interface here. I will try to understand it(Not yet).

Zhiwei
> Alistair
>
>>> +        s->uart_status |= UART_STATUS_TXEMPTY;
>>> +        s->uart_intr_state |= INTR_STATE_TX_EMPTY;
>>> +        s->uart_intr_state &= ~INTR_STATE_TX_WATERMARK;
>>> +        ibex_uart_update_irqs(s);
>>> +        return FALSE;
>>> +    }
>>> +
>>> +    ret = qemu_chr_fe_write(&s->chr, s->tx_fifo, s->tx_level);
>>> +
>>> +    if (ret >= 0) {
>>> +        s->tx_level -= ret;
>>> +        memmove(s->tx_fifo, s->tx_fifo + ret, s->tx_level);
>>> +    }
>>> +
>>> +    if (s->tx_level) {
>>> +        guint r = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP,
>>> +                                        ibex_uart_xmit, s);
>>> +        if (!r) {
>>> +            s->tx_level = 0;
>>> +            return FALSE;
>>> +        }
>>> +    }
>>> +
>> Zhiwei
>>
>>



^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v5 07/11] hw/char: Initial commit of Ibex UART
@ 2020-06-03 10:33           ` LIU Zhiwei
  0 siblings, 0 replies; 68+ messages in thread
From: LIU Zhiwei @ 2020-06-03 10:33 UTC (permalink / raw)
  To: Alistair Francis
  Cc: Alistair Francis, open list:RISC-V, Bin Meng, Palmer Dabbelt,
	qemu-devel@nongnu.org Developers

On 2020/6/3 1:54, Alistair Francis wrote:
> On Tue, Jun 2, 2020 at 5:28 AM LIU Zhiwei<zhiwei_liu@c-sky.com>  wrote:
>> Hi Alistair,
>>
>> There are still some questions I don't understand.
>>
>> 1. Is the baud rate  or fifo a necessary feature to simulate?
>> As you can see, qemu_chr_fe_write will send the byte as soon as possible.
>> When you want to transmit a byte through WDATA,  you can call
>> qemu_chr_fe_write directly.
> So qemu_chr_fe_write() will send the data straight away. This doesn't
> match what teh hardware does though. So by modelling a FIFO and a
> delay in sending we can better match the hardware.
I see many UARTs have similar features. Does the software really care about
these features? Usually I just want to print something to the terminal 
through UART.
Most simulation in QEMU is for running software, not exactly the details 
of hardware.
For example, we will not simulate the 16x oversamples in this UART.

There is no error here. Personally I  think it is necessary to simulate 
the FIFO and baud rate,
maybe for supporting some backends.

Can someone give a reasonable answer for this question?
>> 2.  The baud rate calculation method is not strictly right.
>> I think when a byte write to FIFO,  char_tx_time * 8 is the correct time
>> to send the byte instead of
>> char_tx_time * 4.
> Do you mind explaining why 8 is correct instead of 4?
Usually write a byte to WDATA will trigger a uart_write_tx_fifo. 
Translate a bit will take
char_tx_time. So it will take char_tx_time * 8 to transmit a byte.
>> 3.  Why add a watch here?
> This is based on the Cadence UART implementation in QEMU (which does
> the same thing). This will trigger a callback when we can write more
> data or when the backend has hung up.
Many other serials do the same thing, like virtio-console and serial. So 
it may be a common
interface here. I will try to understand it(Not yet).

Zhiwei
> Alistair
>
>>> +        s->uart_status |= UART_STATUS_TXEMPTY;
>>> +        s->uart_intr_state |= INTR_STATE_TX_EMPTY;
>>> +        s->uart_intr_state &= ~INTR_STATE_TX_WATERMARK;
>>> +        ibex_uart_update_irqs(s);
>>> +        return FALSE;
>>> +    }
>>> +
>>> +    ret = qemu_chr_fe_write(&s->chr, s->tx_fifo, s->tx_level);
>>> +
>>> +    if (ret >= 0) {
>>> +        s->tx_level -= ret;
>>> +        memmove(s->tx_fifo, s->tx_fifo + ret, s->tx_level);
>>> +    }
>>> +
>>> +    if (s->tx_level) {
>>> +        guint r = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP,
>>> +                                        ibex_uart_xmit, s);
>>> +        if (!r) {
>>> +            s->tx_level = 0;
>>> +            return FALSE;
>>> +        }
>>> +    }
>>> +
>> Zhiwei
>>
>>



^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v5 07/11] hw/char: Initial commit of Ibex UART
  2020-06-03 10:33           ` LIU Zhiwei
@ 2020-06-03 15:56             ` Alistair Francis
  -1 siblings, 0 replies; 68+ messages in thread
From: Alistair Francis @ 2020-06-03 15:56 UTC (permalink / raw)
  To: LIU Zhiwei
  Cc: open list:RISC-V, Bin Meng, Alistair Francis, Palmer Dabbelt,
	qemu-devel@nongnu.org Developers

On Wed, Jun 3, 2020 at 3:33 AM LIU Zhiwei <zhiwei_liu@c-sky.com> wrote:
>
> On 2020/6/3 1:54, Alistair Francis wrote:
> > On Tue, Jun 2, 2020 at 5:28 AM LIU Zhiwei<zhiwei_liu@c-sky.com>  wrote:
> >> Hi Alistair,
> >>
> >> There are still some questions I don't understand.
> >>
> >> 1. Is the baud rate  or fifo a necessary feature to simulate?
> >> As you can see, qemu_chr_fe_write will send the byte as soon as possible.
> >> When you want to transmit a byte through WDATA,  you can call
> >> qemu_chr_fe_write directly.
> > So qemu_chr_fe_write() will send the data straight away. This doesn't
> > match what teh hardware does though. So by modelling a FIFO and a
> > delay in sending we can better match the hardware.
> I see many UARTs have similar features. Does the software really care about
> these features? Usually I just want to print something to the terminal
> through UART.

In this case Tock (which is the OS used for OpenTitan) does car about
these features as it relies on interrupts generated by the HW to
complete the serial send task. It also just makes the QEMU model more
accurate.

> Most simulation in QEMU is for running software, not exactly the details
> of hardware.
> For example, we will not simulate the 16x oversamples in this UART.

Agreed. Lots of UARTs don't bother modelling the delay from the
hardware as generally it doesn't matter. In this case it does make a
difference for the software and it makes the QEMU model more accurate,
which is always a good thing.

>
> There is no error here. Personally I  think it is necessary to simulate
> the FIFO and baud rate,
> maybe for supporting some backends.

So baud rate doesn't need to be modelled as we aren't actually sending
UART data, just pretending and then printing it.

>
> Can someone give a reasonable answer for this question?

Which question?

> >> 2.  The baud rate calculation method is not strictly right.
> >> I think when a byte write to FIFO,  char_tx_time * 8 is the correct time
> >> to send the byte instead of
> >> char_tx_time * 4.
> > Do you mind explaining why 8 is correct instead of 4?
> Usually write a byte to WDATA will trigger a uart_write_tx_fifo.
> Translate a bit will take
> char_tx_time. So it will take char_tx_time * 8 to transmit a byte.

I see your point. I just used the 4 as that is what the Cadence one
does. I don't think it matters too much as it's just the delay for a
timer (that isn't used as an accurate timer).

> >> 3.  Why add a watch here?
> > This is based on the Cadence UART implementation in QEMU (which does
> > the same thing). This will trigger a callback when we can write more
> > data or when the backend has hung up.
> Many other serials do the same thing, like virtio-console and serial. So
> it may be a common
> interface here. I will try to understand it(Not yet).

Yep, it's just a more complete model of that the HW does.

Alistair


^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v5 07/11] hw/char: Initial commit of Ibex UART
@ 2020-06-03 15:56             ` Alistair Francis
  0 siblings, 0 replies; 68+ messages in thread
From: Alistair Francis @ 2020-06-03 15:56 UTC (permalink / raw)
  To: LIU Zhiwei
  Cc: Alistair Francis, open list:RISC-V, Bin Meng, Palmer Dabbelt,
	qemu-devel@nongnu.org Developers

On Wed, Jun 3, 2020 at 3:33 AM LIU Zhiwei <zhiwei_liu@c-sky.com> wrote:
>
> On 2020/6/3 1:54, Alistair Francis wrote:
> > On Tue, Jun 2, 2020 at 5:28 AM LIU Zhiwei<zhiwei_liu@c-sky.com>  wrote:
> >> Hi Alistair,
> >>
> >> There are still some questions I don't understand.
> >>
> >> 1. Is the baud rate  or fifo a necessary feature to simulate?
> >> As you can see, qemu_chr_fe_write will send the byte as soon as possible.
> >> When you want to transmit a byte through WDATA,  you can call
> >> qemu_chr_fe_write directly.
> > So qemu_chr_fe_write() will send the data straight away. This doesn't
> > match what teh hardware does though. So by modelling a FIFO and a
> > delay in sending we can better match the hardware.
> I see many UARTs have similar features. Does the software really care about
> these features? Usually I just want to print something to the terminal
> through UART.

In this case Tock (which is the OS used for OpenTitan) does car about
these features as it relies on interrupts generated by the HW to
complete the serial send task. It also just makes the QEMU model more
accurate.

> Most simulation in QEMU is for running software, not exactly the details
> of hardware.
> For example, we will not simulate the 16x oversamples in this UART.

Agreed. Lots of UARTs don't bother modelling the delay from the
hardware as generally it doesn't matter. In this case it does make a
difference for the software and it makes the QEMU model more accurate,
which is always a good thing.

>
> There is no error here. Personally I  think it is necessary to simulate
> the FIFO and baud rate,
> maybe for supporting some backends.

So baud rate doesn't need to be modelled as we aren't actually sending
UART data, just pretending and then printing it.

>
> Can someone give a reasonable answer for this question?

Which question?

> >> 2.  The baud rate calculation method is not strictly right.
> >> I think when a byte write to FIFO,  char_tx_time * 8 is the correct time
> >> to send the byte instead of
> >> char_tx_time * 4.
> > Do you mind explaining why 8 is correct instead of 4?
> Usually write a byte to WDATA will trigger a uart_write_tx_fifo.
> Translate a bit will take
> char_tx_time. So it will take char_tx_time * 8 to transmit a byte.

I see your point. I just used the 4 as that is what the Cadence one
does. I don't think it matters too much as it's just the delay for a
timer (that isn't used as an accurate timer).

> >> 3.  Why add a watch here?
> > This is based on the Cadence UART implementation in QEMU (which does
> > the same thing). This will trigger a callback when we can write more
> > data or when the backend has hung up.
> Many other serials do the same thing, like virtio-console and serial. So
> it may be a common
> interface here. I will try to understand it(Not yet).

Yep, it's just a more complete model of that the HW does.

Alistair


^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v5 07/11] hw/char: Initial commit of Ibex UART
  2020-06-03 15:56             ` Alistair Francis
@ 2020-06-04  1:59               ` LIU Zhiwei
  -1 siblings, 0 replies; 68+ messages in thread
From: LIU Zhiwei @ 2020-06-04  1:59 UTC (permalink / raw)
  To: Alistair Francis
  Cc: open list:RISC-V, Bin Meng, Alistair Francis, Palmer Dabbelt,
	qemu-devel@nongnu.org Developers



On 2020/6/3 23:56, Alistair Francis wrote:
> On Wed, Jun 3, 2020 at 3:33 AM LIU Zhiwei <zhiwei_liu@c-sky.com> wrote:
>> On 2020/6/3 1:54, Alistair Francis wrote:
>>> On Tue, Jun 2, 2020 at 5:28 AM LIU Zhiwei<zhiwei_liu@c-sky.com>  wrote:
>>>> Hi Alistair,
>>>>
>>>> There are still some questions I don't understand.
>>>>
>>>> 1. Is the baud rate  or fifo a necessary feature to simulate?
>>>> As you can see, qemu_chr_fe_write will send the byte as soon as possible.
>>>> When you want to transmit a byte through WDATA,  you can call
>>>> qemu_chr_fe_write directly.
>>> So qemu_chr_fe_write() will send the data straight away. This doesn't
>>> match what teh hardware does though. So by modelling a FIFO and a
>>> delay in sending we can better match the hardware.
>> I see many UARTs have similar features. Does the software really care about
>> these features? Usually I just want to print something to the terminal
>> through UART.
> In this case Tock (which is the OS used for OpenTitan) does car about
> these features as it relies on interrupts generated by the HW to
> complete the serial send task. It also just makes the QEMU model more
> accurate.

Fair enough. I see the "tx_watermark" interrupt, which needs the FIFO. 
At least,
it can verify the ISP.
>> Most simulation in QEMU is for running software, not exactly the details
>> of hardware.
>> For example, we will not simulate the 16x oversamples in this UART.
> Agreed. Lots of UARTs don't bother modelling the delay from the
> hardware as generally it doesn't matter. In this case it does make a
> difference for the software and it makes the QEMU model more accurate,
> which is always a good thing.
>
>> There is no error here. Personally I  think it is necessary to simulate
>> the FIFO and baud rate,
>> maybe for supporting some backends.
> So baud rate doesn't need to be modelled as we aren't actually sending
> UART data, just pretending and then printing it.
>
>> Can someone give a reasonable answer for this question?
> Which question?
I see  the UART can work with many  different backends,  such as pty , 
file, socket and so on.
I wonder if this a backend, which has some requirements on the baud 
rate.  You can ignore it,
as it doesn't matter.
>
>>>> 2.  The baud rate calculation method is not strictly right.
>>>> I think when a byte write to FIFO,  char_tx_time * 8 is the correct time
>>>> to send the byte instead of
>>>> char_tx_time * 4.
>>> Do you mind explaining why 8 is correct instead of 4?
>> Usually write a byte to WDATA will trigger a uart_write_tx_fifo.
>> Translate a bit will take
>> char_tx_time. So it will take char_tx_time * 8 to transmit a byte.
> I see your point. I just used the 4 as that is what the Cadence one
> does. I don't think it matters too much as it's just the delay for a
> timer (that isn't used as an accurate timer).
Got it. Just a way to send the bytes at sometime later.
>>>> 3.  Why add a watch here?
>>> This is based on the Cadence UART implementation in QEMU (which does
>>> the same thing). This will trigger a callback when we can write more
>>> data or when the backend has hung up.
>> Many other serials do the same thing, like virtio-console and serial. So
>> it may be a common
>> interface here. I will try to understand it(Not yet).
> Yep, it's just a more complete model of that the HW does.
I try to boot a RISC-V Linux, and set a breakpoint  to a watch callback 
function.
The breakpoint did't match.

I just wonder if there is a case really need the callback function.

Zhiwei
>
> Alistair



^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v5 07/11] hw/char: Initial commit of Ibex UART
@ 2020-06-04  1:59               ` LIU Zhiwei
  0 siblings, 0 replies; 68+ messages in thread
From: LIU Zhiwei @ 2020-06-04  1:59 UTC (permalink / raw)
  To: Alistair Francis
  Cc: Alistair Francis, open list:RISC-V, Bin Meng, Palmer Dabbelt,
	qemu-devel@nongnu.org Developers



On 2020/6/3 23:56, Alistair Francis wrote:
> On Wed, Jun 3, 2020 at 3:33 AM LIU Zhiwei <zhiwei_liu@c-sky.com> wrote:
>> On 2020/6/3 1:54, Alistair Francis wrote:
>>> On Tue, Jun 2, 2020 at 5:28 AM LIU Zhiwei<zhiwei_liu@c-sky.com>  wrote:
>>>> Hi Alistair,
>>>>
>>>> There are still some questions I don't understand.
>>>>
>>>> 1. Is the baud rate  or fifo a necessary feature to simulate?
>>>> As you can see, qemu_chr_fe_write will send the byte as soon as possible.
>>>> When you want to transmit a byte through WDATA,  you can call
>>>> qemu_chr_fe_write directly.
>>> So qemu_chr_fe_write() will send the data straight away. This doesn't
>>> match what teh hardware does though. So by modelling a FIFO and a
>>> delay in sending we can better match the hardware.
>> I see many UARTs have similar features. Does the software really care about
>> these features? Usually I just want to print something to the terminal
>> through UART.
> In this case Tock (which is the OS used for OpenTitan) does car about
> these features as it relies on interrupts generated by the HW to
> complete the serial send task. It also just makes the QEMU model more
> accurate.

Fair enough. I see the "tx_watermark" interrupt, which needs the FIFO. 
At least,
it can verify the ISP.
>> Most simulation in QEMU is for running software, not exactly the details
>> of hardware.
>> For example, we will not simulate the 16x oversamples in this UART.
> Agreed. Lots of UARTs don't bother modelling the delay from the
> hardware as generally it doesn't matter. In this case it does make a
> difference for the software and it makes the QEMU model more accurate,
> which is always a good thing.
>
>> There is no error here. Personally I  think it is necessary to simulate
>> the FIFO and baud rate,
>> maybe for supporting some backends.
> So baud rate doesn't need to be modelled as we aren't actually sending
> UART data, just pretending and then printing it.
>
>> Can someone give a reasonable answer for this question?
> Which question?
I see  the UART can work with many  different backends,  such as pty , 
file, socket and so on.
I wonder if this a backend, which has some requirements on the baud 
rate.  You can ignore it,
as it doesn't matter.
>
>>>> 2.  The baud rate calculation method is not strictly right.
>>>> I think when a byte write to FIFO,  char_tx_time * 8 is the correct time
>>>> to send the byte instead of
>>>> char_tx_time * 4.
>>> Do you mind explaining why 8 is correct instead of 4?
>> Usually write a byte to WDATA will trigger a uart_write_tx_fifo.
>> Translate a bit will take
>> char_tx_time. So it will take char_tx_time * 8 to transmit a byte.
> I see your point. I just used the 4 as that is what the Cadence one
> does. I don't think it matters too much as it's just the delay for a
> timer (that isn't used as an accurate timer).
Got it. Just a way to send the bytes at sometime later.
>>>> 3.  Why add a watch here?
>>> This is based on the Cadence UART implementation in QEMU (which does
>>> the same thing). This will trigger a callback when we can write more
>>> data or when the backend has hung up.
>> Many other serials do the same thing, like virtio-console and serial. So
>> it may be a common
>> interface here. I will try to understand it(Not yet).
> Yep, it's just a more complete model of that the HW does.
I try to boot a RISC-V Linux, and set a breakpoint  to a watch callback 
function.
The breakpoint did't match.

I just wonder if there is a case really need the callback function.

Zhiwei
>
> Alistair



^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v5 07/11] hw/char: Initial commit of Ibex UART
  2020-06-04  1:59               ` LIU Zhiwei
@ 2020-06-04  4:35                 ` Alistair Francis
  -1 siblings, 0 replies; 68+ messages in thread
From: Alistair Francis @ 2020-06-04  4:35 UTC (permalink / raw)
  To: LIU Zhiwei
  Cc: open list:RISC-V, Bin Meng, Alistair Francis, Palmer Dabbelt,
	qemu-devel@nongnu.org Developers

On Wed, Jun 3, 2020 at 6:59 PM LIU Zhiwei <zhiwei_liu@c-sky.com> wrote:
>
>
>
> On 2020/6/3 23:56, Alistair Francis wrote:
> > On Wed, Jun 3, 2020 at 3:33 AM LIU Zhiwei <zhiwei_liu@c-sky.com> wrote:
> >> On 2020/6/3 1:54, Alistair Francis wrote:
> >>> On Tue, Jun 2, 2020 at 5:28 AM LIU Zhiwei<zhiwei_liu@c-sky.com>  wrote:
> >>>> Hi Alistair,
> >>>>
> >>>> There are still some questions I don't understand.
> >>>>
> >>>> 1. Is the baud rate  or fifo a necessary feature to simulate?
> >>>> As you can see, qemu_chr_fe_write will send the byte as soon as possible.
> >>>> When you want to transmit a byte through WDATA,  you can call
> >>>> qemu_chr_fe_write directly.
> >>> So qemu_chr_fe_write() will send the data straight away. This doesn't
> >>> match what teh hardware does though. So by modelling a FIFO and a
> >>> delay in sending we can better match the hardware.
> >> I see many UARTs have similar features. Does the software really care about
> >> these features? Usually I just want to print something to the terminal
> >> through UART.
> > In this case Tock (which is the OS used for OpenTitan) does car about
> > these features as it relies on interrupts generated by the HW to
> > complete the serial send task. It also just makes the QEMU model more
> > accurate.
>
> Fair enough. I see the "tx_watermark" interrupt, which needs the FIFO.
> At least,
> it can verify the ISP.

Exactly :)

> >> Most simulation in QEMU is for running software, not exactly the details
> >> of hardware.
> >> For example, we will not simulate the 16x oversamples in this UART.
> > Agreed. Lots of UARTs don't bother modelling the delay from the
> > hardware as generally it doesn't matter. In this case it does make a
> > difference for the software and it makes the QEMU model more accurate,
> > which is always a good thing.
> >
> >> There is no error here. Personally I  think it is necessary to simulate
> >> the FIFO and baud rate,
> >> maybe for supporting some backends.
> > So baud rate doesn't need to be modelled as we aren't actually sending
> > UART data, just pretending and then printing it.
> >
> >> Can someone give a reasonable answer for this question?
> > Which question?
> I see  the UART can work with many  different backends,  such as pty ,
> file, socket and so on.
> I wonder if this a backend, which has some requirements on the baud

The backend should be independent so it doesn't matter what baud rate
we choose here.

> rate.  You can ignore it,
> as it doesn't matter.
> >
> >>>> 2.  The baud rate calculation method is not strictly right.
> >>>> I think when a byte write to FIFO,  char_tx_time * 8 is the correct time
> >>>> to send the byte instead of
> >>>> char_tx_time * 4.
> >>> Do you mind explaining why 8 is correct instead of 4?
> >> Usually write a byte to WDATA will trigger a uart_write_tx_fifo.
> >> Translate a bit will take
> >> char_tx_time. So it will take char_tx_time * 8 to transmit a byte.
> > I see your point. I just used the 4 as that is what the Cadence one
> > does. I don't think it matters too much as it's just the delay for a
> > timer (that isn't used as an accurate timer).
> Got it. Just a way to send the bytes at sometime later.
> >>>> 3.  Why add a watch here?
> >>> This is based on the Cadence UART implementation in QEMU (which does
> >>> the same thing). This will trigger a callback when we can write more
> >>> data or when the backend has hung up.
> >> Many other serials do the same thing, like virtio-console and serial. So
> >> it may be a common
> >> interface here. I will try to understand it(Not yet).
> > Yep, it's just a more complete model of that the HW does.
> I try to boot a RISC-V Linux, and set a breakpoint  to a watch callback
> function.
> The breakpoint did't match.
>
> I just wonder if there is a case really need the callback function.

AFAIK Linux doesn't support the Ibex UART (or Ibex at all) so it
shouldn't be triggered.

Alistair

>
> Zhiwei
> >
> > Alistair
>


^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v5 07/11] hw/char: Initial commit of Ibex UART
@ 2020-06-04  4:35                 ` Alistair Francis
  0 siblings, 0 replies; 68+ messages in thread
From: Alistair Francis @ 2020-06-04  4:35 UTC (permalink / raw)
  To: LIU Zhiwei
  Cc: Alistair Francis, open list:RISC-V, Bin Meng, Palmer Dabbelt,
	qemu-devel@nongnu.org Developers

On Wed, Jun 3, 2020 at 6:59 PM LIU Zhiwei <zhiwei_liu@c-sky.com> wrote:
>
>
>
> On 2020/6/3 23:56, Alistair Francis wrote:
> > On Wed, Jun 3, 2020 at 3:33 AM LIU Zhiwei <zhiwei_liu@c-sky.com> wrote:
> >> On 2020/6/3 1:54, Alistair Francis wrote:
> >>> On Tue, Jun 2, 2020 at 5:28 AM LIU Zhiwei<zhiwei_liu@c-sky.com>  wrote:
> >>>> Hi Alistair,
> >>>>
> >>>> There are still some questions I don't understand.
> >>>>
> >>>> 1. Is the baud rate  or fifo a necessary feature to simulate?
> >>>> As you can see, qemu_chr_fe_write will send the byte as soon as possible.
> >>>> When you want to transmit a byte through WDATA,  you can call
> >>>> qemu_chr_fe_write directly.
> >>> So qemu_chr_fe_write() will send the data straight away. This doesn't
> >>> match what teh hardware does though. So by modelling a FIFO and a
> >>> delay in sending we can better match the hardware.
> >> I see many UARTs have similar features. Does the software really care about
> >> these features? Usually I just want to print something to the terminal
> >> through UART.
> > In this case Tock (which is the OS used for OpenTitan) does car about
> > these features as it relies on interrupts generated by the HW to
> > complete the serial send task. It also just makes the QEMU model more
> > accurate.
>
> Fair enough. I see the "tx_watermark" interrupt, which needs the FIFO.
> At least,
> it can verify the ISP.

Exactly :)

> >> Most simulation in QEMU is for running software, not exactly the details
> >> of hardware.
> >> For example, we will not simulate the 16x oversamples in this UART.
> > Agreed. Lots of UARTs don't bother modelling the delay from the
> > hardware as generally it doesn't matter. In this case it does make a
> > difference for the software and it makes the QEMU model more accurate,
> > which is always a good thing.
> >
> >> There is no error here. Personally I  think it is necessary to simulate
> >> the FIFO and baud rate,
> >> maybe for supporting some backends.
> > So baud rate doesn't need to be modelled as we aren't actually sending
> > UART data, just pretending and then printing it.
> >
> >> Can someone give a reasonable answer for this question?
> > Which question?
> I see  the UART can work with many  different backends,  such as pty ,
> file, socket and so on.
> I wonder if this a backend, which has some requirements on the baud

The backend should be independent so it doesn't matter what baud rate
we choose here.

> rate.  You can ignore it,
> as it doesn't matter.
> >
> >>>> 2.  The baud rate calculation method is not strictly right.
> >>>> I think when a byte write to FIFO,  char_tx_time * 8 is the correct time
> >>>> to send the byte instead of
> >>>> char_tx_time * 4.
> >>> Do you mind explaining why 8 is correct instead of 4?
> >> Usually write a byte to WDATA will trigger a uart_write_tx_fifo.
> >> Translate a bit will take
> >> char_tx_time. So it will take char_tx_time * 8 to transmit a byte.
> > I see your point. I just used the 4 as that is what the Cadence one
> > does. I don't think it matters too much as it's just the delay for a
> > timer (that isn't used as an accurate timer).
> Got it. Just a way to send the bytes at sometime later.
> >>>> 3.  Why add a watch here?
> >>> This is based on the Cadence UART implementation in QEMU (which does
> >>> the same thing). This will trigger a callback when we can write more
> >>> data or when the backend has hung up.
> >> Many other serials do the same thing, like virtio-console and serial. So
> >> it may be a common
> >> interface here. I will try to understand it(Not yet).
> > Yep, it's just a more complete model of that the HW does.
> I try to boot a RISC-V Linux, and set a breakpoint  to a watch callback
> function.
> The breakpoint did't match.
>
> I just wonder if there is a case really need the callback function.

AFAIK Linux doesn't support the Ibex UART (or Ibex at all) so it
shouldn't be triggered.

Alistair

>
> Zhiwei
> >
> > Alistair
>


^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v5 07/11] hw/char: Initial commit of Ibex UART
  2020-06-04  4:35                 ` Alistair Francis
@ 2020-06-04  5:05                   ` LIU Zhiwei
  -1 siblings, 0 replies; 68+ messages in thread
From: LIU Zhiwei @ 2020-06-04  5:05 UTC (permalink / raw)
  To: Alistair Francis, LIU Zhiwei
  Cc: Alistair Francis, Bin Meng, open list:RISC-V, Palmer Dabbelt,
	qemu-devel@nongnu.org Developers



On 2020/6/4 12:35, Alistair Francis wrote:
> On Wed, Jun 3, 2020 at 6:59 PM LIU Zhiwei <zhiwei_liu@c-sky.com> wrote:
>>
>>
>> On 2020/6/3 23:56, Alistair Francis wrote:
>>> On Wed, Jun 3, 2020 at 3:33 AM LIU Zhiwei <zhiwei_liu@c-sky.com> wrote:
>>>> On 2020/6/3 1:54, Alistair Francis wrote:
>>>>> On Tue, Jun 2, 2020 at 5:28 AM LIU Zhiwei<zhiwei_liu@c-sky.com>  wrote:
>>>>>> Hi Alistair,
>>>>>>
>>>>>> There are still some questions I don't understand.
>>>>>>
>>>>>> 1. Is the baud rate  or fifo a necessary feature to simulate?
>>>>>> As you can see, qemu_chr_fe_write will send the byte as soon as possible.
>>>>>> When you want to transmit a byte through WDATA,  you can call
>>>>>> qemu_chr_fe_write directly.
>>>>> So qemu_chr_fe_write() will send the data straight away. This doesn't
>>>>> match what teh hardware does though. So by modelling a FIFO and a
>>>>> delay in sending we can better match the hardware.
>>>> I see many UARTs have similar features. Does the software really care about
>>>> these features? Usually I just want to print something to the terminal
>>>> through UART.
>>> In this case Tock (which is the OS used for OpenTitan) does car about
>>> these features as it relies on interrupts generated by the HW to
>>> complete the serial send task. It also just makes the QEMU model more
>>> accurate.
>> Fair enough. I see the "tx_watermark" interrupt, which needs the FIFO.
>> At least,
>> it can verify the ISP.
> Exactly :)
>
>>>> Most simulation in QEMU is for running software, not exactly the details
>>>> of hardware.
>>>> For example, we will not simulate the 16x oversamples in this UART.
>>> Agreed. Lots of UARTs don't bother modelling the delay from the
>>> hardware as generally it doesn't matter. In this case it does make a
>>> difference for the software and it makes the QEMU model more accurate,
>>> which is always a good thing.
>>>
>>>> There is no error here. Personally I  think it is necessary to simulate
>>>> the FIFO and baud rate,
>>>> maybe for supporting some backends.
>>> So baud rate doesn't need to be modelled as we aren't actually sending
>>> UART data, just pretending and then printing it.
>>>
>>>> Can someone give a reasonable answer for this question?
>>> Which question?
>> I see  the UART can work with many  different backends,  such as pty ,
>> file, socket and so on.
>> I wonder if this a backend, which has some requirements on the baud
> The backend should be independent so it doesn't matter what baud rate
> we choose here.
>
>> rate.  You can ignore it,
>> as it doesn't matter.
>>>>>> 2.  The baud rate calculation method is not strictly right.
>>>>>> I think when a byte write to FIFO,  char_tx_time * 8 is the correct time
>>>>>> to send the byte instead of
>>>>>> char_tx_time * 4.
>>>>> Do you mind explaining why 8 is correct instead of 4?
>>>> Usually write a byte to WDATA will trigger a uart_write_tx_fifo.
>>>> Translate a bit will take
>>>> char_tx_time. So it will take char_tx_time * 8 to transmit a byte.
>>> I see your point. I just used the 4 as that is what the Cadence one
>>> does. I don't think it matters too much as it's just the delay for a
>>> timer (that isn't used as an accurate timer).
>> Got it. Just a way to send the bytes at sometime later.
>>>>>> 3.  Why add a watch here?
>>>>> This is based on the Cadence UART implementation in QEMU (which does
>>>>> the same thing). This will trigger a callback when we can write more
>>>>> data or when the backend has hung up.
>>>> Many other serials do the same thing, like virtio-console and serial. So
>>>> it may be a common
>>>> interface here. I will try to understand it(Not yet).
>>> Yep, it's just a more complete model of that the HW does.
>> I try to boot a RISC-V Linux, and set a breakpoint  to a watch callback
>> function.
>> The breakpoint did't match.
>>
>> I just wonder if there is a case really need the callback function.
> AFAIK Linux doesn't support the Ibex UART (or Ibex at all) so it
> shouldn't be triggered.
I tried with the UART in the virt board.  It also registers the watch 
callback on
G_IO_HUP and G_IO_OUT.

However I will through the question alone in another mail.

After the two points addressed,

Reviewed-by: LIU Zhiwei<zhiwei_liu@c-sky.com>

Zhiwei
>
> Alistair
>
>> Zhiwei
>>> Alistair




^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v5 07/11] hw/char: Initial commit of Ibex UART
@ 2020-06-04  5:05                   ` LIU Zhiwei
  0 siblings, 0 replies; 68+ messages in thread
From: LIU Zhiwei @ 2020-06-04  5:05 UTC (permalink / raw)
  To: Alistair Francis, LIU Zhiwei
  Cc: open list:RISC-V, Bin Meng, Alistair Francis, Palmer Dabbelt,
	qemu-devel@nongnu.org Developers



On 2020/6/4 12:35, Alistair Francis wrote:
> On Wed, Jun 3, 2020 at 6:59 PM LIU Zhiwei <zhiwei_liu@c-sky.com> wrote:
>>
>>
>> On 2020/6/3 23:56, Alistair Francis wrote:
>>> On Wed, Jun 3, 2020 at 3:33 AM LIU Zhiwei <zhiwei_liu@c-sky.com> wrote:
>>>> On 2020/6/3 1:54, Alistair Francis wrote:
>>>>> On Tue, Jun 2, 2020 at 5:28 AM LIU Zhiwei<zhiwei_liu@c-sky.com>  wrote:
>>>>>> Hi Alistair,
>>>>>>
>>>>>> There are still some questions I don't understand.
>>>>>>
>>>>>> 1. Is the baud rate  or fifo a necessary feature to simulate?
>>>>>> As you can see, qemu_chr_fe_write will send the byte as soon as possible.
>>>>>> When you want to transmit a byte through WDATA,  you can call
>>>>>> qemu_chr_fe_write directly.
>>>>> So qemu_chr_fe_write() will send the data straight away. This doesn't
>>>>> match what teh hardware does though. So by modelling a FIFO and a
>>>>> delay in sending we can better match the hardware.
>>>> I see many UARTs have similar features. Does the software really care about
>>>> these features? Usually I just want to print something to the terminal
>>>> through UART.
>>> In this case Tock (which is the OS used for OpenTitan) does car about
>>> these features as it relies on interrupts generated by the HW to
>>> complete the serial send task. It also just makes the QEMU model more
>>> accurate.
>> Fair enough. I see the "tx_watermark" interrupt, which needs the FIFO.
>> At least,
>> it can verify the ISP.
> Exactly :)
>
>>>> Most simulation in QEMU is for running software, not exactly the details
>>>> of hardware.
>>>> For example, we will not simulate the 16x oversamples in this UART.
>>> Agreed. Lots of UARTs don't bother modelling the delay from the
>>> hardware as generally it doesn't matter. In this case it does make a
>>> difference for the software and it makes the QEMU model more accurate,
>>> which is always a good thing.
>>>
>>>> There is no error here. Personally I  think it is necessary to simulate
>>>> the FIFO and baud rate,
>>>> maybe for supporting some backends.
>>> So baud rate doesn't need to be modelled as we aren't actually sending
>>> UART data, just pretending and then printing it.
>>>
>>>> Can someone give a reasonable answer for this question?
>>> Which question?
>> I see  the UART can work with many  different backends,  such as pty ,
>> file, socket and so on.
>> I wonder if this a backend, which has some requirements on the baud
> The backend should be independent so it doesn't matter what baud rate
> we choose here.
>
>> rate.  You can ignore it,
>> as it doesn't matter.
>>>>>> 2.  The baud rate calculation method is not strictly right.
>>>>>> I think when a byte write to FIFO,  char_tx_time * 8 is the correct time
>>>>>> to send the byte instead of
>>>>>> char_tx_time * 4.
>>>>> Do you mind explaining why 8 is correct instead of 4?
>>>> Usually write a byte to WDATA will trigger a uart_write_tx_fifo.
>>>> Translate a bit will take
>>>> char_tx_time. So it will take char_tx_time * 8 to transmit a byte.
>>> I see your point. I just used the 4 as that is what the Cadence one
>>> does. I don't think it matters too much as it's just the delay for a
>>> timer (that isn't used as an accurate timer).
>> Got it. Just a way to send the bytes at sometime later.
>>>>>> 3.  Why add a watch here?
>>>>> This is based on the Cadence UART implementation in QEMU (which does
>>>>> the same thing). This will trigger a callback when we can write more
>>>>> data or when the backend has hung up.
>>>> Many other serials do the same thing, like virtio-console and serial. So
>>>> it may be a common
>>>> interface here. I will try to understand it(Not yet).
>>> Yep, it's just a more complete model of that the HW does.
>> I try to boot a RISC-V Linux, and set a breakpoint  to a watch callback
>> function.
>> The breakpoint did't match.
>>
>> I just wonder if there is a case really need the callback function.
> AFAIK Linux doesn't support the Ibex UART (or Ibex at all) so it
> shouldn't be triggered.
I tried with the UART in the virt board.  It also registers the watch 
callback on
G_IO_HUP and G_IO_OUT.

However I will through the question alone in another mail.

After the two points addressed,

Reviewed-by: LIU Zhiwei<zhiwei_liu@c-sky.com>

Zhiwei
>
> Alistair
>
>> Zhiwei
>>> Alistair




^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v5 07/11] hw/char: Initial commit of Ibex UART
  2020-06-04  4:35                 ` Alistair Francis
@ 2020-06-04  5:40                   ` LIU Zhiwei
  -1 siblings, 0 replies; 68+ messages in thread
From: LIU Zhiwei @ 2020-06-04  5:40 UTC (permalink / raw)
  To: Alistair Francis
  Cc: open list:RISC-V, Bin Meng, Alistair Francis, Palmer Dabbelt,
	qemu-devel@nongnu.org Developers



On 2020/6/4 12:35, Alistair Francis wrote:
> On Wed, Jun 3, 2020 at 6:59 PM LIU Zhiwei <zhiwei_liu@c-sky.com> wrote:
>>
>>
>> On 2020/6/3 23:56, Alistair Francis wrote:
>>> On Wed, Jun 3, 2020 at 3:33 AM LIU Zhiwei <zhiwei_liu@c-sky.com> wrote:
>>>> On 2020/6/3 1:54, Alistair Francis wrote:
>>>>> On Tue, Jun 2, 2020 at 5:28 AM LIU Zhiwei<zhiwei_liu@c-sky.com>  wrote:
>>>>>> Hi Alistair,
>>>>>>
>>>>>> There are still some questions I don't understand.
>>>>>>
>>>>>> 1. Is the baud rate  or fifo a necessary feature to simulate?
>>>>>> As you can see, qemu_chr_fe_write will send the byte as soon as possible.
>>>>>> When you want to transmit a byte through WDATA,  you can call
>>>>>> qemu_chr_fe_write directly.
>>>>> So qemu_chr_fe_write() will send the data straight away. This doesn't
>>>>> match what teh hardware does though. So by modelling a FIFO and a
>>>>> delay in sending we can better match the hardware.
>>>> I see many UARTs have similar features. Does the software really care about
>>>> these features? Usually I just want to print something to the terminal
>>>> through UART.
>>> In this case Tock (which is the OS used for OpenTitan) does car about
>>> these features as it relies on interrupts generated by the HW to
>>> complete the serial send task. It also just makes the QEMU model more
>>> accurate.
>> Fair enough. I see the "tx_watermark" interrupt, which needs the FIFO.
>> At least,
>> it can verify the ISP.
> Exactly :)
>
>>>> Most simulation in QEMU is for running software, not exactly the details
>>>> of hardware.
>>>> For example, we will not simulate the 16x oversamples in this UART.
>>> Agreed. Lots of UARTs don't bother modelling the delay from the
>>> hardware as generally it doesn't matter. In this case it does make a
>>> difference for the software and it makes the QEMU model more accurate,
>>> which is always a good thing.
>>>
>>>> There is no error here. Personally I  think it is necessary to simulate
>>>> the FIFO and baud rate,
>>>> maybe for supporting some backends.
>>> So baud rate doesn't need to be modelled as we aren't actually sending
>>> UART data, just pretending and then printing it.
>>>
>>>> Can someone give a reasonable answer for this question?
>>> Which question?
>> I see  the UART can work with many  different backends,  such as pty ,
>> file, socket and so on.
>> I wonder if this a backend, which has some requirements on the baud
> The backend should be independent so it doesn't matter what baud rate
> we choose here.
>
>> rate.  You can ignore it,
>> as it doesn't matter.
>>>>>> 2.  The baud rate calculation method is not strictly right.
>>>>>> I think when a byte write to FIFO,  char_tx_time * 8 is the correct time
>>>>>> to send the byte instead of
>>>>>> char_tx_time * 4.
>>>>> Do you mind explaining why 8 is correct instead of 4?
>>>> Usually write a byte to WDATA will trigger a uart_write_tx_fifo.
>>>> Translate a bit will take
>>>> char_tx_time. So it will take char_tx_time * 8 to transmit a byte.
>>> I see your point. I just used the 4 as that is what the Cadence one
>>> does. I don't think it matters too much as it's just the delay for a
>>> timer (that isn't used as an accurate timer).
>> Got it. Just a way to send the bytes at sometime later.
>>>>>> 3.  Why add a watch here?
>>>>> This is based on the Cadence UART implementation in QEMU (which does
>>>>> the same thing). This will trigger a callback when we can write more
>>>>> data or when the backend has hung up.
>>>> Many other serials do the same thing, like virtio-console and serial. So
>>>> it may be a common
>>>> interface here. I will try to understand it(Not yet).
>>> Yep, it's just a more complete model of that the HW does.
>> I try to boot a RISC-V Linux, and set a breakpoint  to a watch callback
>> function.
>> The breakpoint did't match.
>>
>> I just wonder if there is a case really need the callback function.
> AFAIK Linux doesn't support the Ibex UART (or Ibex at all) so it
> shouldn't be triggered.
I tried with the UART in the virt board.  It also registers the watch 
callback on
G_IO_HUP and G_IO_OUT.

However I will throw the question alone in another thread.

After the two comments pointed at another email addressed,

Reviewed-by: LIU Zhiwei<zhiwei_liu@c-sky.com>

Zhiwei
>
> Alistair
>
>> Zhiwei
>>> Alistair



^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v5 07/11] hw/char: Initial commit of Ibex UART
@ 2020-06-04  5:40                   ` LIU Zhiwei
  0 siblings, 0 replies; 68+ messages in thread
From: LIU Zhiwei @ 2020-06-04  5:40 UTC (permalink / raw)
  To: Alistair Francis
  Cc: Alistair Francis, open list:RISC-V, Bin Meng, Palmer Dabbelt,
	qemu-devel@nongnu.org Developers



On 2020/6/4 12:35, Alistair Francis wrote:
> On Wed, Jun 3, 2020 at 6:59 PM LIU Zhiwei <zhiwei_liu@c-sky.com> wrote:
>>
>>
>> On 2020/6/3 23:56, Alistair Francis wrote:
>>> On Wed, Jun 3, 2020 at 3:33 AM LIU Zhiwei <zhiwei_liu@c-sky.com> wrote:
>>>> On 2020/6/3 1:54, Alistair Francis wrote:
>>>>> On Tue, Jun 2, 2020 at 5:28 AM LIU Zhiwei<zhiwei_liu@c-sky.com>  wrote:
>>>>>> Hi Alistair,
>>>>>>
>>>>>> There are still some questions I don't understand.
>>>>>>
>>>>>> 1. Is the baud rate  or fifo a necessary feature to simulate?
>>>>>> As you can see, qemu_chr_fe_write will send the byte as soon as possible.
>>>>>> When you want to transmit a byte through WDATA,  you can call
>>>>>> qemu_chr_fe_write directly.
>>>>> So qemu_chr_fe_write() will send the data straight away. This doesn't
>>>>> match what teh hardware does though. So by modelling a FIFO and a
>>>>> delay in sending we can better match the hardware.
>>>> I see many UARTs have similar features. Does the software really care about
>>>> these features? Usually I just want to print something to the terminal
>>>> through UART.
>>> In this case Tock (which is the OS used for OpenTitan) does car about
>>> these features as it relies on interrupts generated by the HW to
>>> complete the serial send task. It also just makes the QEMU model more
>>> accurate.
>> Fair enough. I see the "tx_watermark" interrupt, which needs the FIFO.
>> At least,
>> it can verify the ISP.
> Exactly :)
>
>>>> Most simulation in QEMU is for running software, not exactly the details
>>>> of hardware.
>>>> For example, we will not simulate the 16x oversamples in this UART.
>>> Agreed. Lots of UARTs don't bother modelling the delay from the
>>> hardware as generally it doesn't matter. In this case it does make a
>>> difference for the software and it makes the QEMU model more accurate,
>>> which is always a good thing.
>>>
>>>> There is no error here. Personally I  think it is necessary to simulate
>>>> the FIFO and baud rate,
>>>> maybe for supporting some backends.
>>> So baud rate doesn't need to be modelled as we aren't actually sending
>>> UART data, just pretending and then printing it.
>>>
>>>> Can someone give a reasonable answer for this question?
>>> Which question?
>> I see  the UART can work with many  different backends,  such as pty ,
>> file, socket and so on.
>> I wonder if this a backend, which has some requirements on the baud
> The backend should be independent so it doesn't matter what baud rate
> we choose here.
>
>> rate.  You can ignore it,
>> as it doesn't matter.
>>>>>> 2.  The baud rate calculation method is not strictly right.
>>>>>> I think when a byte write to FIFO,  char_tx_time * 8 is the correct time
>>>>>> to send the byte instead of
>>>>>> char_tx_time * 4.
>>>>> Do you mind explaining why 8 is correct instead of 4?
>>>> Usually write a byte to WDATA will trigger a uart_write_tx_fifo.
>>>> Translate a bit will take
>>>> char_tx_time. So it will take char_tx_time * 8 to transmit a byte.
>>> I see your point. I just used the 4 as that is what the Cadence one
>>> does. I don't think it matters too much as it's just the delay for a
>>> timer (that isn't used as an accurate timer).
>> Got it. Just a way to send the bytes at sometime later.
>>>>>> 3.  Why add a watch here?
>>>>> This is based on the Cadence UART implementation in QEMU (which does
>>>>> the same thing). This will trigger a callback when we can write more
>>>>> data or when the backend has hung up.
>>>> Many other serials do the same thing, like virtio-console and serial. So
>>>> it may be a common
>>>> interface here. I will try to understand it(Not yet).
>>> Yep, it's just a more complete model of that the HW does.
>> I try to boot a RISC-V Linux, and set a breakpoint  to a watch callback
>> function.
>> The breakpoint did't match.
>>
>> I just wonder if there is a case really need the callback function.
> AFAIK Linux doesn't support the Ibex UART (or Ibex at all) so it
> shouldn't be triggered.
I tried with the UART in the virt board.  It also registers the watch 
callback on
G_IO_HUP and G_IO_OUT.

However I will throw the question alone in another thread.

After the two comments pointed at another email addressed,

Reviewed-by: LIU Zhiwei<zhiwei_liu@c-sky.com>

Zhiwei
>
> Alistair
>
>> Zhiwei
>>> Alistair



^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v5 07/11] hw/char: Initial commit of Ibex UART
  2020-06-04  5:05                   ` LIU Zhiwei
@ 2020-06-04  5:46                     ` Alistair Francis
  -1 siblings, 0 replies; 68+ messages in thread
From: Alistair Francis @ 2020-06-04  5:46 UTC (permalink / raw)
  To: LIU Zhiwei
  Cc: open list:RISC-V, qemu-devel@nongnu.org Developers,
	Palmer Dabbelt, Alistair Francis, Bin Meng, LIU Zhiwei

On Wed, Jun 3, 2020 at 10:06 PM LIU Zhiwei <liuzwnan@163.com> wrote:
>
>
>
> On 2020/6/4 12:35, Alistair Francis wrote:
> > On Wed, Jun 3, 2020 at 6:59 PM LIU Zhiwei <zhiwei_liu@c-sky.com> wrote:
> >>
> >>
> >> On 2020/6/3 23:56, Alistair Francis wrote:
> >>> On Wed, Jun 3, 2020 at 3:33 AM LIU Zhiwei <zhiwei_liu@c-sky.com> wrote:
> >>>> On 2020/6/3 1:54, Alistair Francis wrote:
> >>>>> On Tue, Jun 2, 2020 at 5:28 AM LIU Zhiwei<zhiwei_liu@c-sky.com>  wrote:
> >>>>>> Hi Alistair,
> >>>>>>
> >>>>>> There are still some questions I don't understand.
> >>>>>>
> >>>>>> 1. Is the baud rate  or fifo a necessary feature to simulate?
> >>>>>> As you can see, qemu_chr_fe_write will send the byte as soon as possible.
> >>>>>> When you want to transmit a byte through WDATA,  you can call
> >>>>>> qemu_chr_fe_write directly.
> >>>>> So qemu_chr_fe_write() will send the data straight away. This doesn't
> >>>>> match what teh hardware does though. So by modelling a FIFO and a
> >>>>> delay in sending we can better match the hardware.
> >>>> I see many UARTs have similar features. Does the software really care about
> >>>> these features? Usually I just want to print something to the terminal
> >>>> through UART.
> >>> In this case Tock (which is the OS used for OpenTitan) does car about
> >>> these features as it relies on interrupts generated by the HW to
> >>> complete the serial send task. It also just makes the QEMU model more
> >>> accurate.
> >> Fair enough. I see the "tx_watermark" interrupt, which needs the FIFO.
> >> At least,
> >> it can verify the ISP.
> > Exactly :)
> >
> >>>> Most simulation in QEMU is for running software, not exactly the details
> >>>> of hardware.
> >>>> For example, we will not simulate the 16x oversamples in this UART.
> >>> Agreed. Lots of UARTs don't bother modelling the delay from the
> >>> hardware as generally it doesn't matter. In this case it does make a
> >>> difference for the software and it makes the QEMU model more accurate,
> >>> which is always a good thing.
> >>>
> >>>> There is no error here. Personally I  think it is necessary to simulate
> >>>> the FIFO and baud rate,
> >>>> maybe for supporting some backends.
> >>> So baud rate doesn't need to be modelled as we aren't actually sending
> >>> UART data, just pretending and then printing it.
> >>>
> >>>> Can someone give a reasonable answer for this question?
> >>> Which question?
> >> I see  the UART can work with many  different backends,  such as pty ,
> >> file, socket and so on.
> >> I wonder if this a backend, which has some requirements on the baud
> > The backend should be independent so it doesn't matter what baud rate
> > we choose here.
> >
> >> rate.  You can ignore it,
> >> as it doesn't matter.
> >>>>>> 2.  The baud rate calculation method is not strictly right.
> >>>>>> I think when a byte write to FIFO,  char_tx_time * 8 is the correct time
> >>>>>> to send the byte instead of
> >>>>>> char_tx_time * 4.
> >>>>> Do you mind explaining why 8 is correct instead of 4?
> >>>> Usually write a byte to WDATA will trigger a uart_write_tx_fifo.
> >>>> Translate a bit will take
> >>>> char_tx_time. So it will take char_tx_time * 8 to transmit a byte.
> >>> I see your point. I just used the 4 as that is what the Cadence one
> >>> does. I don't think it matters too much as it's just the delay for a
> >>> timer (that isn't used as an accurate timer).
> >> Got it. Just a way to send the bytes at sometime later.
> >>>>>> 3.  Why add a watch here?
> >>>>> This is based on the Cadence UART implementation in QEMU (which does
> >>>>> the same thing). This will trigger a callback when we can write more
> >>>>> data or when the backend has hung up.
> >>>> Many other serials do the same thing, like virtio-console and serial. So
> >>>> it may be a common
> >>>> interface here. I will try to understand it(Not yet).
> >>> Yep, it's just a more complete model of that the HW does.
> >> I try to boot a RISC-V Linux, and set a breakpoint  to a watch callback
> >> function.
> >> The breakpoint did't match.
> >>
> >> I just wonder if there is a case really need the callback function.
> > AFAIK Linux doesn't support the Ibex UART (or Ibex at all) so it
> > shouldn't be triggered.
> I tried with the UART in the virt board.  It also registers the watch
> callback on
> G_IO_HUP and G_IO_OUT.
>
> However I will through the question alone in another mail.

Ah, sorry I misunderstood what you meant.

I haven't looked at it, it's possible it's not enabled by Linux.

>
> After the two points addressed,
>
> Reviewed-by: LIU Zhiwei<zhiwei_liu@c-sky.com>

Thanks!

Alistair

>
> Zhiwei
> >
> > Alistair
> >
> >> Zhiwei
> >>> Alistair
>
>
>


^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v5 07/11] hw/char: Initial commit of Ibex UART
@ 2020-06-04  5:46                     ` Alistair Francis
  0 siblings, 0 replies; 68+ messages in thread
From: Alistair Francis @ 2020-06-04  5:46 UTC (permalink / raw)
  To: LIU Zhiwei
  Cc: LIU Zhiwei, Alistair Francis, Bin Meng, open list:RISC-V,
	Palmer Dabbelt, qemu-devel@nongnu.org Developers

On Wed, Jun 3, 2020 at 10:06 PM LIU Zhiwei <liuzwnan@163.com> wrote:
>
>
>
> On 2020/6/4 12:35, Alistair Francis wrote:
> > On Wed, Jun 3, 2020 at 6:59 PM LIU Zhiwei <zhiwei_liu@c-sky.com> wrote:
> >>
> >>
> >> On 2020/6/3 23:56, Alistair Francis wrote:
> >>> On Wed, Jun 3, 2020 at 3:33 AM LIU Zhiwei <zhiwei_liu@c-sky.com> wrote:
> >>>> On 2020/6/3 1:54, Alistair Francis wrote:
> >>>>> On Tue, Jun 2, 2020 at 5:28 AM LIU Zhiwei<zhiwei_liu@c-sky.com>  wrote:
> >>>>>> Hi Alistair,
> >>>>>>
> >>>>>> There are still some questions I don't understand.
> >>>>>>
> >>>>>> 1. Is the baud rate  or fifo a necessary feature to simulate?
> >>>>>> As you can see, qemu_chr_fe_write will send the byte as soon as possible.
> >>>>>> When you want to transmit a byte through WDATA,  you can call
> >>>>>> qemu_chr_fe_write directly.
> >>>>> So qemu_chr_fe_write() will send the data straight away. This doesn't
> >>>>> match what teh hardware does though. So by modelling a FIFO and a
> >>>>> delay in sending we can better match the hardware.
> >>>> I see many UARTs have similar features. Does the software really care about
> >>>> these features? Usually I just want to print something to the terminal
> >>>> through UART.
> >>> In this case Tock (which is the OS used for OpenTitan) does car about
> >>> these features as it relies on interrupts generated by the HW to
> >>> complete the serial send task. It also just makes the QEMU model more
> >>> accurate.
> >> Fair enough. I see the "tx_watermark" interrupt, which needs the FIFO.
> >> At least,
> >> it can verify the ISP.
> > Exactly :)
> >
> >>>> Most simulation in QEMU is for running software, not exactly the details
> >>>> of hardware.
> >>>> For example, we will not simulate the 16x oversamples in this UART.
> >>> Agreed. Lots of UARTs don't bother modelling the delay from the
> >>> hardware as generally it doesn't matter. In this case it does make a
> >>> difference for the software and it makes the QEMU model more accurate,
> >>> which is always a good thing.
> >>>
> >>>> There is no error here. Personally I  think it is necessary to simulate
> >>>> the FIFO and baud rate,
> >>>> maybe for supporting some backends.
> >>> So baud rate doesn't need to be modelled as we aren't actually sending
> >>> UART data, just pretending and then printing it.
> >>>
> >>>> Can someone give a reasonable answer for this question?
> >>> Which question?
> >> I see  the UART can work with many  different backends,  such as pty ,
> >> file, socket and so on.
> >> I wonder if this a backend, which has some requirements on the baud
> > The backend should be independent so it doesn't matter what baud rate
> > we choose here.
> >
> >> rate.  You can ignore it,
> >> as it doesn't matter.
> >>>>>> 2.  The baud rate calculation method is not strictly right.
> >>>>>> I think when a byte write to FIFO,  char_tx_time * 8 is the correct time
> >>>>>> to send the byte instead of
> >>>>>> char_tx_time * 4.
> >>>>> Do you mind explaining why 8 is correct instead of 4?
> >>>> Usually write a byte to WDATA will trigger a uart_write_tx_fifo.
> >>>> Translate a bit will take
> >>>> char_tx_time. So it will take char_tx_time * 8 to transmit a byte.
> >>> I see your point. I just used the 4 as that is what the Cadence one
> >>> does. I don't think it matters too much as it's just the delay for a
> >>> timer (that isn't used as an accurate timer).
> >> Got it. Just a way to send the bytes at sometime later.
> >>>>>> 3.  Why add a watch here?
> >>>>> This is based on the Cadence UART implementation in QEMU (which does
> >>>>> the same thing). This will trigger a callback when we can write more
> >>>>> data or when the backend has hung up.
> >>>> Many other serials do the same thing, like virtio-console and serial. So
> >>>> it may be a common
> >>>> interface here. I will try to understand it(Not yet).
> >>> Yep, it's just a more complete model of that the HW does.
> >> I try to boot a RISC-V Linux, and set a breakpoint  to a watch callback
> >> function.
> >> The breakpoint did't match.
> >>
> >> I just wonder if there is a case really need the callback function.
> > AFAIK Linux doesn't support the Ibex UART (or Ibex at all) so it
> > shouldn't be triggered.
> I tried with the UART in the virt board.  It also registers the watch
> callback on
> G_IO_HUP and G_IO_OUT.
>
> However I will through the question alone in another mail.

Ah, sorry I misunderstood what you meant.

I haven't looked at it, it's possible it's not enabled by Linux.

>
> After the two points addressed,
>
> Reviewed-by: LIU Zhiwei<zhiwei_liu@c-sky.com>

Thanks!

Alistair

>
> Zhiwei
> >
> > Alistair
> >
> >> Zhiwei
> >>> Alistair
>
>
>


^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v5 06/11] riscv: Initial commit of OpenTitan machine
  2020-05-28 22:14   ` Alistair Francis
@ 2020-06-09 13:48     ` Damien Hedde
  -1 siblings, 0 replies; 68+ messages in thread
From: Damien Hedde @ 2020-06-09 13:48 UTC (permalink / raw)
  To: Alistair Francis, qemu-devel, qemu-riscv; +Cc: alistair23, bmeng.cn, palmer


Hi Alistair,

On 5/29/20 12:14 AM, Alistair Francis wrote:
> This adds a barebone OpenTitan machine to QEMU.
> 
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> Reviewed-by: Bin Meng <bin.meng@windriver.com>
> ---

> diff --git a/include/hw/riscv/opentitan.h b/include/hw/riscv/opentitan.h
> new file mode 100644
> index 0000000000..a4b6499444
> --- /dev/null
> +++ b/include/hw/riscv/opentitan.h
> @@ -0,0 +1,68 @@

[...]

> +
> +static const struct MemmapEntry {
> +    hwaddr base;
> +    hwaddr size;
> +} ibex_memmap[] = {
> +    [IBEX_ROM] =            {  0x00008000,   0xc000 },

Shouldn't the ROM size be 0x4000 (which make the end of rom at 0xc000) ?

Not sure if that's exactly this platform you are modeling but the
following doc says the ROM size is 16kB (0x4000):
https://github.com/lowRISC/opentitan/blob/master/hw/top_earlgrey/doc/_index.md

--
Damien



^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v5 06/11] riscv: Initial commit of OpenTitan machine
@ 2020-06-09 13:48     ` Damien Hedde
  0 siblings, 0 replies; 68+ messages in thread
From: Damien Hedde @ 2020-06-09 13:48 UTC (permalink / raw)
  To: Alistair Francis, qemu-devel, qemu-riscv; +Cc: bmeng.cn, palmer, alistair23


Hi Alistair,

On 5/29/20 12:14 AM, Alistair Francis wrote:
> This adds a barebone OpenTitan machine to QEMU.
> 
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> Reviewed-by: Bin Meng <bin.meng@windriver.com>
> ---

> diff --git a/include/hw/riscv/opentitan.h b/include/hw/riscv/opentitan.h
> new file mode 100644
> index 0000000000..a4b6499444
> --- /dev/null
> +++ b/include/hw/riscv/opentitan.h
> @@ -0,0 +1,68 @@

[...]

> +
> +static const struct MemmapEntry {
> +    hwaddr base;
> +    hwaddr size;
> +} ibex_memmap[] = {
> +    [IBEX_ROM] =            {  0x00008000,   0xc000 },

Shouldn't the ROM size be 0x4000 (which make the end of rom at 0xc000) ?

Not sure if that's exactly this platform you are modeling but the
following doc says the ROM size is 16kB (0x4000):
https://github.com/lowRISC/opentitan/blob/master/hw/top_earlgrey/doc/_index.md

--
Damien



^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v5 06/11] riscv: Initial commit of OpenTitan machine
  2020-06-09 13:48     ` Damien Hedde
  (?)
@ 2020-06-09 14:21     ` Philippe Mathieu-Daudé
  2020-06-09 23:09         ` Alistair Francis
  -1 siblings, 1 reply; 68+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-06-09 14:21 UTC (permalink / raw)
  To: Damien Hedde, Alistair Francis, qemu-devel, qemu-riscv
  Cc: alistair23, bmeng.cn, palmer

On 6/9/20 3:48 PM, Damien Hedde wrote:
> 
> Hi Alistair,
> 
> On 5/29/20 12:14 AM, Alistair Francis wrote:
>> This adds a barebone OpenTitan machine to QEMU.
>>
>> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
>> Reviewed-by: Bin Meng <bin.meng@windriver.com>
>> ---
> 
>> diff --git a/include/hw/riscv/opentitan.h b/include/hw/riscv/opentitan.h
>> new file mode 100644
>> index 0000000000..a4b6499444
>> --- /dev/null
>> +++ b/include/hw/riscv/opentitan.h
>> @@ -0,0 +1,68 @@
> 
> [...]
> 
>> +
>> +static const struct MemmapEntry {
>> +    hwaddr base;
>> +    hwaddr size;
>> +} ibex_memmap[] = {
>> +    [IBEX_ROM] =            {  0x00008000,   0xc000 },
> 
> Shouldn't the ROM size be 0x4000 (which make the end of rom at 0xc000) ?
> 
> Not sure if that's exactly this platform you are modeling but the
> following doc says the ROM size is 16kB (0x4000):
> https://github.com/lowRISC/opentitan/blob/master/hw/top_earlgrey/doc/_index.md

Good catch. This is why I prefer the IEC notation:

    [IBEX_ROM] =            {  0x00008000,   16 * KiB },

You can then verify the mapping running 'info mtree' in the monitor.

> 
> --
> Damien
> 
> 



^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v5 06/11] riscv: Initial commit of OpenTitan machine
  2020-06-09 14:21     ` Philippe Mathieu-Daudé
@ 2020-06-09 23:09         ` Alistair Francis
  0 siblings, 0 replies; 68+ messages in thread
From: Alistair Francis @ 2020-06-09 23:09 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: Damien Hedde, open list:RISC-V, qemu-devel@nongnu.org Developers,
	Palmer Dabbelt, Alistair Francis, Bin Meng

On Tue, Jun 9, 2020 at 7:21 AM Philippe Mathieu-Daudé <philmd@redhat.com> wrote:
>
> On 6/9/20 3:48 PM, Damien Hedde wrote:
> >
> > Hi Alistair,
> >
> > On 5/29/20 12:14 AM, Alistair Francis wrote:
> >> This adds a barebone OpenTitan machine to QEMU.
> >>
> >> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> >> Reviewed-by: Bin Meng <bin.meng@windriver.com>
> >> ---
> >
> >> diff --git a/include/hw/riscv/opentitan.h b/include/hw/riscv/opentitan.h
> >> new file mode 100644
> >> index 0000000000..a4b6499444
> >> --- /dev/null
> >> +++ b/include/hw/riscv/opentitan.h
> >> @@ -0,0 +1,68 @@
> >
> > [...]
> >
> >> +
> >> +static const struct MemmapEntry {
> >> +    hwaddr base;
> >> +    hwaddr size;
> >> +} ibex_memmap[] = {
> >> +    [IBEX_ROM] =            {  0x00008000,   0xc000 },
> >
> > Shouldn't the ROM size be 0x4000 (which make the end of rom at 0xc000) ?
> >
> > Not sure if that's exactly this platform you are modeling but the
> > following doc says the ROM size is 16kB (0x4000):
> > https://github.com/lowRISC/opentitan/blob/master/hw/top_earlgrey/doc/_index.md

Yep you are right, I have fixed this.

>
> Good catch. This is why I prefer the IEC notation:
>
>     [IBEX_ROM] =            {  0x00008000,   16 * KiB },
>
> You can then verify the mapping running 'info mtree' in the monitor.

Thanks!

Alistair

>
> >
> > --
> > Damien
> >
> >
>


^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v5 06/11] riscv: Initial commit of OpenTitan machine
@ 2020-06-09 23:09         ` Alistair Francis
  0 siblings, 0 replies; 68+ messages in thread
From: Alistair Francis @ 2020-06-09 23:09 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: Damien Hedde, Alistair Francis, qemu-devel@nongnu.org Developers,
	open list:RISC-V, Bin Meng, Palmer Dabbelt

On Tue, Jun 9, 2020 at 7:21 AM Philippe Mathieu-Daudé <philmd@redhat.com> wrote:
>
> On 6/9/20 3:48 PM, Damien Hedde wrote:
> >
> > Hi Alistair,
> >
> > On 5/29/20 12:14 AM, Alistair Francis wrote:
> >> This adds a barebone OpenTitan machine to QEMU.
> >>
> >> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> >> Reviewed-by: Bin Meng <bin.meng@windriver.com>
> >> ---
> >
> >> diff --git a/include/hw/riscv/opentitan.h b/include/hw/riscv/opentitan.h
> >> new file mode 100644
> >> index 0000000000..a4b6499444
> >> --- /dev/null
> >> +++ b/include/hw/riscv/opentitan.h
> >> @@ -0,0 +1,68 @@
> >
> > [...]
> >
> >> +
> >> +static const struct MemmapEntry {
> >> +    hwaddr base;
> >> +    hwaddr size;
> >> +} ibex_memmap[] = {
> >> +    [IBEX_ROM] =            {  0x00008000,   0xc000 },
> >
> > Shouldn't the ROM size be 0x4000 (which make the end of rom at 0xc000) ?
> >
> > Not sure if that's exactly this platform you are modeling but the
> > following doc says the ROM size is 16kB (0x4000):
> > https://github.com/lowRISC/opentitan/blob/master/hw/top_earlgrey/doc/_index.md

Yep you are right, I have fixed this.

>
> Good catch. This is why I prefer the IEC notation:
>
>     [IBEX_ROM] =            {  0x00008000,   16 * KiB },
>
> You can then verify the mapping running 'info mtree' in the monitor.

Thanks!

Alistair

>
> >
> > --
> > Damien
> >
> >
>


^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v5 06/11] riscv: Initial commit of OpenTitan machine
  2020-05-28 22:14   ` Alistair Francis
@ 2020-09-08 14:52     ` Peter Maydell
  -1 siblings, 0 replies; 68+ messages in thread
From: Peter Maydell @ 2020-09-08 14:52 UTC (permalink / raw)
  To: Alistair Francis
  Cc: Palmer Dabbelt, Bin Meng, open list:RISC-V, QEMU Developers,
	Alistair Francis

On Thu, 28 May 2020 at 23:31, Alistair Francis <alistair.francis@wdc.com> wrote:
>
> This adds a barebone OpenTitan machine to QEMU.
>
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> Reviewed-by: Bin Meng <bin.meng@windriver.com>
> ---
>  default-configs/riscv32-softmmu.mak |   1 +
>  default-configs/riscv64-softmmu.mak |  11 +-

Just noticed this, but:

> diff --git a/default-configs/riscv32-softmmu.mak b/default-configs/riscv32-softmmu.mak
> index 1ae077ed87..94a236c9c2 100644
> --- a/default-configs/riscv32-softmmu.mak
> +++ b/default-configs/riscv32-softmmu.mak
> @@ -10,3 +10,4 @@ CONFIG_SPIKE=y
>  CONFIG_SIFIVE_E=y
>  CONFIG_SIFIVE_U=y
>  CONFIG_RISCV_VIRT=y
> +CONFIG_OPENTITAN=y
> diff --git a/default-configs/riscv64-softmmu.mak b/default-configs/riscv64-softmmu.mak
> index 235c6f473f..aaf6d735bb 100644
> --- a/default-configs/riscv64-softmmu.mak
> +++ b/default-configs/riscv64-softmmu.mak
> @@ -1,3 +1,12 @@
>  # Default configuration for riscv64-softmmu
>
> -include riscv32-softmmu.mak
> +# Uncomment the following lines to disable these optional devices:
> +#
> +#CONFIG_PCI_DEVICES=n
> +
> +# Boards:
> +#
> +CONFIG_SPIKE=y
> +CONFIG_SIFIVE_E=y
> +CONFIG_SIFIVE_U=y
> +CONFIG_RISCV_VIRT=y

...shouldn't the riscv64-softmmu config have CONFIG_OPENTITAN too?
The usual principle is that the 64-bit executable can run the
32-bit boards too.

thanks
-- PMM


^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v5 06/11] riscv: Initial commit of OpenTitan machine
@ 2020-09-08 14:52     ` Peter Maydell
  0 siblings, 0 replies; 68+ messages in thread
From: Peter Maydell @ 2020-09-08 14:52 UTC (permalink / raw)
  To: Alistair Francis
  Cc: QEMU Developers, open list:RISC-V, Bin Meng, Palmer Dabbelt,
	Alistair Francis

On Thu, 28 May 2020 at 23:31, Alistair Francis <alistair.francis@wdc.com> wrote:
>
> This adds a barebone OpenTitan machine to QEMU.
>
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> Reviewed-by: Bin Meng <bin.meng@windriver.com>
> ---
>  default-configs/riscv32-softmmu.mak |   1 +
>  default-configs/riscv64-softmmu.mak |  11 +-

Just noticed this, but:

> diff --git a/default-configs/riscv32-softmmu.mak b/default-configs/riscv32-softmmu.mak
> index 1ae077ed87..94a236c9c2 100644
> --- a/default-configs/riscv32-softmmu.mak
> +++ b/default-configs/riscv32-softmmu.mak
> @@ -10,3 +10,4 @@ CONFIG_SPIKE=y
>  CONFIG_SIFIVE_E=y
>  CONFIG_SIFIVE_U=y
>  CONFIG_RISCV_VIRT=y
> +CONFIG_OPENTITAN=y
> diff --git a/default-configs/riscv64-softmmu.mak b/default-configs/riscv64-softmmu.mak
> index 235c6f473f..aaf6d735bb 100644
> --- a/default-configs/riscv64-softmmu.mak
> +++ b/default-configs/riscv64-softmmu.mak
> @@ -1,3 +1,12 @@
>  # Default configuration for riscv64-softmmu
>
> -include riscv32-softmmu.mak
> +# Uncomment the following lines to disable these optional devices:
> +#
> +#CONFIG_PCI_DEVICES=n
> +
> +# Boards:
> +#
> +CONFIG_SPIKE=y
> +CONFIG_SIFIVE_E=y
> +CONFIG_SIFIVE_U=y
> +CONFIG_RISCV_VIRT=y

...shouldn't the riscv64-softmmu config have CONFIG_OPENTITAN too?
The usual principle is that the 64-bit executable can run the
32-bit boards too.

thanks
-- PMM


^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v5 06/11] riscv: Initial commit of OpenTitan machine
  2020-09-08 14:52     ` Peter Maydell
@ 2020-09-09 17:49       ` Alistair Francis
  -1 siblings, 0 replies; 68+ messages in thread
From: Alistair Francis @ 2020-09-09 17:49 UTC (permalink / raw)
  To: Peter Maydell
  Cc: open list:RISC-V, Palmer Dabbelt, Bin Meng, Alistair Francis,
	QEMU Developers

On Tue, Sep 8, 2020 at 7:52 AM Peter Maydell <peter.maydell@linaro.org> wrote:
>
> On Thu, 28 May 2020 at 23:31, Alistair Francis <alistair.francis@wdc.com> wrote:
> >
> > This adds a barebone OpenTitan machine to QEMU.
> >
> > Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> > Reviewed-by: Bin Meng <bin.meng@windriver.com>
> > ---
> >  default-configs/riscv32-softmmu.mak |   1 +
> >  default-configs/riscv64-softmmu.mak |  11 +-
>
> Just noticed this, but:
>
> > diff --git a/default-configs/riscv32-softmmu.mak b/default-configs/riscv32-softmmu.mak
> > index 1ae077ed87..94a236c9c2 100644
> > --- a/default-configs/riscv32-softmmu.mak
> > +++ b/default-configs/riscv32-softmmu.mak
> > @@ -10,3 +10,4 @@ CONFIG_SPIKE=y
> >  CONFIG_SIFIVE_E=y
> >  CONFIG_SIFIVE_U=y
> >  CONFIG_RISCV_VIRT=y
> > +CONFIG_OPENTITAN=y
> > diff --git a/default-configs/riscv64-softmmu.mak b/default-configs/riscv64-softmmu.mak
> > index 235c6f473f..aaf6d735bb 100644
> > --- a/default-configs/riscv64-softmmu.mak
> > +++ b/default-configs/riscv64-softmmu.mak
> > @@ -1,3 +1,12 @@
> >  # Default configuration for riscv64-softmmu
> >
> > -include riscv32-softmmu.mak
> > +# Uncomment the following lines to disable these optional devices:
> > +#
> > +#CONFIG_PCI_DEVICES=n
> > +
> > +# Boards:
> > +#
> > +CONFIG_SPIKE=y
> > +CONFIG_SIFIVE_E=y
> > +CONFIG_SIFIVE_U=y
> > +CONFIG_RISCV_VIRT=y
>
> ...shouldn't the riscv64-softmmu config have CONFIG_OPENTITAN too?
> The usual principle is that the 64-bit executable can run the
> 32-bit boards too.

I didn't know that was the general case. I'll send a patch to enable this.

Alistair

>
> thanks
> -- PMM


^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v5 06/11] riscv: Initial commit of OpenTitan machine
@ 2020-09-09 17:49       ` Alistair Francis
  0 siblings, 0 replies; 68+ messages in thread
From: Alistair Francis @ 2020-09-09 17:49 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Alistair Francis, QEMU Developers, open list:RISC-V, Bin Meng,
	Palmer Dabbelt

On Tue, Sep 8, 2020 at 7:52 AM Peter Maydell <peter.maydell@linaro.org> wrote:
>
> On Thu, 28 May 2020 at 23:31, Alistair Francis <alistair.francis@wdc.com> wrote:
> >
> > This adds a barebone OpenTitan machine to QEMU.
> >
> > Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> > Reviewed-by: Bin Meng <bin.meng@windriver.com>
> > ---
> >  default-configs/riscv32-softmmu.mak |   1 +
> >  default-configs/riscv64-softmmu.mak |  11 +-
>
> Just noticed this, but:
>
> > diff --git a/default-configs/riscv32-softmmu.mak b/default-configs/riscv32-softmmu.mak
> > index 1ae077ed87..94a236c9c2 100644
> > --- a/default-configs/riscv32-softmmu.mak
> > +++ b/default-configs/riscv32-softmmu.mak
> > @@ -10,3 +10,4 @@ CONFIG_SPIKE=y
> >  CONFIG_SIFIVE_E=y
> >  CONFIG_SIFIVE_U=y
> >  CONFIG_RISCV_VIRT=y
> > +CONFIG_OPENTITAN=y
> > diff --git a/default-configs/riscv64-softmmu.mak b/default-configs/riscv64-softmmu.mak
> > index 235c6f473f..aaf6d735bb 100644
> > --- a/default-configs/riscv64-softmmu.mak
> > +++ b/default-configs/riscv64-softmmu.mak
> > @@ -1,3 +1,12 @@
> >  # Default configuration for riscv64-softmmu
> >
> > -include riscv32-softmmu.mak
> > +# Uncomment the following lines to disable these optional devices:
> > +#
> > +#CONFIG_PCI_DEVICES=n
> > +
> > +# Boards:
> > +#
> > +CONFIG_SPIKE=y
> > +CONFIG_SIFIVE_E=y
> > +CONFIG_SIFIVE_U=y
> > +CONFIG_RISCV_VIRT=y
>
> ...shouldn't the riscv64-softmmu config have CONFIG_OPENTITAN too?
> The usual principle is that the 64-bit executable can run the
> 32-bit boards too.

I didn't know that was the general case. I'll send a patch to enable this.

Alistair

>
> thanks
> -- PMM


^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v5 06/11] riscv: Initial commit of OpenTitan machine
  2020-09-09 17:49       ` Alistair Francis
@ 2020-09-09 19:00         ` Peter Maydell
  -1 siblings, 0 replies; 68+ messages in thread
From: Peter Maydell @ 2020-09-09 19:00 UTC (permalink / raw)
  To: Alistair Francis
  Cc: open list:RISC-V, Palmer Dabbelt, Bin Meng, Alistair Francis,
	QEMU Developers

On Wed, 9 Sep 2020 at 19:00, Alistair Francis <alistair23@gmail.com> wrote:
>
> On Tue, Sep 8, 2020 at 7:52 AM Peter Maydell <peter.maydell@linaro.org> wrote:
> > ...shouldn't the riscv64-softmmu config have CONFIG_OPENTITAN too?
> > The usual principle is that the 64-bit executable can run the
> > 32-bit boards too.
>
> I didn't know that was the general case. I'll send a patch to enable this.

Somebody on IRC suggested that the riscv code currently
assumes that #ifdef TARGET_RISCV64 implies a 64-bit CPU,
ie that the 32-bit CPUs don't actually behave correctly
if built into the qemu-system-riscv64 process, so you might
want to check that things seem to work when you enable it...

thanks
-- pMM


^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v5 06/11] riscv: Initial commit of OpenTitan machine
@ 2020-09-09 19:00         ` Peter Maydell
  0 siblings, 0 replies; 68+ messages in thread
From: Peter Maydell @ 2020-09-09 19:00 UTC (permalink / raw)
  To: Alistair Francis
  Cc: Alistair Francis, QEMU Developers, open list:RISC-V, Bin Meng,
	Palmer Dabbelt

On Wed, 9 Sep 2020 at 19:00, Alistair Francis <alistair23@gmail.com> wrote:
>
> On Tue, Sep 8, 2020 at 7:52 AM Peter Maydell <peter.maydell@linaro.org> wrote:
> > ...shouldn't the riscv64-softmmu config have CONFIG_OPENTITAN too?
> > The usual principle is that the 64-bit executable can run the
> > 32-bit boards too.
>
> I didn't know that was the general case. I'll send a patch to enable this.

Somebody on IRC suggested that the riscv code currently
assumes that #ifdef TARGET_RISCV64 implies a 64-bit CPU,
ie that the 32-bit CPUs don't actually behave correctly
if built into the qemu-system-riscv64 process, so you might
want to check that things seem to work when you enable it...

thanks
-- pMM


^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v5 06/11] riscv: Initial commit of OpenTitan machine
  2020-09-09 19:00         ` Peter Maydell
@ 2020-09-09 19:51           ` Palmer Dabbelt
  -1 siblings, 0 replies; 68+ messages in thread
From: Palmer Dabbelt @ 2020-09-09 19:51 UTC (permalink / raw)
  To: Peter Maydell
  Cc: alistair23, bmeng.cn, Alistair Francis, qemu-devel, qemu-riscv

On Wed, 09 Sep 2020 12:00:07 PDT (-0700), Peter Maydell wrote:
> On Wed, 9 Sep 2020 at 19:00, Alistair Francis <alistair23@gmail.com> wrote:
>>
>> On Tue, Sep 8, 2020 at 7:52 AM Peter Maydell <peter.maydell@linaro.org> wrote:
>> > ...shouldn't the riscv64-softmmu config have CONFIG_OPENTITAN too?
>> > The usual principle is that the 64-bit executable can run the
>> > 32-bit boards too.
>>
>> I didn't know that was the general case. I'll send a patch to enable this.
>
> Somebody on IRC suggested that the riscv code currently
> assumes that #ifdef TARGET_RISCV64 implies a 64-bit CPU,
> ie that the 32-bit CPUs don't actually behave correctly
> if built into the qemu-system-riscv64 process, so you might
> want to check that things seem to work when you enable it...

IIRC there's a whole bunch of that floating around the RISC-V port, so just
tossing a 32-bit CPU into qemu-system-riscv64 is going to result in garbage.
At the time we originally did the port we though we weren't goin to have
mixed-XLEN systems, but the ISA now allows for it so in theory we should go fix
all that.

I don't think anyone has looked into doing it, though, as there isn't much
interest in mixed-XLEN systems (though oddly enough there was a glibc post
yesterday about them).


^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v5 06/11] riscv: Initial commit of OpenTitan machine
@ 2020-09-09 19:51           ` Palmer Dabbelt
  0 siblings, 0 replies; 68+ messages in thread
From: Palmer Dabbelt @ 2020-09-09 19:51 UTC (permalink / raw)
  To: Peter Maydell
  Cc: alistair23, Alistair Francis, qemu-devel, qemu-riscv, bmeng.cn

On Wed, 09 Sep 2020 12:00:07 PDT (-0700), Peter Maydell wrote:
> On Wed, 9 Sep 2020 at 19:00, Alistair Francis <alistair23@gmail.com> wrote:
>>
>> On Tue, Sep 8, 2020 at 7:52 AM Peter Maydell <peter.maydell@linaro.org> wrote:
>> > ...shouldn't the riscv64-softmmu config have CONFIG_OPENTITAN too?
>> > The usual principle is that the 64-bit executable can run the
>> > 32-bit boards too.
>>
>> I didn't know that was the general case. I'll send a patch to enable this.
>
> Somebody on IRC suggested that the riscv code currently
> assumes that #ifdef TARGET_RISCV64 implies a 64-bit CPU,
> ie that the 32-bit CPUs don't actually behave correctly
> if built into the qemu-system-riscv64 process, so you might
> want to check that things seem to work when you enable it...

IIRC there's a whole bunch of that floating around the RISC-V port, so just
tossing a 32-bit CPU into qemu-system-riscv64 is going to result in garbage.
At the time we originally did the port we though we weren't goin to have
mixed-XLEN systems, but the ISA now allows for it so in theory we should go fix
all that.

I don't think anyone has looked into doing it, though, as there isn't much
interest in mixed-XLEN systems (though oddly enough there was a glibc post
yesterday about them).


^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v5 06/11] riscv: Initial commit of OpenTitan machine
  2020-09-09 19:51           ` Palmer Dabbelt
@ 2020-09-10 18:48             ` Alistair Francis
  -1 siblings, 0 replies; 68+ messages in thread
From: Alistair Francis @ 2020-09-10 18:48 UTC (permalink / raw)
  To: Palmer Dabbelt
  Cc: Peter Maydell, Bin Meng, Alistair Francis,
	qemu-devel@nongnu.org Developers, open list:RISC-V

On Wed, Sep 9, 2020 at 12:51 PM Palmer Dabbelt <palmer@dabbelt.com> wrote:
>
> On Wed, 09 Sep 2020 12:00:07 PDT (-0700), Peter Maydell wrote:
> > On Wed, 9 Sep 2020 at 19:00, Alistair Francis <alistair23@gmail.com> wrote:
> >>
> >> On Tue, Sep 8, 2020 at 7:52 AM Peter Maydell <peter.maydell@linaro.org> wrote:
> >> > ...shouldn't the riscv64-softmmu config have CONFIG_OPENTITAN too?
> >> > The usual principle is that the 64-bit executable can run the
> >> > 32-bit boards too.
> >>
> >> I didn't know that was the general case. I'll send a patch to enable this.
> >
> > Somebody on IRC suggested that the riscv code currently
> > assumes that #ifdef TARGET_RISCV64 implies a 64-bit CPU,
> > ie that the 32-bit CPUs don't actually behave correctly
> > if built into the qemu-system-riscv64 process, so you might
> > want to check that things seem to work when you enable it...

Yep, we don't even build the 32-bit CPUs for 64-bit.

I'm going to leave this config disabled and we can add a TODO of
fixing up riscv64-softmmu to support 32-bit and 64-bit.

>
> IIRC there's a whole bunch of that floating around the RISC-V port, so just
> tossing a 32-bit CPU into qemu-system-riscv64 is going to result in garbage.
> At the time we originally did the port we though we weren't goin to have
> mixed-XLEN systems, but the ISA now allows for it so in theory we should go fix
> all that.

Dynamically changing XLEN is then another can of worms. Although there
isn't much interest, it becomes more useful with the Hypervisor
extensions supporting 32-bit guests on 64-bit systems.

Alistair

>
> I don't think anyone has looked into doing it, though, as there isn't much
> interest in mixed-XLEN systems (though oddly enough there was a glibc post
> yesterday about them).


^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v5 06/11] riscv: Initial commit of OpenTitan machine
@ 2020-09-10 18:48             ` Alistair Francis
  0 siblings, 0 replies; 68+ messages in thread
From: Alistair Francis @ 2020-09-10 18:48 UTC (permalink / raw)
  To: Palmer Dabbelt
  Cc: Peter Maydell, Alistair Francis,
	qemu-devel@nongnu.org Developers, open list:RISC-V, Bin Meng

On Wed, Sep 9, 2020 at 12:51 PM Palmer Dabbelt <palmer@dabbelt.com> wrote:
>
> On Wed, 09 Sep 2020 12:00:07 PDT (-0700), Peter Maydell wrote:
> > On Wed, 9 Sep 2020 at 19:00, Alistair Francis <alistair23@gmail.com> wrote:
> >>
> >> On Tue, Sep 8, 2020 at 7:52 AM Peter Maydell <peter.maydell@linaro.org> wrote:
> >> > ...shouldn't the riscv64-softmmu config have CONFIG_OPENTITAN too?
> >> > The usual principle is that the 64-bit executable can run the
> >> > 32-bit boards too.
> >>
> >> I didn't know that was the general case. I'll send a patch to enable this.
> >
> > Somebody on IRC suggested that the riscv code currently
> > assumes that #ifdef TARGET_RISCV64 implies a 64-bit CPU,
> > ie that the 32-bit CPUs don't actually behave correctly
> > if built into the qemu-system-riscv64 process, so you might
> > want to check that things seem to work when you enable it...

Yep, we don't even build the 32-bit CPUs for 64-bit.

I'm going to leave this config disabled and we can add a TODO of
fixing up riscv64-softmmu to support 32-bit and 64-bit.

>
> IIRC there's a whole bunch of that floating around the RISC-V port, so just
> tossing a 32-bit CPU into qemu-system-riscv64 is going to result in garbage.
> At the time we originally did the port we though we weren't goin to have
> mixed-XLEN systems, but the ISA now allows for it so in theory we should go fix
> all that.

Dynamically changing XLEN is then another can of worms. Although there
isn't much interest, it becomes more useful with the Hypervisor
extensions supporting 32-bit guests on 64-bit systems.

Alistair

>
> I don't think anyone has looked into doing it, though, as there isn't much
> interest in mixed-XLEN systems (though oddly enough there was a glibc post
> yesterday about them).


^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v5 6/11] riscv: Initial commit of OpenTitan machine
  2020-05-28 22:14   ` Alistair Francis
                     ` (2 preceding siblings ...)
  (?)
@ 2023-05-19 17:15   ` Philippe Mathieu-Daudé
  -1 siblings, 0 replies; 68+ messages in thread
From: Philippe Mathieu-Daudé @ 2023-05-19 17:15 UTC (permalink / raw)
  To: Alistair Francis, qemu-devel, qemu-riscv; +Cc: bmeng.cn, palmer, alistair23

Hi Alistair,

[Old patch]

On 29/5/20 00:14, Alistair Francis wrote:
> This adds a barebone OpenTitan machine to QEMU.
> 
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> Reviewed-by: Bin Meng <bin.meng@windriver.com>
> ---
>   default-configs/riscv32-softmmu.mak |   1 +
>   default-configs/riscv64-softmmu.mak |  11 +-
>   include/hw/riscv/opentitan.h        |  68 ++++++++++
>   hw/riscv/opentitan.c                | 184 ++++++++++++++++++++++++++++
>   MAINTAINERS                         |   9 ++
>   hw/riscv/Kconfig                    |   5 +
>   hw/riscv/Makefile.objs              |   1 +
>   7 files changed, 278 insertions(+), 1 deletion(-)
>   create mode 100644 include/hw/riscv/opentitan.h
>   create mode 100644 hw/riscv/opentitan.c


> diff --git a/include/hw/riscv/opentitan.h b/include/hw/riscv/opentitan.h
> new file mode 100644
> index 0000000000..a4b6499444
> --- /dev/null
> +++ b/include/hw/riscv/opentitan.h
> @@ -0,0 +1,68 @@
> +/*
> + * QEMU RISC-V Board Compatible with OpenTitan FPGA platform
> + *
> + * Copyright (c) 2020 Western Digital
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2 or later, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope 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.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef HW_OPENTITAN_H
> +#define HW_OPENTITAN_H
> +
> +#include "hw/riscv/riscv_hart.h"
> +
> +#define TYPE_RISCV_IBEX_SOC "riscv.lowrisc.ibex.soc"
> +#define RISCV_IBEX_SOC(obj) \
> +    OBJECT_CHECK(LowRISCIbexSoCState, (obj), TYPE_RISCV_IBEX_SOC)
> +
> +typedef struct LowRISCIbexSoCState {
> +    /*< private >*/
> +    SysBusDevice parent_obj;
> +
> +    /*< public >*/
> +    RISCVHartArrayState cpus;
> +    MemoryRegion flash_mem;
> +    MemoryRegion rom;
> +} LowRISCIbexSoCState;
> +
> +typedef struct OpenTitanState {
> +    /*< private >*/
> +    SysBusDevice parent_obj;

Shouldn't this object inheritate from MachineState ...?

> +    /*< public >*/
> +    LowRISCIbexSoCState soc;
> +} OpenTitanState;


> diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c
> new file mode 100644
> index 0000000000..b4fb836466
> --- /dev/null
> +++ b/hw/riscv/opentitan.c
> @@ -0,0 +1,184 @@
> +/*
> + * QEMU RISC-V Board Compatible with OpenTitan FPGA platform
> + *
> + * Copyright (c) 2020 Western Digital
> + *
> + * Provides a board compatible with the OpenTitan FPGA platform:
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2 or later, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope 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.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "hw/riscv/opentitan.h"
> +#include "qapi/error.h"
> +#include "hw/boards.h"
> +#include "hw/misc/unimp.h"
> +#include "hw/riscv/boot.h"
> +#include "exec/address-spaces.h"
> +
> +static const struct MemmapEntry {
> +    hwaddr base;
> +    hwaddr size;
> +} ibex_memmap[] = {
> +    [IBEX_ROM] =            {  0x00008000,   0xc000 },
> +    [IBEX_RAM] =            {  0x10000000,  0x10000 },
> +    [IBEX_FLASH] =          {  0x20000000,  0x80000 },
> +    [IBEX_UART] =           {  0x40000000,  0x10000 },
> +    [IBEX_GPIO] =           {  0x40010000,  0x10000 },
> +    [IBEX_SPI] =            {  0x40020000,  0x10000 },
> +    [IBEX_FLASH_CTRL] =     {  0x40030000,  0x10000 },
> +    [IBEX_PINMUX] =         {  0x40070000,  0x10000 },
> +    [IBEX_RV_TIMER] =       {  0x40080000,  0x10000 },
> +    [IBEX_PLIC] =           {  0x40090000,  0x10000 },
> +    [IBEX_PWRMGR] =         {  0x400A0000,  0x10000 },
> +    [IBEX_RSTMGR] =         {  0x400B0000,  0x10000 },
> +    [IBEX_CLKMGR] =         {  0x400C0000,  0x10000 },
> +    [IBEX_AES] =            {  0x40110000,  0x10000 },
> +    [IBEX_HMAC] =           {  0x40120000,  0x10000 },
> +    [IBEX_ALERT_HANDLER] =  {  0x40130000,  0x10000 },
> +    [IBEX_NMI_GEN] =        {  0x40140000,  0x10000 },
> +    [IBEX_USBDEV] =         {  0x40150000,  0x10000 },
> +    [IBEX_PADCTRL] =        {  0x40160000,  0x10000 }
> +};
> +
> +static void riscv_opentitan_init(MachineState *machine)
> +{
> +    const struct MemmapEntry *memmap = ibex_memmap;
> +    OpenTitanState *s = g_new0(OpenTitanState, 1);

... because looking at QOM design issue, this line looks dubious.

> +    MemoryRegion *sys_mem = get_system_memory();
> +    MemoryRegion *main_mem = g_new(MemoryRegion, 1);
> +
> +    /* Initialize SoC */
> +    object_initialize_child(OBJECT(machine), "soc", &s->soc,
> +                            sizeof(s->soc), TYPE_RISCV_IBEX_SOC,
> +                            &error_abort, NULL);
> +    object_property_set_bool(OBJECT(&s->soc), true, "realized",
> +                            &error_abort);
> +
> +    memory_region_init_ram(main_mem, NULL, "riscv.lowrisc.ibex.ram",
> +        memmap[IBEX_RAM].size, &error_fatal);
> +    memory_region_add_subregion(sys_mem,
> +        memmap[IBEX_RAM].base, main_mem);
> +
> +
> +    if (machine->firmware) {
> +        riscv_load_firmware(machine->firmware, memmap[IBEX_RAM].base, NULL);
> +    }
> +
> +    if (machine->kernel_filename) {
> +        riscv_load_kernel(machine->kernel_filename, NULL);
> +    }
> +}


^ permalink raw reply	[flat|nested] 68+ messages in thread

end of thread, other threads:[~2023-05-19 17:16 UTC | newest]

Thread overview: 68+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-05-28 22:14 [PATCH v5 00/11] RISC-V Add the OpenTitan Machine Alistair Francis
2020-05-28 22:14 ` Alistair Francis
2020-05-28 22:14 ` [PATCH v5 01/11] riscv/boot: Add a missing header include Alistair Francis
2020-05-28 22:14   ` Alistair Francis
2020-05-28 22:14 ` [PATCH v5 02/11] target/riscv: Don't overwrite the reset vector Alistair Francis
2020-05-28 22:14   ` Alistair Francis
2020-05-28 22:14 ` [PATCH v5 03/11] target/riscv: Disable the MMU correctly Alistair Francis
2020-05-28 22:14   ` Alistair Francis
2020-06-01  5:24   ` Bin Meng
2020-06-01  5:24     ` Bin Meng
2020-05-28 22:14 ` [PATCH v5 04/11] target/riscv: Don't set PMP feature in the cpu init Alistair Francis
2020-05-28 22:14   ` Alistair Francis
2020-06-01  5:26   ` Bin Meng
2020-06-01  5:26     ` Bin Meng
2020-05-28 22:14 ` [PATCH v5 05/11] target/riscv: Add the lowRISC Ibex CPU Alistair Francis
2020-05-28 22:14   ` Alistair Francis
2020-05-28 22:14 ` [PATCH v5 06/11] riscv: Initial commit of OpenTitan machine Alistair Francis
2020-05-28 22:14   ` Alistair Francis
2020-06-09 13:48   ` Damien Hedde
2020-06-09 13:48     ` Damien Hedde
2020-06-09 14:21     ` Philippe Mathieu-Daudé
2020-06-09 23:09       ` Alistair Francis
2020-06-09 23:09         ` Alistair Francis
2020-09-08 14:52   ` Peter Maydell
2020-09-08 14:52     ` Peter Maydell
2020-09-09 17:49     ` Alistair Francis
2020-09-09 17:49       ` Alistair Francis
2020-09-09 19:00       ` Peter Maydell
2020-09-09 19:00         ` Peter Maydell
2020-09-09 19:51         ` Palmer Dabbelt
2020-09-09 19:51           ` Palmer Dabbelt
2020-09-10 18:48           ` Alistair Francis
2020-09-10 18:48             ` Alistair Francis
2023-05-19 17:15   ` [PATCH v5 6/11] " Philippe Mathieu-Daudé
2020-05-28 22:14 ` [PATCH v5 07/11] hw/char: Initial commit of Ibex UART Alistair Francis
2020-05-28 22:14   ` Alistair Francis
2020-06-01 21:23   ` Alistair Francis
2020-06-01 21:23     ` Alistair Francis
2020-06-02 11:22   ` LIU Zhiwei
2020-06-02 11:22     ` LIU Zhiwei
2020-06-02 12:28     ` LIU Zhiwei
2020-06-02 12:28       ` LIU Zhiwei
2020-06-02 17:54       ` Alistair Francis
2020-06-02 17:54         ` Alistair Francis
2020-06-03 10:33         ` LIU Zhiwei
2020-06-03 10:33           ` LIU Zhiwei
2020-06-03 15:56           ` Alistair Francis
2020-06-03 15:56             ` Alistair Francis
2020-06-04  1:59             ` LIU Zhiwei
2020-06-04  1:59               ` LIU Zhiwei
2020-06-04  4:35               ` Alistair Francis
2020-06-04  4:35                 ` Alistair Francis
2020-06-04  5:05                 ` LIU Zhiwei
2020-06-04  5:05                   ` LIU Zhiwei
2020-06-04  5:46                   ` Alistair Francis
2020-06-04  5:46                     ` Alistair Francis
2020-06-04  5:40                 ` LIU Zhiwei
2020-06-04  5:40                   ` LIU Zhiwei
2020-06-02 17:46     ` Alistair Francis
2020-06-02 17:46       ` Alistair Francis
2020-05-28 22:14 ` [PATCH v5 08/11] hw/intc: Initial commit of lowRISC Ibex PLIC Alistair Francis
2020-05-28 22:14   ` Alistair Francis
2020-05-28 22:14 ` [PATCH v5 09/11] riscv/opentitan: Connect the PLIC device Alistair Francis
2020-05-28 22:14   ` Alistair Francis
2020-05-28 22:14 ` [PATCH v5 10/11] riscv/opentitan: Connect the UART device Alistair Francis
2020-05-28 22:14   ` Alistair Francis
2020-05-28 22:14 ` [PATCH v5 11/11] target/riscv: Use a smaller guess size for no-MMU PMP Alistair Francis
2020-05-28 22:14   ` Alistair Francis

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.