qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 00/10] Add Allwinner H3 SoC and Orange Pi PC Machine
@ 2019-12-16 23:35 Niek Linnenbank
  2019-12-16 23:35 ` [PATCH v2 01/10] hw: arm: add Allwinner H3 System-on-Chip Niek Linnenbank
                   ` (10 more replies)
  0 siblings, 11 replies; 30+ messages in thread
From: Niek Linnenbank @ 2019-12-16 23:35 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, Niek Linnenbank, qemu-arm, philmd

Dear QEMU developers,

Hereby I would like to contribute the following set of patches to QEMU
which add support for the Allwinner H3 System on Chip and the
Orange Pi PC machine. The following features and devices are supported:

 * SMP (Quad Core Cortex A7)
 * Generic Interrupt Controller configuration
 * SRAM mappings
 * Timer device (re-used from Allwinner A10)
 * UART
 * SD/MMC storage controller
 * EMAC ethernet connectivity
 * USB 2.0 interfaces
 * Clock Control Unit
 * System Control module
 * Security Identifier device

Functionality related to graphical output such as HDMI, GPU,
Display Engine and audio are not included. Recently released
mainline Linux kernels (4.19 up to latest master) and mainline U-Boot
are known to work. The SD/MMC code is tested using bonnie++ and
various tools such as fsck, dd and fdisk. The EMAC is verified with iperf3
using -netdev socket.

To build a Linux mainline kernel that can be booted by the Orange Pi PC
machine, simply configure the kernel using the sunxi_defconfig configuration:
 $ ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- make mrproper
 $ ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- make sunxi_defconfig

To be able to use USB storage, you need to manually enable the corresponding
configuration item. Start the kconfig configuration tool:
 $ ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- make menuconfig

Navigate to the following item, enable it and save your configuration:
 Device Drivers > USB support > USB Mass Storage support

Build the Linux kernel with:
 $ ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- make -j5

To boot the newly build linux kernel in QEMU with the Orange Pi PC machine, use:
 $ qemu-system-arm -M orangepi-pc -m 512 -nic user -nographic \
     -kernel /path/to/linux/arch/arm/boot/zImage \
     -append 'console=ttyS0,115200' \
     -dtb /path/to/linux/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dtb

Note that this kernel does not have a root filesystem. You may provide it
with an official Orange Pi PC image [1] either as an SD card or as
USB mass storage. To boot using the Orange Pi PC Debian image on SD card,
simply add the -sd argument and provide the proper root= kernel parameter:
 $ qemu-system-arm -M orangepi-pc -m 512 -nic user -nographic \
     -kernel /path/to/linux/arch/arm/boot/zImage \
     -append 'console=ttyS0,115200 root=/dev/mmcblk0p2' \
     -dtb /path/to/linux/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dtb \
     -sd OrangePi_pc_debian_stretch_server_linux5.3.5_v1.0.img

Alternatively, you can also choose to build and boot a recent buildroot [2]
using the orangepi_pc_defconfig or Armbian image [3] for Orange Pi PC.
To attach an USB mass storage device to the machine, simply append to the command:
 -drive if=none,id=stick,file=myimage.img \
 -device usb-storage,bus=usb-bus.0,drive=stick

U-Boot mainline can be build and configured using the orangepi_pc_defconfig
using similar commands as describe above for Linux. To start U-Boot using
the Orange Pi PC machine, provide the u-boot binary to the -kernel argument:
 $ qemu-system-arm -M orangepi-pc -m 512 -nic user -nographic \
     -kernel /path/to/uboot/u-boot -sd disk.img

Use the following U-boot commands to load and boot a Linux kernel from SD card:
 -> setenv bootargs console=ttyS0,115200
 -> ext2load mmc 0 0x42000000 zImage
 -> ext2load mmc 0 0x43000000 sun8i-h3-orangepi-pc.dtb
 -> bootz 0x42000000 - 0x43000000

Looking forward to your review comments. I will do my best
to update the patches where needed.

===== CHANGELOG =====

v2:
 * hw/arm/allwinner-h3.c: use cpus array in AwH3State instead of object_new()
 * hw/arm/allwinner-h3.c: use error_abort in aw_h3_realize()
 * hw/arm/allwinner-h3.c: use qdev_init_nofail() in aw_h3_realize()
 * hw/arm/allwinner-h3.c: use qdev_get_gpio_in() instead of irq array
 * hw/arm/allwinner-h3.c: add all missing unimplemented devices (memory map is complete)
 * hw/arm/allwinner-h3.c: add UART1, UART2, UART3 and remove 'if (serial_hd(...))'
 * hw/arm/allwinner-h3.c: remove sysbusdev variable and use SYS_BUS_DEVICE() directly
 * include/hw/arm/allwinner-h3.h: move PPI/SPI defines to allwinner-h3.c as enum
 * include/hw/arm/allwinner-h3.h: replace mem base/size defines with enum and memmap (like aspeed_soc.h)
 * hw/arm/orangepi.c: Only allow Cortex-A7 in machine->cpu_type
 * hw/arm/orangepi.c: Set mc->default_cpu_type to ARM_CPU_TYPE_NAME("cortex-a7")
 * hw/arm/orangepi.c: Use error_abort in orangepi_init()
 * hw/arm/orangepi.c: only allow maximum 1GiB RAM
 * hw/arm/orangepi.c: renamed machine name to 'orangepi-pc'
 * hw/arm/orangepi.c: remove mc->ignore_memory_transaction_failures = true
 * hw/arm/orangepi.c: remove unnecessary check for 'sd-bus'
 * hw/net/allwinner-h3-emac.c: use AW_H3_EMAC() for opaque in read/write functions
 * hw/sd/allwinner-h3-sdhost.c: replace register defines with enums
 * hw/sd/allwinner-h3-sdhost.c: remove 'irq_en' and use if() to set 'irq' in update_irq function
 * hw/sd/allwinner-h3-sdhost.c: simplified if (rlen==) conditions in send_command function
 * hw/sd/allwinner-h3-sdhost.c: use KiB macro to set desc->size
 * hw/sd/allwinner-h3-sdhost.c: use ARRAY_SIZE() macro in reset function
 * hw/misc/allwinner-h3-sid.c: replace randomized identifier with QemuUUID property
 * hw/misc/allwinner-h3-sid.c: add tracing for read/write functions
 * hw/misc/allwinner-h3-sid.c: fix incorrect usage of REG_PRCTL_OP_LOCK/REG_PRCTL_WRITE
 * hw/misc/trace-events: add allwinner_h3_cpucfg* entries in correct patch (#7)
 * hw/*/trace-events: use PRIu32/PRIx32 macros for size and max fields
 * hw/*/allwinner-h3-*.c: set .impl.min_access_size = 4 to restrict MMIO access to 32-bit aligned
 * hw/*/allwinner-h3-*.c: replace register defines with enums
 * hw/*/allwinner-h3-*.c: set VMStateDescription.name with inline string (dont use TYPE macro)
 * include/hw/*/allwinner-h3-*.h: remove MEM_SIZE define and use size inline in the source file
 * target/arm/arm-powerctl.c: invoke arm_rebuild_hflags() after setting CP15 bits

With kind regards,

Niek Linnenbank

[1] http://www.orangepi.org/downloadresources/
[2] https://buildroot.org/download.html
[3] https://www.armbian.com/orange-pi-pc/

Niek Linnenbank (10):
  hw: arm: add Allwinner H3 System-on-Chip
  hw: arm: add Xunlong Orange Pi PC machine
  arm: allwinner-h3: add Clock Control Unit
  arm: allwinner-h3: add USB host controller
  arm: allwinner-h3: add System Control module
  arm/arm-powerctl: rebuild hflags after setting CP15 bits in
    arm_set_cpu_on()
  arm: allwinner-h3: add CPU Configuration module
  arm: allwinner-h3: add Security Identifier device
  arm: allwinner-h3: add SD/MMC host controller
  arm: allwinner-h3: add EMAC ethernet device

 default-configs/arm-softmmu.mak       |   1 +
 hw/usb/hcd-ehci.h                     |   1 +
 include/hw/arm/allwinner-h3.h         |  93 +++
 include/hw/misc/allwinner-h3-clk.h    |  40 ++
 include/hw/misc/allwinner-h3-cpucfg.h |  42 ++
 include/hw/misc/allwinner-h3-sid.h    |  40 ++
 include/hw/misc/allwinner-h3-syscon.h |  42 ++
 include/hw/net/allwinner-h3-emac.h    |  67 +++
 include/hw/sd/allwinner-h3-sdhost.h   |  71 +++
 hw/arm/allwinner-h3.c                 | 442 ++++++++++++++
 hw/arm/orangepi.c                     | 127 ++++
 hw/misc/allwinner-h3-clk.c            | 238 ++++++++
 hw/misc/allwinner-h3-cpucfg.c         | 288 +++++++++
 hw/misc/allwinner-h3-sid.c            | 179 ++++++
 hw/misc/allwinner-h3-syscon.c         | 146 +++++
 hw/net/allwinner-h3-emac.c            | 829 ++++++++++++++++++++++++++
 hw/sd/allwinner-h3-sdhost.c           | 813 +++++++++++++++++++++++++
 hw/usb/hcd-ehci-sysbus.c              |  17 +
 target/arm/arm-powerctl.c             |   3 +
 MAINTAINERS                           |   8 +
 hw/arm/Kconfig                        |   9 +
 hw/arm/Makefile.objs                  |   1 +
 hw/misc/Makefile.objs                 |   4 +
 hw/misc/trace-events                  |   9 +
 hw/net/Kconfig                        |   3 +
 hw/net/Makefile.objs                  |   1 +
 hw/net/trace-events                   |  10 +
 hw/sd/Makefile.objs                   |   1 +
 hw/sd/trace-events                    |   7 +
 29 files changed, 3532 insertions(+)
 create mode 100644 include/hw/arm/allwinner-h3.h
 create mode 100644 include/hw/misc/allwinner-h3-clk.h
 create mode 100644 include/hw/misc/allwinner-h3-cpucfg.h
 create mode 100644 include/hw/misc/allwinner-h3-sid.h
 create mode 100644 include/hw/misc/allwinner-h3-syscon.h
 create mode 100644 include/hw/net/allwinner-h3-emac.h
 create mode 100644 include/hw/sd/allwinner-h3-sdhost.h
 create mode 100644 hw/arm/allwinner-h3.c
 create mode 100644 hw/arm/orangepi.c
 create mode 100644 hw/misc/allwinner-h3-clk.c
 create mode 100644 hw/misc/allwinner-h3-cpucfg.c
 create mode 100644 hw/misc/allwinner-h3-sid.c
 create mode 100644 hw/misc/allwinner-h3-syscon.c
 create mode 100644 hw/net/allwinner-h3-emac.c
 create mode 100644 hw/sd/allwinner-h3-sdhost.c

-- 
2.17.1



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

* [PATCH v2 01/10] hw: arm: add Allwinner H3 System-on-Chip
  2019-12-16 23:35 [PATCH v2 00/10] Add Allwinner H3 SoC and Orange Pi PC Machine Niek Linnenbank
@ 2019-12-16 23:35 ` Niek Linnenbank
  2019-12-16 23:35 ` [PATCH v2 02/10] hw: arm: add Xunlong Orange Pi PC machine Niek Linnenbank
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 30+ messages in thread
From: Niek Linnenbank @ 2019-12-16 23:35 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, Niek Linnenbank, qemu-arm, philmd

The Allwinner H3 is a System on Chip containing four ARM Cortex A7
processor cores. Features and specifications include DDR2/DDR3 memory,
SD/MMC storage cards, 10/100/1000Mbit ethernet, USB 2.0, HDMI and
various I/O modules. This commit adds support for the Allwinner H3
System on Chip.

Signed-off-by: Niek Linnenbank <nieklinnenbank@gmail.com>
---
 default-configs/arm-softmmu.mak |   1 +
 include/hw/arm/allwinner-h3.h   |  80 +++++++
 hw/arm/allwinner-h3.c           | 360 ++++++++++++++++++++++++++++++++
 MAINTAINERS                     |   7 +
 hw/arm/Kconfig                  |   8 +
 hw/arm/Makefile.objs            |   1 +
 6 files changed, 457 insertions(+)
 create mode 100644 include/hw/arm/allwinner-h3.h
 create mode 100644 hw/arm/allwinner-h3.c

diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index 1f2e0e7fde..d75a239c2c 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -40,3 +40,4 @@ CONFIG_FSL_IMX25=y
 CONFIG_FSL_IMX7=y
 CONFIG_FSL_IMX6UL=y
 CONFIG_SEMIHOSTING=y
+CONFIG_ALLWINNER_H3=y
diff --git a/include/hw/arm/allwinner-h3.h b/include/hw/arm/allwinner-h3.h
new file mode 100644
index 0000000000..e50caeffaa
--- /dev/null
+++ b/include/hw/arm/allwinner-h3.h
@@ -0,0 +1,80 @@
+/*
+ * Allwinner H3 System on Chip emulation
+ *
+ * Copyright (C) 2019 Niek Linnenbank <nieklinnenbank@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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_ARM_ALLWINNER_H3_H
+#define HW_ARM_ALLWINNER_H3_H
+
+#include "qemu/error-report.h"
+#include "qemu/units.h"
+#include "hw/char/serial.h"
+#include "hw/arm/boot.h"
+#include "hw/timer/allwinner-a10-pit.h"
+#include "hw/intc/arm_gic.h"
+#include "target/arm/cpu.h"
+
+enum {
+    AW_H3_SRAM_A1,
+    AW_H3_SRAM_A2,
+    AW_H3_SRAM_C,
+    AW_H3_SYSCON,
+    AW_H3_SID,
+    AW_H3_CCU,
+    AW_H3_PIT,
+    AW_H3_UART0,
+    AW_H3_UART1,
+    AW_H3_UART2,
+    AW_H3_UART3,
+    AW_H3_EMAC,
+    AW_H3_MMC0,
+    AW_H3_EHCI0,
+    AW_H3_OHCI0,
+    AW_H3_EHCI1,
+    AW_H3_OHCI1,
+    AW_H3_EHCI2,
+    AW_H3_OHCI2,
+    AW_H3_EHCI3,
+    AW_H3_OHCI3,
+    AW_H3_GIC_DIST,
+    AW_H3_GIC_CPU,
+    AW_H3_GIC_HYP,
+    AW_H3_GIC_VCPU,
+    AW_H3_CPUCFG,
+    AW_H3_SDRAM
+};
+
+#define AW_H3_NUM_CPUS      (4)
+
+#define TYPE_AW_H3 "allwinner-h3"
+#define AW_H3(obj) OBJECT_CHECK(AwH3State, (obj), TYPE_AW_H3)
+
+typedef struct AwH3State {
+    /*< private >*/
+    DeviceState parent_obj;
+    /*< public >*/
+
+    ARMCPU cpus[AW_H3_NUM_CPUS];
+    const hwaddr *memmap;
+    AwA10PITState timer;
+    GICState gic;
+    MemoryRegion sram_a1;
+    MemoryRegion sram_a2;
+    MemoryRegion sram_c;
+} AwH3State;
+
+#endif
diff --git a/hw/arm/allwinner-h3.c b/hw/arm/allwinner-h3.c
new file mode 100644
index 0000000000..1a47de56f5
--- /dev/null
+++ b/hw/arm/allwinner-h3.c
@@ -0,0 +1,360 @@
+/*
+ * Allwinner H3 System on Chip emulation
+ *
+ * Copyright (C) 2019 Niek Linnenbank <nieklinnenbank@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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 "exec/address-spaces.h"
+#include "qapi/error.h"
+#include "qemu/module.h"
+#include "qemu/units.h"
+#include "cpu.h"
+#include "hw/sysbus.h"
+#include "hw/arm/allwinner-h3.h"
+#include "hw/misc/unimp.h"
+#include "sysemu/sysemu.h"
+
+/* Memory map */
+const hwaddr aw_h3_memmap[] = {
+    [AW_H3_SRAM_A1]    = 0x00000000,
+    [AW_H3_SRAM_A2]    = 0x00044000,
+    [AW_H3_SRAM_C]     = 0x00010000,
+    [AW_H3_SYSCON]     = 0x01c00000,
+    [AW_H3_SID]        = 0x01c14000,
+    [AW_H3_CCU]        = 0x01c20000,
+    [AW_H3_PIT]        = 0x01c20c00,
+    [AW_H3_UART0]      = 0x01c28000,
+    [AW_H3_UART1]      = 0x01c28400,
+    [AW_H3_UART2]      = 0x01c28800,
+    [AW_H3_UART3]      = 0x01c28c00,
+    [AW_H3_EMAC]       = 0x01c30000,
+    [AW_H3_MMC0]       = 0x01c0f000,
+    [AW_H3_EHCI0]      = 0x01c1a000,
+    [AW_H3_OHCI0]      = 0x01c1a400,
+    [AW_H3_EHCI1]      = 0x01c1b000,
+    [AW_H3_OHCI1]      = 0x01c1b400,
+    [AW_H3_EHCI2]      = 0x01c1c000,
+    [AW_H3_OHCI2]      = 0x01c1c400,
+    [AW_H3_EHCI3]      = 0x01c1d000,
+    [AW_H3_OHCI3]      = 0x01c1d400,
+    [AW_H3_GIC_DIST]   = 0x01c81000,
+    [AW_H3_GIC_CPU]    = 0x01c82000,
+    [AW_H3_GIC_HYP]    = 0x01c84000,
+    [AW_H3_GIC_VCPU]   = 0x01c86000,
+    [AW_H3_CPUCFG]     = 0x01f01c00,
+    [AW_H3_SDRAM]      = 0x40000000
+};
+
+/* List of unimplemented devices */
+struct AwH3Unimplemented {
+    const char *device_name;
+    hwaddr base;
+    hwaddr size;
+} unimplemented[] = {
+    { "d-engine",  0x01000000, 4 * MiB },
+    { "d-inter",   0x01400000, 128 * KiB },
+    { "dma",       0x01c02000, 4 * KiB },
+    { "nfdc",      0x01c03000, 4 * KiB },
+    { "ts",        0x01c06000, 4 * KiB },
+    { "keymem",    0x01c0b000, 4 * KiB },
+    { "lcd0",      0x01c0c000, 4 * KiB },
+    { "lcd1",      0x01c0d000, 4 * KiB },
+    { "ve",        0x01c0e000, 4 * KiB },
+    { "mmc1",      0x01c10000, 4 * KiB },
+    { "mmc2",      0x01c11000, 4 * KiB },
+    { "crypto",    0x01c15000, 4 * KiB },
+    { "msgbox",    0x01c17000, 4 * KiB },
+    { "spinlock",  0x01c18000, 4 * KiB },
+    { "usb0-otg",  0x01c19000, 4 * KiB },
+    { "usb0-phy",  0x01c1a000, 4 * KiB },
+    { "usb1-phy",  0x01c1b000, 4 * KiB },
+    { "usb2-phy",  0x01c1c000, 4 * KiB },
+    { "usb3-phy",  0x01c1d000, 4 * KiB },
+    { "smc",       0x01c1e000, 4 * KiB },
+    { "pio",       0x01c20800, 1 * KiB },
+    { "owa",       0x01c21000, 1 * KiB },
+    { "pwm",       0x01c21400, 1 * KiB },
+    { "keyadc",    0x01c21800, 1 * KiB },
+    { "pcm0",      0x01c22000, 1 * KiB },
+    { "pcm1",      0x01c22400, 1 * KiB },
+    { "pcm2",      0x01c22800, 1 * KiB },
+    { "audio",     0x01c22c00, 2 * KiB },
+    { "smta",      0x01c23400, 1 * KiB },
+    { "ths",       0x01c25000, 1 * KiB },
+    { "uart0",     0x01c28000, 1 * KiB },
+    { "uart1",     0x01c28400, 1 * KiB },
+    { "uart2",     0x01c28800, 1 * KiB },
+    { "uart3",     0x01c28c00, 1 * KiB },
+    { "twi0",      0x01c2ac00, 1 * KiB },
+    { "twi1",      0x01c2b000, 1 * KiB },
+    { "twi2",      0x01c2b400, 1 * KiB },
+    { "scr",       0x01c2c400, 1 * KiB },
+    { "gpu",       0x01c40000, 64 * KiB },
+    { "hstmr",     0x01c60000, 4 * KiB },
+    { "dramcom",   0x01c62000, 4 * KiB },
+    { "dramctl0",  0x01c63000, 4 * KiB },
+    { "dramphy0",  0x01c65000, 4 * KiB },
+    { "spi0",      0x01c68000, 4 * KiB },
+    { "spi1",      0x01c69000, 4 * KiB },
+    { "csi",       0x01cb0000, 320 * KiB },
+    { "tve",       0x01e00000, 64 * KiB },
+    { "hdmi",      0x01ee0000, 128 * KiB },
+    { "rtc",       0x01f00000, 1 * KiB },
+    { "r_timer",   0x01f00800, 1 * KiB },
+    { "r_intc",    0x01f00c00, 1 * KiB },
+    { "r_wdog",    0x01f01000, 1 * KiB },
+    { "r_prcm",    0x01f01400, 1 * KiB },
+    { "r_twd",     0x01f01800, 1 * KiB },
+    { "r_cpucfg",  0x01f01c00, 1 * KiB },
+    { "r_cir-rx",  0x01f02000, 1 * KiB },
+    { "r_twi",     0x01f02400, 1 * KiB },
+    { "r_uart",    0x01f02800, 1 * KiB },
+    { "r_pio",     0x01f02c00, 1 * KiB },
+    { "r_pwm",     0x01f03800, 1 * KiB },
+    { "core-dbg",  0x3f500000, 128 * KiB },
+    { "tsgen-ro",  0x3f506000, 4 * KiB },
+    { "tsgen-ctl", 0x3f507000, 4 * KiB },
+    { "ddr-mem",   0x40000000, 2 * GiB },
+    { "n-brom",    0xffff0000, 32 * KiB },
+    { "s-brom",    0xffff0000, 64 * KiB }
+};
+
+/* Per Processor Interrupts */
+enum {
+    AW_H3_GIC_PPI_MAINT     =  9,
+    AW_H3_GIC_PPI_HYPTIMER  = 10,
+    AW_H3_GIC_PPI_VIRTTIMER = 11,
+    AW_H3_GIC_PPI_SECTIMER  = 13,
+    AW_H3_GIC_PPI_PHYSTIMER = 14
+};
+
+/* Shared Processor Interrupts */
+enum {
+    AW_H3_GIC_SPI_UART0     =  0,
+    AW_H3_GIC_SPI_UART1     =  1,
+    AW_H3_GIC_SPI_UART2     =  2,
+    AW_H3_GIC_SPI_UART3     =  3,
+    AW_H3_GIC_SPI_TIMER0    = 18,
+    AW_H3_GIC_SPI_TIMER1    = 19,
+    AW_H3_GIC_SPI_MMC0      = 60,
+    AW_H3_GIC_SPI_MMC1      = 61,
+    AW_H3_GIC_SPI_MMC2      = 62,
+    AW_H3_GIC_SPI_EHCI0     = 72,
+    AW_H3_GIC_SPI_OHCI0     = 73,
+    AW_H3_GIC_SPI_EHCI1     = 74,
+    AW_H3_GIC_SPI_OHCI1     = 75,
+    AW_H3_GIC_SPI_EHCI2     = 76,
+    AW_H3_GIC_SPI_OHCI2     = 77,
+    AW_H3_GIC_SPI_EHCI3     = 78,
+    AW_H3_GIC_SPI_OHCI3     = 79,
+    AW_H3_GIC_SPI_EMAC      = 82
+};
+
+/* Allwinner H3 constants */
+enum {
+    AW_H3_GIC_NUM_SPI       = 128
+};
+
+static void aw_h3_init(Object *obj)
+{
+    AwH3State *s = AW_H3(obj);
+
+    s->memmap = aw_h3_memmap;
+
+    for (int i = 0; i < AW_H3_NUM_CPUS; i++) {
+        object_initialize_child(obj, "cpu[*]", &s->cpus[i], sizeof(s->cpus[i]),
+                                ARM_CPU_TYPE_NAME("cortex-a7"),
+                                &error_abort, NULL);
+    }
+
+    sysbus_init_child_obj(obj, "gic", &s->gic, sizeof(s->gic),
+                          TYPE_ARM_GIC);
+
+    sysbus_init_child_obj(obj, "timer", &s->timer, sizeof(s->timer),
+                          TYPE_AW_A10_PIT);
+}
+
+static void aw_h3_realize(DeviceState *dev, Error **errp)
+{
+    AwH3State *s = AW_H3(dev);
+    unsigned i = 0;
+
+    /* CPUs */
+    for (i = 0; i < AW_H3_NUM_CPUS; i++) {
+
+        /* Provide Power State Coordination Interface */
+        object_property_set_int(OBJECT(&s->cpus[i]), QEMU_PSCI_CONDUIT_HVC,
+                                "psci-conduit", &error_abort);
+        if (error_abort != NULL) {
+            error_propagate(errp, error_abort);
+            return;
+        }
+
+        /* Disable secondary CPUs */
+        object_property_set_bool(OBJECT(&s->cpus[i]), i > 0,
+                                "start-powered-off", &error_abort);
+        if (error_abort != NULL) {
+            error_propagate(errp, error_abort);
+            return;
+        }
+
+        /* All exception levels required */
+        object_property_set_bool(OBJECT(&s->cpus[i]),
+                                 true, "has_el3", &error_abort);
+        if (error_abort != NULL) {
+            error_propagate(errp, error_abort);
+            return;
+        }
+
+        object_property_set_bool(OBJECT(&s->cpus[i]),
+                                 true, "has_el2", &error_abort);
+        if (error_abort != NULL) {
+            error_propagate(errp, error_abort);
+            return;
+        }
+
+        /* Mark realized */
+        qdev_init_nofail(DEVICE(&s->cpus[i]));
+    }
+
+    /* Generic Interrupt Controller */
+    qdev_prop_set_uint32(DEVICE(&s->gic), "num-irq", AW_H3_GIC_NUM_SPI +
+                                                     GIC_INTERNAL);
+    qdev_prop_set_uint32(DEVICE(&s->gic), "revision", 2);
+    qdev_prop_set_uint32(DEVICE(&s->gic), "num-cpu", AW_H3_NUM_CPUS);
+    qdev_prop_set_bit(DEVICE(&s->gic), "has-security-extensions", false);
+    qdev_prop_set_bit(DEVICE(&s->gic), "has-virtualization-extensions", true);
+    qdev_init_nofail(DEVICE(&s->gic));
+
+    sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 0, s->memmap[AW_H3_GIC_DIST]);
+    sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 1, s->memmap[AW_H3_GIC_CPU]);
+    sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 2, s->memmap[AW_H3_GIC_HYP]);
+    sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 3, s->memmap[AW_H3_GIC_VCPU]);
+
+    /*
+     * Wire the outputs from each CPU's generic timer and the GICv3
+     * maintenance interrupt signal to the appropriate GIC PPI inputs,
+     * and the GIC's IRQ/FIQ/VIRQ/VFIQ interrupt outputs to the CPU's inputs.
+     */
+    for (i = 0; i < AW_H3_NUM_CPUS; i++) {
+        DeviceState *cpudev = DEVICE(qemu_get_cpu(i));
+        int ppibase = AW_H3_GIC_NUM_SPI + i * GIC_INTERNAL + GIC_NR_SGIS;
+        int irq;
+        /*
+         * Mapping from the output timer irq lines from the CPU to the
+         * GIC PPI inputs used for this board.
+         */
+        const int timer_irq[] = {
+            [GTIMER_PHYS] = AW_H3_GIC_PPI_PHYSTIMER,
+            [GTIMER_VIRT] = AW_H3_GIC_PPI_VIRTTIMER,
+            [GTIMER_HYP]  = AW_H3_GIC_PPI_HYPTIMER,
+            [GTIMER_SEC]  = AW_H3_GIC_PPI_SECTIMER,
+        };
+
+        /* Connect CPU timer outputs to GIC PPI inputs */
+        for (irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) {
+            qdev_connect_gpio_out(cpudev, irq,
+                                  qdev_get_gpio_in(DEVICE(&s->gic),
+                                                   ppibase + timer_irq[irq]));
+        }
+
+        /* Connect GIC outputs to CPU interrupt inputs */
+        sysbus_connect_irq(SYS_BUS_DEVICE(&s->gic), i,
+                           qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
+        sysbus_connect_irq(SYS_BUS_DEVICE(&s->gic), i + AW_H3_NUM_CPUS,
+                           qdev_get_gpio_in(cpudev, ARM_CPU_FIQ));
+        sysbus_connect_irq(SYS_BUS_DEVICE(&s->gic), i + (2 * AW_H3_NUM_CPUS),
+                           qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ));
+        sysbus_connect_irq(SYS_BUS_DEVICE(&s->gic), i + (3 * AW_H3_NUM_CPUS),
+                           qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ));
+
+        /* GIC maintenance signal */
+        sysbus_connect_irq(SYS_BUS_DEVICE(&s->gic), i + (4 * AW_H3_NUM_CPUS),
+                           qdev_get_gpio_in(DEVICE(&s->gic),
+                                            ppibase + AW_H3_GIC_PPI_MAINT));
+    }
+
+    /* Timer */
+    qdev_init_nofail(DEVICE(&s->timer));
+    sysbus_mmio_map(SYS_BUS_DEVICE(&s->timer), 0, s->memmap[AW_H3_PIT]);
+    sysbus_connect_irq(SYS_BUS_DEVICE(&s->timer), 0,
+                       qdev_get_gpio_in(DEVICE(&s->gic), AW_H3_GIC_SPI_TIMER0));
+    sysbus_connect_irq(SYS_BUS_DEVICE(&s->timer), 1,
+                       qdev_get_gpio_in(DEVICE(&s->gic), AW_H3_GIC_SPI_TIMER1));
+
+    /* SRAM */
+    memory_region_init_ram(&s->sram_a1, OBJECT(dev), "sram A1",
+                            64 * KiB, &error_abort);
+    memory_region_init_ram(&s->sram_a2, OBJECT(dev), "sram A2",
+                            32 * KiB, &error_abort);
+    memory_region_init_ram(&s->sram_c, OBJECT(dev), "sram C",
+                            44 * KiB, &error_abort);
+    memory_region_add_subregion(get_system_memory(), s->memmap[AW_H3_SRAM_A1],
+                                &s->sram_a1);
+    memory_region_add_subregion(get_system_memory(), s->memmap[AW_H3_SRAM_A2],
+                                &s->sram_a2);
+    memory_region_add_subregion(get_system_memory(), s->memmap[AW_H3_SRAM_C],
+                                &s->sram_c);
+
+    /* UART0 */
+    serial_mm_init(get_system_memory(), s->memmap[AW_H3_UART0], 2,
+                   qdev_get_gpio_in(DEVICE(&s->gic), AW_H3_GIC_SPI_UART0),
+                   115200, serial_hd(0), DEVICE_NATIVE_ENDIAN);
+    /* UART1 */
+    serial_mm_init(get_system_memory(), s->memmap[AW_H3_UART1], 2,
+                   qdev_get_gpio_in(DEVICE(&s->gic), AW_H3_GIC_SPI_UART1),
+                   115200, serial_hd(1), DEVICE_NATIVE_ENDIAN);
+    /* UART2 */
+    serial_mm_init(get_system_memory(), s->memmap[AW_H3_UART2], 2,
+                   qdev_get_gpio_in(DEVICE(&s->gic), AW_H3_GIC_SPI_UART2),
+                   115200, serial_hd(2), DEVICE_NATIVE_ENDIAN);
+    /* UART3 */
+    serial_mm_init(get_system_memory(), s->memmap[AW_H3_UART3], 2,
+                   qdev_get_gpio_in(DEVICE(&s->gic), AW_H3_GIC_SPI_UART3),
+                   115200, serial_hd(3), DEVICE_NATIVE_ENDIAN);
+
+    /* Unimplemented devices */
+    for (int i = 0; i < ARRAY_SIZE(unimplemented); i++) {
+        create_unimplemented_device(unimplemented[i].device_name,
+                                    unimplemented[i].base,
+                                    unimplemented[i].size);
+    }
+}
+
+static void aw_h3_class_init(ObjectClass *oc, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(oc);
+
+    dc->realize = aw_h3_realize;
+    /* Reason: uses serial_hds and nd_table */
+    dc->user_creatable = false;
+}
+
+static const TypeInfo aw_h3_type_info = {
+    .name = TYPE_AW_H3,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(AwH3State),
+    .instance_init = aw_h3_init,
+    .class_init = aw_h3_class_init,
+};
+
+static void aw_h3_register_types(void)
+{
+    type_register_static(&aw_h3_type_info);
+}
+
+type_init(aw_h3_register_types)
diff --git a/MAINTAINERS b/MAINTAINERS
index 740401bcbb..aae1a049b4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -480,6 +480,13 @@ F: hw/*/allwinner*
 F: include/hw/*/allwinner*
 F: hw/arm/cubieboard.c
 
+Allwinner-h3
+M: Niek Linnenbank <nieklinnenbank@gmail.com>
+L: qemu-arm@nongnu.org
+S: Maintained
+F: hw/*/allwinner-h3*
+F: include/hw/*/allwinner-h3*
+
 ARM PrimeCell and CMSDK devices
 M: Peter Maydell <peter.maydell@linaro.org>
 L: qemu-arm@nongnu.org
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index c6e7782580..ebf8d2325f 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -291,6 +291,14 @@ config ALLWINNER_A10
     select SERIAL
     select UNIMP
 
+config ALLWINNER_H3
+    bool
+    select ALLWINNER_A10_PIT
+    select SERIAL
+    select ARM_TIMER
+    select ARM_GIC
+    select UNIMP
+
 config RASPI
     bool
     select FRAMEBUFFER
diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index fe749f65fd..956e496052 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -34,6 +34,7 @@ obj-$(CONFIG_DIGIC) += digic.o
 obj-$(CONFIG_OMAP) += omap1.o omap2.o
 obj-$(CONFIG_STRONGARM) += strongarm.o
 obj-$(CONFIG_ALLWINNER_A10) += allwinner-a10.o cubieboard.o
+obj-$(CONFIG_ALLWINNER_H3) += allwinner-h3.o
 obj-$(CONFIG_RASPI) += bcm2835_peripherals.o bcm2836.o raspi.o
 obj-$(CONFIG_STM32F205_SOC) += stm32f205_soc.o
 obj-$(CONFIG_XLNX_ZYNQMP_ARM) += xlnx-zynqmp.o xlnx-zcu102.o
-- 
2.17.1



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

* [PATCH v2 02/10] hw: arm: add Xunlong Orange Pi PC machine
  2019-12-16 23:35 [PATCH v2 00/10] Add Allwinner H3 SoC and Orange Pi PC Machine Niek Linnenbank
  2019-12-16 23:35 ` [PATCH v2 01/10] hw: arm: add Allwinner H3 System-on-Chip Niek Linnenbank
@ 2019-12-16 23:35 ` Niek Linnenbank
  2019-12-17  7:31   ` Philippe Mathieu-Daudé
  2019-12-16 23:35 ` [PATCH v2 03/10] arm: allwinner-h3: add Clock Control Unit Niek Linnenbank
                   ` (8 subsequent siblings)
  10 siblings, 1 reply; 30+ messages in thread
From: Niek Linnenbank @ 2019-12-16 23:35 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, Niek Linnenbank, qemu-arm, philmd

The Xunlong Orange Pi PC is an Allwinner H3 System on Chip
based embedded computer with mainline support in both U-Boot
and Linux. The board comes with a Quad Core Cortex A7 @ 1.3GHz,
512MB RAM, 100Mbit ethernet, USB, SD/MMC, USB, HDMI and
various other I/O. This commit add support for the Xunlong
Orange Pi PC machine.

Signed-off-by: Niek Linnenbank <nieklinnenbank@gmail.com>
Tested-by: KONRAD Frederic <frederic.konrad@adacore.com>
---
 hw/arm/orangepi.c    | 101 +++++++++++++++++++++++++++++++++++++++++++
 MAINTAINERS          |   1 +
 hw/arm/Makefile.objs |   2 +-
 3 files changed, 103 insertions(+), 1 deletion(-)
 create mode 100644 hw/arm/orangepi.c

diff --git a/hw/arm/orangepi.c b/hw/arm/orangepi.c
new file mode 100644
index 0000000000..62cefc8c06
--- /dev/null
+++ b/hw/arm/orangepi.c
@@ -0,0 +1,101 @@
+/*
+ * Orange Pi emulation
+ *
+ * Copyright (C) 2019 Niek Linnenbank <nieklinnenbank@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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 "exec/address-spaces.h"
+#include "qapi/error.h"
+#include "cpu.h"
+#include "hw/sysbus.h"
+#include "hw/boards.h"
+#include "hw/qdev-properties.h"
+#include "hw/arm/allwinner-h3.h"
+
+static struct arm_boot_info orangepi_binfo = {
+    .board_id = -1,
+};
+
+typedef struct OrangePiState {
+    AwH3State *h3;
+    MemoryRegion sdram;
+} OrangePiState;
+
+static void orangepi_init(MachineState *machine)
+{
+    OrangePiState *s = g_new(OrangePiState, 1);
+
+    /* Only allow Cortex-A7 for this board */
+    if (strcmp(machine->cpu_type, ARM_CPU_TYPE_NAME("cortex-a7")) != 0) {
+        error_report("This board can only be used with cortex-a7 CPU");
+        exit(1);
+    }
+
+    s->h3 = AW_H3(object_new(TYPE_AW_H3));
+
+    /* Setup timer properties */
+    object_property_set_int(OBJECT(&s->h3->timer), 32768, "clk0-freq",
+                            &error_abort);
+    if (error_abort != NULL) {
+        error_reportf_err(error_abort, "Couldn't set clk0 frequency: ");
+        exit(1);
+    }
+
+    object_property_set_int(OBJECT(&s->h3->timer), 24000000, "clk1-freq",
+                            &error_abort);
+    if (error_abort != NULL) {
+        error_reportf_err(error_abort, "Couldn't set clk1 frequency: ");
+        exit(1);
+    }
+
+    /* Mark H3 object realized */
+    object_property_set_bool(OBJECT(s->h3), true, "realized", &error_abort);
+    if (error_abort != NULL) {
+        error_reportf_err(error_abort, "Couldn't realize Allwinner H3: ");
+        exit(1);
+    }
+
+    /* RAM */
+    if (machine->ram_size > 1 * GiB) {
+        error_report("Requested ram size is too large for this machine: "
+                     "maximum is 1GB");
+        exit(1);
+    }
+    memory_region_allocate_system_memory(&s->sdram, NULL, "orangepi.ram",
+                                         machine->ram_size);
+    memory_region_add_subregion(get_system_memory(), s->h3->memmap[AW_H3_SDRAM],
+                                &s->sdram);
+
+    /* Load target kernel */
+    orangepi_binfo.loader_start = s->h3->memmap[AW_H3_SDRAM];
+    orangepi_binfo.ram_size = machine->ram_size;
+    orangepi_binfo.nb_cpus  = AW_H3_NUM_CPUS;
+    arm_load_kernel(ARM_CPU(first_cpu), machine, &orangepi_binfo);
+}
+
+static void orangepi_machine_init(MachineClass *mc)
+{
+    mc->desc = "Orange Pi PC";
+    mc->init = orangepi_init;
+    mc->units_per_default_bus = 1;
+    mc->min_cpus = AW_H3_NUM_CPUS;
+    mc->max_cpus = AW_H3_NUM_CPUS;
+    mc->default_cpus = AW_H3_NUM_CPUS;
+    mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a7");
+}
+
+DEFINE_MACHINE("orangepi-pc", orangepi_machine_init)
diff --git a/MAINTAINERS b/MAINTAINERS
index aae1a049b4..db682e49ca 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -486,6 +486,7 @@ L: qemu-arm@nongnu.org
 S: Maintained
 F: hw/*/allwinner-h3*
 F: include/hw/*/allwinner-h3*
+F: hw/arm/orangepi.c
 
 ARM PrimeCell and CMSDK devices
 M: Peter Maydell <peter.maydell@linaro.org>
diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index 956e496052..8d5ea453d5 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -34,7 +34,7 @@ obj-$(CONFIG_DIGIC) += digic.o
 obj-$(CONFIG_OMAP) += omap1.o omap2.o
 obj-$(CONFIG_STRONGARM) += strongarm.o
 obj-$(CONFIG_ALLWINNER_A10) += allwinner-a10.o cubieboard.o
-obj-$(CONFIG_ALLWINNER_H3) += allwinner-h3.o
+obj-$(CONFIG_ALLWINNER_H3) += allwinner-h3.o orangepi.o
 obj-$(CONFIG_RASPI) += bcm2835_peripherals.o bcm2836.o raspi.o
 obj-$(CONFIG_STM32F205_SOC) += stm32f205_soc.o
 obj-$(CONFIG_XLNX_ZYNQMP_ARM) += xlnx-zynqmp.o xlnx-zcu102.o
-- 
2.17.1



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

* [PATCH v2 03/10] arm: allwinner-h3: add Clock Control Unit
  2019-12-16 23:35 [PATCH v2 00/10] Add Allwinner H3 SoC and Orange Pi PC Machine Niek Linnenbank
  2019-12-16 23:35 ` [PATCH v2 01/10] hw: arm: add Allwinner H3 System-on-Chip Niek Linnenbank
  2019-12-16 23:35 ` [PATCH v2 02/10] hw: arm: add Xunlong Orange Pi PC machine Niek Linnenbank
@ 2019-12-16 23:35 ` Niek Linnenbank
  2019-12-16 23:35 ` [PATCH v2 04/10] arm: allwinner-h3: add USB host controller Niek Linnenbank
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 30+ messages in thread
From: Niek Linnenbank @ 2019-12-16 23:35 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, Niek Linnenbank, qemu-arm, philmd

The Clock Control Unit is responsible for clock signal generation,
configuration and distribution in the Allwinner H3 System on Chip.
This commit adds support for the Clock Control Unit which emulates
a simple read/write register interface.

Signed-off-by: Niek Linnenbank <nieklinnenbank@gmail.com>
---
 include/hw/arm/allwinner-h3.h      |   2 +
 include/hw/misc/allwinner-h3-clk.h |  40 +++++
 hw/arm/allwinner-h3.c              |   7 +
 hw/misc/allwinner-h3-clk.c         | 238 +++++++++++++++++++++++++++++
 hw/misc/Makefile.objs              |   1 +
 5 files changed, 288 insertions(+)
 create mode 100644 include/hw/misc/allwinner-h3-clk.h
 create mode 100644 hw/misc/allwinner-h3-clk.c

diff --git a/include/hw/arm/allwinner-h3.h b/include/hw/arm/allwinner-h3.h
index e50caeffaa..47d6f82cc4 100644
--- a/include/hw/arm/allwinner-h3.h
+++ b/include/hw/arm/allwinner-h3.h
@@ -26,6 +26,7 @@
 #include "hw/arm/boot.h"
 #include "hw/timer/allwinner-a10-pit.h"
 #include "hw/intc/arm_gic.h"
+#include "hw/misc/allwinner-h3-clk.h"
 #include "target/arm/cpu.h"
 
 enum {
@@ -71,6 +72,7 @@ typedef struct AwH3State {
     ARMCPU cpus[AW_H3_NUM_CPUS];
     const hwaddr *memmap;
     AwA10PITState timer;
+    AwH3ClockState ccu;
     GICState gic;
     MemoryRegion sram_a1;
     MemoryRegion sram_a2;
diff --git a/include/hw/misc/allwinner-h3-clk.h b/include/hw/misc/allwinner-h3-clk.h
new file mode 100644
index 0000000000..ce058a900b
--- /dev/null
+++ b/include/hw/misc/allwinner-h3-clk.h
@@ -0,0 +1,40 @@
+/*
+ * Allwinner H3 Clock Control Unit emulation
+ *
+ * Copyright (C) 2019 Niek Linnenbank <nieklinnenbank@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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_MISC_ALLWINNER_H3_CLK_H
+#define HW_MISC_ALLWINNER_H3_CLK_H
+
+#include "hw/sysbus.h"
+
+#define AW_H3_CLK_REGS_MAX_ADDR (0x304)
+#define AW_H3_CLK_REGS_NUM      (AW_H3_CLK_REGS_MAX_ADDR / sizeof(uint32_t))
+
+#define TYPE_AW_H3_CLK    "allwinner-h3-clk"
+#define AW_H3_CLK(obj)    OBJECT_CHECK(AwH3ClockState, (obj), TYPE_AW_H3_CLK)
+
+typedef struct AwH3ClockState {
+    /*< private >*/
+    SysBusDevice parent_obj;
+    /*< public >*/
+
+    MemoryRegion iomem;
+    uint32_t regs[AW_H3_CLK_REGS_NUM];
+} AwH3ClockState;
+
+#endif
diff --git a/hw/arm/allwinner-h3.c b/hw/arm/allwinner-h3.c
index 1a47de56f5..0da09188d1 100644
--- a/hw/arm/allwinner-h3.c
+++ b/hw/arm/allwinner-h3.c
@@ -186,6 +186,9 @@ static void aw_h3_init(Object *obj)
 
     sysbus_init_child_obj(obj, "timer", &s->timer, sizeof(s->timer),
                           TYPE_AW_A10_PIT);
+
+    sysbus_init_child_obj(obj, "ccu", &s->ccu, sizeof(s->ccu),
+                          TYPE_AW_H3_CLK);
 }
 
 static void aw_h3_realize(DeviceState *dev, Error **errp)
@@ -310,6 +313,10 @@ static void aw_h3_realize(DeviceState *dev, Error **errp)
     memory_region_add_subregion(get_system_memory(), s->memmap[AW_H3_SRAM_C],
                                 &s->sram_c);
 
+    /* Clock Control Unit */
+    qdev_init_nofail(DEVICE(&s->ccu));
+    sysbus_mmio_map(SYS_BUS_DEVICE(&s->ccu), 0, s->memmap[AW_H3_CCU]);
+
     /* UART0 */
     serial_mm_init(get_system_memory(), s->memmap[AW_H3_UART0], 2,
                    qdev_get_gpio_in(DEVICE(&s->gic), AW_H3_GIC_SPI_UART0),
diff --git a/hw/misc/allwinner-h3-clk.c b/hw/misc/allwinner-h3-clk.c
new file mode 100644
index 0000000000..4758cd4d7e
--- /dev/null
+++ b/hw/misc/allwinner-h3-clk.c
@@ -0,0 +1,238 @@
+/*
+ * Allwinner H3 Clock Control Unit emulation
+ *
+ * Copyright (C) 2019 Niek Linnenbank <nieklinnenbank@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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/units.h"
+#include "hw/sysbus.h"
+#include "migration/vmstate.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "hw/misc/allwinner-h3-clk.h"
+
+/* CCU register offsets */
+enum {
+    REG_PLL_CPUX             = 0x0000, /* PLL CPUX Control */
+    REG_PLL_AUDIO            = 0x0008, /* PLL Audio Control */
+    REG_PLL_VIDEO            = 0x0010, /* PLL Video Control */
+    REG_PLL_VE               = 0x0018, /* PLL VE Control */
+    REG_PLL_DDR              = 0x0020, /* PLL DDR Control */
+    REG_PLL_PERIPH0          = 0x0028, /* PLL Peripherals 0 Control */
+    REG_PLL_GPU              = 0x0038, /* PLL GPU Control */
+    REG_PLL_PERIPH1          = 0x0044, /* PLL Peripherals 1 Control */
+    REG_PLL_DE               = 0x0048, /* PLL Display Engine Control */
+    REG_CPUX_AXI             = 0x0050, /* CPUX/AXI Configuration */
+    REG_APB1                 = 0x0054, /* ARM Peripheral Bus 1 Config */
+    REG_APB2                 = 0x0058, /* ARM Peripheral Bus 2 Config */
+    REG_MBUS                 = 0x00FC, /* MBUS Reset */
+    REG_PLL_TIME0            = 0x0200, /* PLL Stable Time 0 */
+    REG_PLL_TIME1            = 0x0204, /* PLL Stable Time 1 */
+    REG_PLL_CPUX_BIAS        = 0x0220, /* PLL CPUX Bias */
+    REG_PLL_AUDIO_BIAS       = 0x0224, /* PLL Audio Bias */
+    REG_PLL_VIDEO_BIAS       = 0x0228, /* PLL Video Bias */
+    REG_PLL_VE_BIAS          = 0x022C, /* PLL VE Bias */
+    REG_PLL_DDR_BIAS         = 0x0230, /* PLL DDR Bias */
+    REG_PLL_PERIPH0_BIAS     = 0x0234, /* PLL Peripherals 0 Bias */
+    REG_PLL_GPU_BIAS         = 0x023C, /* PLL GPU Bias */
+    REG_PLL_PERIPH1_BIAS     = 0x0244, /* PLL Peripherals 1 Bias */
+    REG_PLL_DE_BIAS          = 0x0248, /* PLL Display Engine Bias */
+    REG_PLL_CPUX_TUNING      = 0x0250, /* PLL CPUX Tuning */
+    REG_PLL_DDR_TUNING       = 0x0260, /* PLL DDR Tuning */
+};
+
+#define REG_INDEX(offset)    (offset / sizeof(uint32_t))
+
+/* CCU register flags */
+enum {
+    REG_PLL_ENABLE           = (1 << 31),
+    REG_PLL_LOCK             = (1 << 28),
+};
+
+/* CCU register reset values */
+enum {
+    REG_PLL_CPUX_RST         = 0x00001000,
+    REG_PLL_AUDIO_RST        = 0x00035514,
+    REG_PLL_VIDEO_RST        = 0x03006207,
+    REG_PLL_VE_RST           = 0x03006207,
+    REG_PLL_DDR_RST          = 0x00001000,
+    REG_PLL_PERIPH0_RST      = 0x00041811,
+    REG_PLL_GPU_RST          = 0x03006207,
+    REG_PLL_PERIPH1_RST      = 0x00041811,
+    REG_PLL_DE_RST           = 0x03006207,
+    REG_CPUX_AXI_RST         = 0x00010000,
+    REG_APB1_RST             = 0x00001010,
+    REG_APB2_RST             = 0x01000000,
+    REG_MBUS_RST             = 0x80000000,
+    REG_PLL_TIME0_RST        = 0x000000FF,
+    REG_PLL_TIME1_RST        = 0x000000FF,
+    REG_PLL_CPUX_BIAS_RST    = 0x08100200,
+    REG_PLL_AUDIO_BIAS_RST   = 0x10100000,
+    REG_PLL_VIDEO_BIAS_RST   = 0x10100000,
+    REG_PLL_VE_BIAS_RST      = 0x10100000,
+    REG_PLL_DDR_BIAS_RST     = 0x81104000,
+    REG_PLL_PERIPH0_BIAS_RST = 0x10100010,
+    REG_PLL_GPU_BIAS_RST     = 0x10100000,
+    REG_PLL_PERIPH1_BIAS_RST = 0x10100010,
+    REG_PLL_DE_BIAS_RST      = 0x10100000,
+    REG_PLL_CPUX_TUNING_RST  = 0x0A101000,
+    REG_PLL_DDR_TUNING_RST   = 0x14880000,
+};
+
+static uint64_t allwinner_h3_clk_read(void *opaque, hwaddr offset,
+                                      unsigned size)
+{
+    const AwH3ClockState *s = (AwH3ClockState *)opaque;
+    const uint32_t idx = REG_INDEX(offset);
+
+    if (idx >= AW_H3_CLK_REGS_NUM) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: bad read offset 0x%04x\n",
+                      __func__, (uint32_t)offset);
+        return 0;
+    }
+
+    return s->regs[idx];
+}
+
+static void allwinner_h3_clk_write(void *opaque, hwaddr offset,
+                                   uint64_t val, unsigned size)
+{
+    AwH3ClockState *s = (AwH3ClockState *)opaque;
+    const uint32_t idx = REG_INDEX(offset);
+
+    if (idx >= AW_H3_CLK_REGS_NUM) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write offset 0x%04x\n",
+                      __func__, (uint32_t)offset);
+        return;
+    }
+
+    switch (offset) {
+    case REG_PLL_CPUX:    /* PLL CPUX Control */
+    case REG_PLL_AUDIO:   /* PLL Audio Control */
+    case REG_PLL_VIDEO:   /* PLL Video Control */
+    case REG_PLL_VE:      /* PLL VE Control */
+    case REG_PLL_DDR:     /* PLL DDR Control */
+    case REG_PLL_PERIPH0: /* PLL Peripherals 0 Control */
+    case REG_PLL_GPU:     /* PLL GPU Control */
+    case REG_PLL_PERIPH1: /* PLL Peripherals 1 Control */
+    case REG_PLL_DE:      /* PLL Display Engine Control */
+        if (val & REG_PLL_ENABLE) {
+            val |= REG_PLL_LOCK;
+        }
+        break;
+    default:
+        qemu_log_mask(LOG_UNIMP, "%s: unimplemented write offset 0x%04x\n",
+                      __func__, (uint32_t)offset);
+        break;
+    }
+
+    s->regs[idx] = (uint32_t) val;
+}
+
+static const MemoryRegionOps allwinner_h3_clk_ops = {
+    .read = allwinner_h3_clk_read,
+    .write = allwinner_h3_clk_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+        .unaligned = false
+    },
+    .impl.min_access_size = 4,
+};
+
+static void allwinner_h3_clk_reset(DeviceState *dev)
+{
+    AwH3ClockState *s = AW_H3_CLK(dev);
+
+    /* Set default values for registers */
+    s->regs[REG_INDEX(REG_PLL_CPUX)] = REG_PLL_CPUX_RST;
+    s->regs[REG_INDEX(REG_PLL_AUDIO)] = REG_PLL_AUDIO_RST;
+    s->regs[REG_INDEX(REG_PLL_VIDEO)] = REG_PLL_VIDEO_RST;
+    s->regs[REG_INDEX(REG_PLL_VE)] = REG_PLL_VE_RST;
+    s->regs[REG_INDEX(REG_PLL_DDR)] = REG_PLL_DDR_RST;
+    s->regs[REG_INDEX(REG_PLL_PERIPH0)] = REG_PLL_PERIPH0_RST;
+    s->regs[REG_INDEX(REG_PLL_GPU)] = REG_PLL_GPU_RST;
+    s->regs[REG_INDEX(REG_PLL_PERIPH1)] = REG_PLL_PERIPH1_RST;
+    s->regs[REG_INDEX(REG_PLL_DE)] = REG_PLL_DE_RST;
+    s->regs[REG_INDEX(REG_CPUX_AXI)] = REG_CPUX_AXI_RST;
+    s->regs[REG_INDEX(REG_APB1)] = REG_APB1_RST;
+    s->regs[REG_INDEX(REG_APB2)] = REG_APB2_RST;
+    s->regs[REG_INDEX(REG_MBUS)] = REG_MBUS_RST;
+    s->regs[REG_INDEX(REG_PLL_TIME0)] = REG_PLL_TIME0_RST;
+    s->regs[REG_INDEX(REG_PLL_TIME1)] = REG_PLL_TIME1_RST;
+    s->regs[REG_INDEX(REG_PLL_CPUX_BIAS)] = REG_PLL_CPUX_BIAS_RST;
+    s->regs[REG_INDEX(REG_PLL_AUDIO_BIAS)] = REG_PLL_AUDIO_BIAS_RST;
+    s->regs[REG_INDEX(REG_PLL_VIDEO_BIAS)] = REG_PLL_VIDEO_BIAS_RST;
+    s->regs[REG_INDEX(REG_PLL_VE_BIAS)] = REG_PLL_VE_BIAS_RST;
+    s->regs[REG_INDEX(REG_PLL_DDR_BIAS)] = REG_PLL_DDR_BIAS_RST;
+    s->regs[REG_INDEX(REG_PLL_PERIPH0_BIAS)] = REG_PLL_PERIPH0_BIAS_RST;
+    s->regs[REG_INDEX(REG_PLL_GPU_BIAS)] = REG_PLL_GPU_BIAS_RST;
+    s->regs[REG_INDEX(REG_PLL_PERIPH1_BIAS)] = REG_PLL_PERIPH1_BIAS_RST;
+    s->regs[REG_INDEX(REG_PLL_DE_BIAS)] = REG_PLL_DE_BIAS_RST;
+    s->regs[REG_INDEX(REG_PLL_CPUX_TUNING)] = REG_PLL_CPUX_TUNING_RST;
+    s->regs[REG_INDEX(REG_PLL_DDR_TUNING)] = REG_PLL_DDR_TUNING_RST;
+}
+
+static void allwinner_h3_clk_realize(DeviceState *dev, Error **errp)
+{
+}
+
+static void allwinner_h3_clk_init(Object *obj)
+{
+    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+    AwH3ClockState *s = AW_H3_CLK(obj);
+
+    /* Memory mapping */
+    memory_region_init_io(&s->iomem, OBJECT(s), &allwinner_h3_clk_ops, s,
+                          TYPE_AW_H3_CLK, 1 * KiB);
+    sysbus_init_mmio(sbd, &s->iomem);
+}
+
+static const VMStateDescription allwinner_h3_clk_vmstate = {
+    .name = "allwinner-h3-clk",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, AwH3ClockState, AW_H3_CLK_REGS_NUM),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void allwinner_h3_clk_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->reset = allwinner_h3_clk_reset;
+    dc->realize = allwinner_h3_clk_realize;
+    dc->vmsd = &allwinner_h3_clk_vmstate;
+}
+
+static const TypeInfo allwinner_h3_clk_info = {
+    .name          = TYPE_AW_H3_CLK,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_init = allwinner_h3_clk_init,
+    .instance_size = sizeof(AwH3ClockState),
+    .class_init    = allwinner_h3_clk_class_init,
+};
+
+static void allwinner_h3_clk_register(void)
+{
+    type_register_static(&allwinner_h3_clk_info);
+}
+
+type_init(allwinner_h3_clk_register)
diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
index ba898a5781..200ed44ce1 100644
--- a/hw/misc/Makefile.objs
+++ b/hw/misc/Makefile.objs
@@ -28,6 +28,7 @@ common-obj-$(CONFIG_MACIO) += macio/
 
 common-obj-$(CONFIG_IVSHMEM_DEVICE) += ivshmem.o
 
+common-obj-$(CONFIG_ALLWINNER_H3) += allwinner-h3-clk.o
 common-obj-$(CONFIG_REALVIEW) += arm_sysctl.o
 common-obj-$(CONFIG_NSERIES) += cbus.o
 common-obj-$(CONFIG_ECCMEMCTL) += eccmemctl.o
-- 
2.17.1



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

* [PATCH v2 04/10] arm: allwinner-h3: add USB host controller
  2019-12-16 23:35 [PATCH v2 00/10] Add Allwinner H3 SoC and Orange Pi PC Machine Niek Linnenbank
                   ` (2 preceding siblings ...)
  2019-12-16 23:35 ` [PATCH v2 03/10] arm: allwinner-h3: add Clock Control Unit Niek Linnenbank
@ 2019-12-16 23:35 ` Niek Linnenbank
  2019-12-16 23:35 ` [PATCH v2 05/10] arm: allwinner-h3: add System Control module Niek Linnenbank
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 30+ messages in thread
From: Niek Linnenbank @ 2019-12-16 23:35 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, Niek Linnenbank, qemu-arm, philmd

The Allwinner H3 System on Chip contains multiple USB 2.0 bus
connections which provide software access using the Enhanced
Host Controller Interface (EHCI) and Open Host Controller
Interface (OHCI) interfaces. This commit adds support for
both interfaces in the Allwinner H3 System on Chip.

Signed-off-by: Niek Linnenbank <nieklinnenbank@gmail.com>
Reviewed-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/usb/hcd-ehci.h        |  1 +
 hw/arm/allwinner-h3.c    | 28 ++++++++++++++++++++++++++++
 hw/usb/hcd-ehci-sysbus.c | 17 +++++++++++++++++
 3 files changed, 46 insertions(+)

diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h
index 0298238f0b..edb59311c4 100644
--- a/hw/usb/hcd-ehci.h
+++ b/hw/usb/hcd-ehci.h
@@ -342,6 +342,7 @@ typedef struct EHCIPCIState {
 #define TYPE_SYS_BUS_EHCI "sysbus-ehci-usb"
 #define TYPE_PLATFORM_EHCI "platform-ehci-usb"
 #define TYPE_EXYNOS4210_EHCI "exynos4210-ehci-usb"
+#define TYPE_AW_H3_EHCI "aw-h3-ehci-usb"
 #define TYPE_TEGRA2_EHCI "tegra2-ehci-usb"
 #define TYPE_PPC4xx_EHCI "ppc4xx-ehci-usb"
 #define TYPE_FUSBH200_EHCI "fusbh200-ehci-usb"
diff --git a/hw/arm/allwinner-h3.c b/hw/arm/allwinner-h3.c
index 0da09188d1..f0ea088852 100644
--- a/hw/arm/allwinner-h3.c
+++ b/hw/arm/allwinner-h3.c
@@ -26,6 +26,7 @@
 #include "hw/sysbus.h"
 #include "hw/arm/allwinner-h3.h"
 #include "hw/misc/unimp.h"
+#include "hw/usb/hcd-ehci.h"
 #include "sysemu/sysemu.h"
 
 /* Memory map */
@@ -317,6 +318,33 @@ static void aw_h3_realize(DeviceState *dev, Error **errp)
     qdev_init_nofail(DEVICE(&s->ccu));
     sysbus_mmio_map(SYS_BUS_DEVICE(&s->ccu), 0, s->memmap[AW_H3_CCU]);
 
+    /* Universal Serial Bus */
+    sysbus_create_simple(TYPE_AW_H3_EHCI, s->memmap[AW_H3_EHCI0],
+                         qdev_get_gpio_in(DEVICE(&s->gic),
+                                          AW_H3_GIC_SPI_EHCI0));
+    sysbus_create_simple(TYPE_AW_H3_EHCI, s->memmap[AW_H3_EHCI1],
+                         qdev_get_gpio_in(DEVICE(&s->gic),
+                                          AW_H3_GIC_SPI_EHCI1));
+    sysbus_create_simple(TYPE_AW_H3_EHCI, s->memmap[AW_H3_EHCI2],
+                         qdev_get_gpio_in(DEVICE(&s->gic),
+                                          AW_H3_GIC_SPI_EHCI2));
+    sysbus_create_simple(TYPE_AW_H3_EHCI, s->memmap[AW_H3_EHCI3],
+                         qdev_get_gpio_in(DEVICE(&s->gic),
+                                          AW_H3_GIC_SPI_EHCI3));
+
+    sysbus_create_simple("sysbus-ohci", s->memmap[AW_H3_OHCI0],
+                         qdev_get_gpio_in(DEVICE(&s->gic),
+                                          AW_H3_GIC_SPI_OHCI0));
+    sysbus_create_simple("sysbus-ohci", s->memmap[AW_H3_OHCI1],
+                         qdev_get_gpio_in(DEVICE(&s->gic),
+                                          AW_H3_GIC_SPI_OHCI1));
+    sysbus_create_simple("sysbus-ohci", s->memmap[AW_H3_OHCI2],
+                         qdev_get_gpio_in(DEVICE(&s->gic),
+                                          AW_H3_GIC_SPI_OHCI2));
+    sysbus_create_simple("sysbus-ohci", s->memmap[AW_H3_OHCI3],
+                         qdev_get_gpio_in(DEVICE(&s->gic),
+                                          AW_H3_GIC_SPI_OHCI3));
+
     /* UART0 */
     serial_mm_init(get_system_memory(), s->memmap[AW_H3_UART0], 2,
                    qdev_get_gpio_in(DEVICE(&s->gic), AW_H3_GIC_SPI_UART0),
diff --git a/hw/usb/hcd-ehci-sysbus.c b/hw/usb/hcd-ehci-sysbus.c
index 020211fd10..174c3446ef 100644
--- a/hw/usb/hcd-ehci-sysbus.c
+++ b/hw/usb/hcd-ehci-sysbus.c
@@ -145,6 +145,22 @@ static const TypeInfo ehci_exynos4210_type_info = {
     .class_init    = ehci_exynos4210_class_init,
 };
 
+static void ehci_aw_h3_class_init(ObjectClass *oc, void *data)
+{
+    SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
+    DeviceClass *dc = DEVICE_CLASS(oc);
+
+    sec->capsbase = 0x0;
+    sec->opregbase = 0x10;
+    set_bit(DEVICE_CATEGORY_USB, dc->categories);
+}
+
+static const TypeInfo ehci_aw_h3_type_info = {
+    .name          = TYPE_AW_H3_EHCI,
+    .parent        = TYPE_SYS_BUS_EHCI,
+    .class_init    = ehci_aw_h3_class_init,
+};
+
 static void ehci_tegra2_class_init(ObjectClass *oc, void *data)
 {
     SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
@@ -267,6 +283,7 @@ static void ehci_sysbus_register_types(void)
     type_register_static(&ehci_platform_type_info);
     type_register_static(&ehci_xlnx_type_info);
     type_register_static(&ehci_exynos4210_type_info);
+    type_register_static(&ehci_aw_h3_type_info);
     type_register_static(&ehci_tegra2_type_info);
     type_register_static(&ehci_ppc4xx_type_info);
     type_register_static(&ehci_fusbh200_type_info);
-- 
2.17.1



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

* [PATCH v2 05/10] arm: allwinner-h3: add System Control module
  2019-12-16 23:35 [PATCH v2 00/10] Add Allwinner H3 SoC and Orange Pi PC Machine Niek Linnenbank
                   ` (3 preceding siblings ...)
  2019-12-16 23:35 ` [PATCH v2 04/10] arm: allwinner-h3: add USB host controller Niek Linnenbank
@ 2019-12-16 23:35 ` Niek Linnenbank
  2019-12-16 23:35 ` [PATCH v2 06/10] arm/arm-powerctl: rebuild hflags after setting CP15 bits in arm_set_cpu_on() Niek Linnenbank
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 30+ messages in thread
From: Niek Linnenbank @ 2019-12-16 23:35 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, Niek Linnenbank, qemu-arm, philmd

The Allwinner H3 System on Chip has an System Control
module that provides system wide generic controls and
device information. This commit adds support for the
Allwinner H3 System Control module.

Signed-off-by: Niek Linnenbank <nieklinnenbank@gmail.com>
---
 include/hw/arm/allwinner-h3.h         |   2 +
 include/hw/misc/allwinner-h3-syscon.h |  42 ++++++++
 hw/arm/allwinner-h3.c                 |   7 ++
 hw/misc/allwinner-h3-syscon.c         | 146 ++++++++++++++++++++++++++
 hw/misc/Makefile.objs                 |   1 +
 5 files changed, 198 insertions(+)
 create mode 100644 include/hw/misc/allwinner-h3-syscon.h
 create mode 100644 hw/misc/allwinner-h3-syscon.c

diff --git a/include/hw/arm/allwinner-h3.h b/include/hw/arm/allwinner-h3.h
index 47d6f82cc4..bead6d4f85 100644
--- a/include/hw/arm/allwinner-h3.h
+++ b/include/hw/arm/allwinner-h3.h
@@ -27,6 +27,7 @@
 #include "hw/timer/allwinner-a10-pit.h"
 #include "hw/intc/arm_gic.h"
 #include "hw/misc/allwinner-h3-clk.h"
+#include "hw/misc/allwinner-h3-syscon.h"
 #include "target/arm/cpu.h"
 
 enum {
@@ -73,6 +74,7 @@ typedef struct AwH3State {
     const hwaddr *memmap;
     AwA10PITState timer;
     AwH3ClockState ccu;
+    AwH3SysconState syscon;
     GICState gic;
     MemoryRegion sram_a1;
     MemoryRegion sram_a2;
diff --git a/include/hw/misc/allwinner-h3-syscon.h b/include/hw/misc/allwinner-h3-syscon.h
new file mode 100644
index 0000000000..830e1a5061
--- /dev/null
+++ b/include/hw/misc/allwinner-h3-syscon.h
@@ -0,0 +1,42 @@
+/*
+ * Allwinner H3 System Control emulation
+ *
+ * Copyright (C) 2019 Niek Linnenbank <nieklinnenbank@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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_MISC_ALLWINNER_H3_SYSCON_H
+#define HW_MISC_ALLWINNER_H3_SYSCON_H
+
+#include "hw/sysbus.h"
+
+#define AW_H3_SYSCON_REGS_MAX_ADDR  (0x30)
+#define AW_H3_SYSCON_REGS_NUM       ((AW_H3_SYSCON_REGS_MAX_ADDR / \
+                                      sizeof(uint32_t)) + 1)
+
+#define TYPE_AW_H3_SYSCON    "allwinner-h3-syscon"
+#define AW_H3_SYSCON(obj)    OBJECT_CHECK(AwH3SysconState, (obj), \
+                                          TYPE_AW_H3_SYSCON)
+
+typedef struct AwH3SysconState {
+    /*< private >*/
+    SysBusDevice parent_obj;
+    /*< public >*/
+
+    MemoryRegion iomem;
+    uint32_t regs[AW_H3_SYSCON_REGS_NUM];
+} AwH3SysconState;
+
+#endif
diff --git a/hw/arm/allwinner-h3.c b/hw/arm/allwinner-h3.c
index f0ea088852..8482d616e7 100644
--- a/hw/arm/allwinner-h3.c
+++ b/hw/arm/allwinner-h3.c
@@ -190,6 +190,9 @@ static void aw_h3_init(Object *obj)
 
     sysbus_init_child_obj(obj, "ccu", &s->ccu, sizeof(s->ccu),
                           TYPE_AW_H3_CLK);
+
+    sysbus_init_child_obj(obj, "syscon", &s->syscon, sizeof(s->syscon),
+                          TYPE_AW_H3_SYSCON);
 }
 
 static void aw_h3_realize(DeviceState *dev, Error **errp)
@@ -318,6 +321,10 @@ static void aw_h3_realize(DeviceState *dev, Error **errp)
     qdev_init_nofail(DEVICE(&s->ccu));
     sysbus_mmio_map(SYS_BUS_DEVICE(&s->ccu), 0, s->memmap[AW_H3_CCU]);
 
+    /* System Control */
+    qdev_init_nofail(DEVICE(&s->syscon));
+    sysbus_mmio_map(SYS_BUS_DEVICE(&s->syscon), 0, s->memmap[AW_H3_SYSCON]);
+
     /* Universal Serial Bus */
     sysbus_create_simple(TYPE_AW_H3_EHCI, s->memmap[AW_H3_EHCI0],
                          qdev_get_gpio_in(DEVICE(&s->gic),
diff --git a/hw/misc/allwinner-h3-syscon.c b/hw/misc/allwinner-h3-syscon.c
new file mode 100644
index 0000000000..9c5d42dd49
--- /dev/null
+++ b/hw/misc/allwinner-h3-syscon.c
@@ -0,0 +1,146 @@
+/*
+ * Allwinner H3 System Control emulation
+ *
+ * Copyright (C) 2019 Niek Linnenbank <nieklinnenbank@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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/units.h"
+#include "hw/sysbus.h"
+#include "migration/vmstate.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "hw/misc/allwinner-h3-syscon.h"
+
+/* SYSCON register offsets */
+enum {
+    REG_VER               = 0x24,  /* Version */
+    REG_EMAC_PHY_CLK      = 0x30,  /* EMAC PHY Clock */
+};
+
+#define REG_INDEX(offset)   (offset / sizeof(uint32_t))
+
+/* SYSCON register reset values */
+enum {
+    REG_VER_RST           = 0x0,
+    REG_EMAC_PHY_CLK_RST  = 0x58000,
+};
+
+static uint64_t allwinner_h3_syscon_read(void *opaque, hwaddr offset,
+                                         unsigned size)
+{
+    const AwH3SysconState *s = (AwH3SysconState *)opaque;
+    const uint32_t idx = REG_INDEX(offset);
+
+    if (idx >= AW_H3_SYSCON_REGS_NUM) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: bad read offset 0x%04x\n",
+                      __func__, (uint32_t)offset);
+        return 0;
+    }
+
+    return s->regs[idx];
+}
+
+static void allwinner_h3_syscon_write(void *opaque, hwaddr offset,
+                                      uint64_t val, unsigned size)
+{
+    AwH3SysconState *s = (AwH3SysconState *)opaque;
+    const uint32_t idx = REG_INDEX(offset);
+
+    if (idx >= AW_H3_SYSCON_REGS_NUM) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write offset 0x%04x\n",
+                      __func__, (uint32_t)offset);
+        return;
+    }
+
+    switch (offset) {
+    case REG_VER:       /* Version */
+        break;
+    default:
+        s->regs[idx] = (uint32_t) val;
+        break;
+    }
+}
+
+static const MemoryRegionOps allwinner_h3_syscon_ops = {
+    .read = allwinner_h3_syscon_read,
+    .write = allwinner_h3_syscon_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+        .unaligned = false
+    },
+    .impl.min_access_size = 4,
+};
+
+static void allwinner_h3_syscon_reset(DeviceState *dev)
+{
+    AwH3SysconState *s = AW_H3_SYSCON(dev);
+
+    /* Set default values for registers */
+    s->regs[REG_INDEX(REG_VER)] = REG_VER_RST;
+    s->regs[REG_INDEX(REG_EMAC_PHY_CLK)] = REG_EMAC_PHY_CLK_RST;
+}
+
+static void allwinner_h3_syscon_realize(DeviceState *dev, Error **errp)
+{
+}
+
+static void allwinner_h3_syscon_init(Object *obj)
+{
+    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+    AwH3SysconState *s = AW_H3_SYSCON(obj);
+
+    /* Memory mapping */
+    memory_region_init_io(&s->iomem, OBJECT(s), &allwinner_h3_syscon_ops, s,
+                          TYPE_AW_H3_SYSCON, 4 * KiB);
+    sysbus_init_mmio(sbd, &s->iomem);
+}
+
+static const VMStateDescription allwinner_h3_syscon_vmstate = {
+    .name = "allwinner-h3-syscon",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, AwH3SysconState, AW_H3_SYSCON_REGS_NUM),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void allwinner_h3_syscon_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->reset = allwinner_h3_syscon_reset;
+    dc->realize = allwinner_h3_syscon_realize;
+    dc->vmsd = &allwinner_h3_syscon_vmstate;
+}
+
+static const TypeInfo allwinner_h3_syscon_info = {
+    .name          = TYPE_AW_H3_SYSCON,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_init = allwinner_h3_syscon_init,
+    .instance_size = sizeof(AwH3SysconState),
+    .class_init    = allwinner_h3_syscon_class_init,
+};
+
+static void allwinner_h3_syscon_register(void)
+{
+    type_register_static(&allwinner_h3_syscon_info);
+}
+
+type_init(allwinner_h3_syscon_register)
diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
index 200ed44ce1..b234aefba5 100644
--- a/hw/misc/Makefile.objs
+++ b/hw/misc/Makefile.objs
@@ -29,6 +29,7 @@ common-obj-$(CONFIG_MACIO) += macio/
 common-obj-$(CONFIG_IVSHMEM_DEVICE) += ivshmem.o
 
 common-obj-$(CONFIG_ALLWINNER_H3) += allwinner-h3-clk.o
+common-obj-$(CONFIG_ALLWINNER_H3) += allwinner-h3-syscon.o
 common-obj-$(CONFIG_REALVIEW) += arm_sysctl.o
 common-obj-$(CONFIG_NSERIES) += cbus.o
 common-obj-$(CONFIG_ECCMEMCTL) += eccmemctl.o
-- 
2.17.1



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

* [PATCH v2 06/10] arm/arm-powerctl: rebuild hflags after setting CP15 bits in arm_set_cpu_on()
  2019-12-16 23:35 [PATCH v2 00/10] Add Allwinner H3 SoC and Orange Pi PC Machine Niek Linnenbank
                   ` (4 preceding siblings ...)
  2019-12-16 23:35 ` [PATCH v2 05/10] arm: allwinner-h3: add System Control module Niek Linnenbank
@ 2019-12-16 23:35 ` Niek Linnenbank
  2019-12-16 23:44   ` Niek Linnenbank
  2019-12-16 23:35 ` [PATCH v2 07/10] arm: allwinner-h3: add CPU Configuration module Niek Linnenbank
                   ` (4 subsequent siblings)
  10 siblings, 1 reply; 30+ messages in thread
From: Niek Linnenbank @ 2019-12-16 23:35 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, Niek Linnenbank, qemu-arm, philmd

After setting CP15 bits in arm_set_cpu_on() the cached hflags must
be rebuild to reflect the changed processor state. Without rebuilding,
the cached hflags would be inconsistent until the next call to
arm_rebuild_hflags(). When QEMU is compiled with debugging enabled
(--enable-debug), this problem is captured shortly after the first
call to arm_set_cpu_on() for CPUs running in ARM 32-bit non-secure mode:

  qemu-system-arm: target/arm/helper.c:11359: cpu_get_tb_cpu_state:
  Assertion `flags == rebuild_hflags_internal(env)' failed.
  Aborted (core dumped)

Fixes: 0c7f8c43daf65
Signed-off-by: Niek Linnenbank <nieklinnenbank@gmail.com>
---
 target/arm/arm-powerctl.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/target/arm/arm-powerctl.c b/target/arm/arm-powerctl.c
index b064513d44..b75f813b40 100644
--- a/target/arm/arm-powerctl.c
+++ b/target/arm/arm-powerctl.c
@@ -127,6 +127,9 @@ static void arm_set_cpu_on_async_work(CPUState *target_cpu_state,
         target_cpu->env.regs[0] = info->context_id;
     }
 
+    /* CP15 update requires rebuilding hflags */
+    arm_rebuild_hflags(&target_cpu->env);
+
     /* Start the new CPU at the requested address */
     cpu_set_pc(target_cpu_state, info->entry);
 
-- 
2.17.1



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

* [PATCH v2 07/10] arm: allwinner-h3: add CPU Configuration module
  2019-12-16 23:35 [PATCH v2 00/10] Add Allwinner H3 SoC and Orange Pi PC Machine Niek Linnenbank
                   ` (5 preceding siblings ...)
  2019-12-16 23:35 ` [PATCH v2 06/10] arm/arm-powerctl: rebuild hflags after setting CP15 bits in arm_set_cpu_on() Niek Linnenbank
@ 2019-12-16 23:35 ` Niek Linnenbank
  2019-12-16 23:35 ` [PATCH v2 08/10] arm: allwinner-h3: add Security Identifier device Niek Linnenbank
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 30+ messages in thread
From: Niek Linnenbank @ 2019-12-16 23:35 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, Niek Linnenbank, qemu-arm, philmd

The Allwinner H3 System on Chip design contains four ARM Cortex A7
processors that can be configured and reset using the CPU Configuration
module interface. This commit adds support for the CPU configuration
interface which emulates the following features:

 * CPU reset
 * Shared 64-bit timer

Signed-off-by: Niek Linnenbank <nieklinnenbank@gmail.com>
---
 include/hw/arm/allwinner-h3.h         |   2 +
 include/hw/misc/allwinner-h3-cpucfg.h |  42 ++++
 hw/arm/allwinner-h3.c                 |   7 +
 hw/misc/allwinner-h3-cpucfg.c         | 288 ++++++++++++++++++++++++++
 hw/misc/Makefile.objs                 |   1 +
 hw/misc/trace-events                  |   5 +
 6 files changed, 345 insertions(+)
 create mode 100644 include/hw/misc/allwinner-h3-cpucfg.h
 create mode 100644 hw/misc/allwinner-h3-cpucfg.c

diff --git a/include/hw/arm/allwinner-h3.h b/include/hw/arm/allwinner-h3.h
index bead6d4f85..8128ae6131 100644
--- a/include/hw/arm/allwinner-h3.h
+++ b/include/hw/arm/allwinner-h3.h
@@ -27,6 +27,7 @@
 #include "hw/timer/allwinner-a10-pit.h"
 #include "hw/intc/arm_gic.h"
 #include "hw/misc/allwinner-h3-clk.h"
+#include "hw/misc/allwinner-h3-cpucfg.h"
 #include "hw/misc/allwinner-h3-syscon.h"
 #include "target/arm/cpu.h"
 
@@ -74,6 +75,7 @@ typedef struct AwH3State {
     const hwaddr *memmap;
     AwA10PITState timer;
     AwH3ClockState ccu;
+    AwH3CpuCfgState cpucfg;
     AwH3SysconState syscon;
     GICState gic;
     MemoryRegion sram_a1;
diff --git a/include/hw/misc/allwinner-h3-cpucfg.h b/include/hw/misc/allwinner-h3-cpucfg.h
new file mode 100644
index 0000000000..92b2dcbe2f
--- /dev/null
+++ b/include/hw/misc/allwinner-h3-cpucfg.h
@@ -0,0 +1,42 @@
+/*
+ * Allwinner H3 CPU Configuration Module emulation
+ *
+ * Copyright (C) 2019 Niek Linnenbank <nieklinnenbank@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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_MISC_ALLWINNER_H3_CPUCFG_H
+#define HW_MISC_ALLWINNER_H3_CPUCFG_H
+
+#include "hw/sysbus.h"
+
+#define TYPE_AW_H3_CPUCFG   "allwinner-h3-cpucfg"
+#define AW_H3_CPUCFG(obj)   OBJECT_CHECK(AwH3CpuCfgState, (obj), \
+                                         TYPE_AW_H3_CPUCFG)
+
+typedef struct AwH3CpuCfgState {
+    /*< private >*/
+    SysBusDevice parent_obj;
+    /*< public >*/
+
+    MemoryRegion iomem;
+    uint32_t gen_ctrl;
+    uint32_t super_standby;
+    uint32_t entry_addr;
+    uint32_t counter_ctrl;
+
+} AwH3CpuCfgState;
+
+#endif
diff --git a/hw/arm/allwinner-h3.c b/hw/arm/allwinner-h3.c
index 8482d616e7..1a9748ab2e 100644
--- a/hw/arm/allwinner-h3.c
+++ b/hw/arm/allwinner-h3.c
@@ -193,6 +193,9 @@ static void aw_h3_init(Object *obj)
 
     sysbus_init_child_obj(obj, "syscon", &s->syscon, sizeof(s->syscon),
                           TYPE_AW_H3_SYSCON);
+
+    sysbus_init_child_obj(obj, "cpucfg", &s->cpucfg, sizeof(s->cpucfg),
+                          TYPE_AW_H3_CPUCFG);
 }
 
 static void aw_h3_realize(DeviceState *dev, Error **errp)
@@ -325,6 +328,10 @@ static void aw_h3_realize(DeviceState *dev, Error **errp)
     qdev_init_nofail(DEVICE(&s->syscon));
     sysbus_mmio_map(SYS_BUS_DEVICE(&s->syscon), 0, s->memmap[AW_H3_SYSCON]);
 
+    /* CPU Configuration */
+    qdev_init_nofail(DEVICE(&s->cpucfg));
+    sysbus_mmio_map(SYS_BUS_DEVICE(&s->cpucfg), 0, s->memmap[AW_H3_CPUCFG]);
+
     /* Universal Serial Bus */
     sysbus_create_simple(TYPE_AW_H3_EHCI, s->memmap[AW_H3_EHCI0],
                          qdev_get_gpio_in(DEVICE(&s->gic),
diff --git a/hw/misc/allwinner-h3-cpucfg.c b/hw/misc/allwinner-h3-cpucfg.c
new file mode 100644
index 0000000000..1d238c5c78
--- /dev/null
+++ b/hw/misc/allwinner-h3-cpucfg.c
@@ -0,0 +1,288 @@
+/*
+ * Allwinner H3 CPU Configuration Module emulation
+ *
+ * Copyright (C) 2019 Niek Linnenbank <nieklinnenbank@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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/units.h"
+#include "hw/sysbus.h"
+#include "migration/vmstate.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "qemu/error-report.h"
+#include "qemu/timer.h"
+#include "hw/core/cpu.h"
+#include "arm-powerctl.h"
+#include "hw/misc/allwinner-h3-cpucfg.h"
+#include "trace.h"
+
+/* CPUCFG register offsets */
+enum {
+    REG_CPUS_RST_CTRL       = 0x0000, /* CPUs Reset Control */
+    REG_CPU0_RST_CTRL       = 0x0040, /* CPU#0 Reset Control */
+    REG_CPU0_CTRL           = 0x0044, /* CPU#0 Control */
+    REG_CPU0_STATUS         = 0x0048, /* CPU#0 Status */
+    REG_CPU1_RST_CTRL       = 0x0080, /* CPU#1 Reset Control */
+    REG_CPU1_CTRL           = 0x0084, /* CPU#1 Control */
+    REG_CPU1_STATUS         = 0x0088, /* CPU#1 Status */
+    REG_CPU2_RST_CTRL       = 0x00C0, /* CPU#2 Reset Control */
+    REG_CPU2_CTRL           = 0x00C4, /* CPU#2 Control */
+    REG_CPU2_STATUS         = 0x00C8, /* CPU#2 Status */
+    REG_CPU3_RST_CTRL       = 0x0100, /* CPU#3 Reset Control */
+    REG_CPU3_CTRL           = 0x0104, /* CPU#3 Control */
+    REG_CPU3_STATUS         = 0x0108, /* CPU#3 Status */
+    REG_CPU_SYS_RST         = 0x0140, /* CPU System Reset */
+    REG_CLK_GATING          = 0x0144, /* CPU Clock Gating */
+    REG_GEN_CTRL            = 0x0184, /* General Control */
+    REG_SUPER_STANDBY       = 0x01A0, /* Super Standby Flag */
+    REG_ENTRY_ADDR          = 0x01A4, /* Reset Entry Address */
+    REG_DBG_EXTERN          = 0x01E4, /* Debug External */
+    REG_CNT64_CTRL          = 0x0280, /* 64-bit Counter Control */
+    REG_CNT64_LOW           = 0x0284, /* 64-bit Counter Low */
+    REG_CNT64_HIGH          = 0x0288, /* 64-bit Counter High */
+};
+
+/* CPUCFG register flags */
+enum {
+    CPUX_RESET_RELEASED     = ((1 << 1) | (1 << 0)),
+    CPUX_STATUS_SMP         = (1 << 0),
+    CPU_SYS_RESET_RELEASED  = (1 << 0),
+    CLK_GATING_ENABLE       = ((1 << 8) | 0xF),
+};
+
+/* CPUCFG register reset values */
+enum {
+    REG_CLK_GATING_RST      = 0x0000010F,
+    REG_GEN_CTRL_RST        = 0x00000020,
+    REG_SUPER_STANDBY_RST   = 0x0,
+    REG_CNT64_CTRL_RST      = 0x0,
+};
+
+static void allwinner_h3_cpucfg_cpu_reset(AwH3CpuCfgState *s, uint8_t cpu_id)
+{
+    int ret;
+
+    trace_allwinner_h3_cpucfg_cpu_reset(cpu_id, s->entry_addr);
+
+    ret = arm_set_cpu_on(cpu_id, s->entry_addr, 0, 3, false);
+    if (ret != QEMU_ARM_POWERCTL_RET_SUCCESS) {
+        error_report("%s: failed to bring up CPU %d: err %d",
+                     __func__, cpu_id, ret);
+        return;
+    }
+}
+
+static uint64_t allwinner_h3_cpucfg_read(void *opaque, hwaddr offset,
+                                         unsigned size)
+{
+    const AwH3CpuCfgState *s = (AwH3CpuCfgState *)opaque;
+    uint64_t val = 0;
+
+    switch (offset) {
+    case REG_CPUS_RST_CTRL:     /* CPUs Reset Control */
+    case REG_CPU_SYS_RST:       /* CPU System Reset */
+        val = CPU_SYS_RESET_RELEASED;
+        break;
+    case REG_CPU0_RST_CTRL:     /* CPU#0 Reset Control */
+    case REG_CPU1_RST_CTRL:     /* CPU#1 Reset Control */
+    case REG_CPU2_RST_CTRL:     /* CPU#2 Reset Control */
+    case REG_CPU3_RST_CTRL:     /* CPU#3 Reset Control */
+        val = CPUX_RESET_RELEASED;
+        break;
+    case REG_CPU0_CTRL:         /* CPU#0 Control */
+    case REG_CPU1_CTRL:         /* CPU#1 Control */
+    case REG_CPU2_CTRL:         /* CPU#2 Control */
+    case REG_CPU3_CTRL:         /* CPU#3 Control */
+        val = 0;
+        break;
+    case REG_CPU0_STATUS:       /* CPU#0 Status */
+    case REG_CPU1_STATUS:       /* CPU#1 Status */
+    case REG_CPU2_STATUS:       /* CPU#2 Status */
+    case REG_CPU3_STATUS:       /* CPU#3 Status */
+        val = CPUX_STATUS_SMP;
+        break;
+    case REG_CLK_GATING:        /* CPU Clock Gating */
+        val = CLK_GATING_ENABLE;
+        break;
+    case REG_GEN_CTRL:          /* General Control */
+        val = s->gen_ctrl;
+        break;
+    case REG_SUPER_STANDBY:     /* Super Standby Flag */
+        val = s->super_standby;
+        break;
+    case REG_ENTRY_ADDR:        /* Reset Entry Address */
+        val = s->entry_addr;
+        break;
+    case REG_DBG_EXTERN:        /* Debug External */
+        break;
+    case REG_CNT64_CTRL:        /* 64-bit Counter Control */
+        val = s->counter_ctrl;
+        break;
+    case REG_CNT64_LOW:         /* 64-bit Counter Low */
+        val = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) & 0xffffffff;
+        break;
+    case REG_CNT64_HIGH:        /* 64-bit Counter High */
+        val = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) >> 32;
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: bad read offset 0x%04x\n",
+                      __func__, (uint32_t)offset);
+        return 0;
+    }
+
+    trace_allwinner_h3_cpucfg_read(offset, val, size);
+
+    return val;
+}
+
+static void allwinner_h3_cpucfg_write(void *opaque, hwaddr offset,
+                                      uint64_t val, unsigned size)
+{
+    AwH3CpuCfgState *s = (AwH3CpuCfgState *)opaque;
+
+    trace_allwinner_h3_cpucfg_write(offset, val, size);
+
+    switch (offset) {
+    case REG_CPUS_RST_CTRL:     /* CPUs Reset Control */
+    case REG_CPU_SYS_RST:       /* CPU System Reset */
+        break;
+    case REG_CPU0_RST_CTRL:     /* CPU#0 Reset Control */
+        if (val) {
+            allwinner_h3_cpucfg_cpu_reset(s, 0);
+        }
+        break;
+    case REG_CPU1_RST_CTRL:     /* CPU#1 Reset Control */
+        if (val) {
+            allwinner_h3_cpucfg_cpu_reset(s, 1);
+        }
+        break;
+    case REG_CPU2_RST_CTRL:     /* CPU#2 Reset Control */
+        if (val) {
+            allwinner_h3_cpucfg_cpu_reset(s, 2);
+        }
+        break;
+    case REG_CPU3_RST_CTRL:     /* CPU#3 Reset Control */
+        if (val) {
+            allwinner_h3_cpucfg_cpu_reset(s, 3);
+        }
+        break;
+    case REG_CPU0_CTRL:         /* CPU#0 Control */
+    case REG_CPU1_CTRL:         /* CPU#1 Control */
+    case REG_CPU2_CTRL:         /* CPU#2 Control */
+    case REG_CPU3_CTRL:         /* CPU#3 Control */
+    case REG_CPU0_STATUS:       /* CPU#0 Status */
+    case REG_CPU1_STATUS:       /* CPU#1 Status */
+    case REG_CPU2_STATUS:       /* CPU#2 Status */
+    case REG_CPU3_STATUS:       /* CPU#3 Status */
+    case REG_CLK_GATING:        /* CPU Clock Gating */
+    case REG_GEN_CTRL:          /* General Control */
+        s->gen_ctrl = val;
+        break;
+    case REG_SUPER_STANDBY:     /* Super Standby Flag */
+        s->super_standby = val;
+        break;
+    case REG_ENTRY_ADDR:        /* Reset Entry Address */
+        s->entry_addr = val;
+        break;
+    case REG_DBG_EXTERN:        /* Debug External */
+        break;
+    case REG_CNT64_CTRL:        /* 64-bit Counter Control */
+        s->counter_ctrl = val;
+        break;
+    case REG_CNT64_LOW:         /* 64-bit Counter Low */
+    case REG_CNT64_HIGH:        /* 64-bit Counter High */
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write offset 0x%04x\n",
+                      __func__, (uint32_t)offset);
+        return;
+    }
+}
+
+static const MemoryRegionOps allwinner_h3_cpucfg_ops = {
+    .read = allwinner_h3_cpucfg_read,
+    .write = allwinner_h3_cpucfg_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+        .unaligned = false
+    },
+    .impl.min_access_size = 4,
+};
+
+static void allwinner_h3_cpucfg_reset(DeviceState *dev)
+{
+    AwH3CpuCfgState *s = AW_H3_CPUCFG(dev);
+
+    /* Set default values for registers */
+    s->gen_ctrl = REG_GEN_CTRL_RST;
+    s->super_standby = REG_SUPER_STANDBY_RST;
+    s->entry_addr = 0;
+    s->counter_ctrl = REG_CNT64_CTRL_RST;
+}
+
+static void allwinner_h3_cpucfg_realize(DeviceState *dev, Error **errp)
+{
+}
+
+static void allwinner_h3_cpucfg_init(Object *obj)
+{
+    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+    AwH3CpuCfgState *s = AW_H3_CPUCFG(obj);
+
+    /* Memory mapping */
+    memory_region_init_io(&s->iomem, OBJECT(s), &allwinner_h3_cpucfg_ops, s,
+                          TYPE_AW_H3_CPUCFG, 1 * KiB);
+    sysbus_init_mmio(sbd, &s->iomem);
+}
+
+static const VMStateDescription allwinner_h3_cpucfg_vmstate = {
+    .name = "allwinner-h3-cpucfg",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(gen_ctrl, AwH3CpuCfgState),
+        VMSTATE_UINT32(super_standby, AwH3CpuCfgState),
+        VMSTATE_UINT32(counter_ctrl, AwH3CpuCfgState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void allwinner_h3_cpucfg_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->reset = allwinner_h3_cpucfg_reset;
+    dc->realize = allwinner_h3_cpucfg_realize;
+    dc->vmsd = &allwinner_h3_cpucfg_vmstate;
+}
+
+static const TypeInfo allwinner_h3_cpucfg_info = {
+    .name          = TYPE_AW_H3_CPUCFG,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_init = allwinner_h3_cpucfg_init,
+    .instance_size = sizeof(AwH3CpuCfgState),
+    .class_init    = allwinner_h3_cpucfg_class_init,
+};
+
+static void allwinner_h3_cpucfg_register(void)
+{
+    type_register_static(&allwinner_h3_cpucfg_info);
+}
+
+type_init(allwinner_h3_cpucfg_register)
diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
index b234aefba5..c4ca2ed689 100644
--- a/hw/misc/Makefile.objs
+++ b/hw/misc/Makefile.objs
@@ -29,6 +29,7 @@ common-obj-$(CONFIG_MACIO) += macio/
 common-obj-$(CONFIG_IVSHMEM_DEVICE) += ivshmem.o
 
 common-obj-$(CONFIG_ALLWINNER_H3) += allwinner-h3-clk.o
+obj-$(CONFIG_ALLWINNER_H3) += allwinner-h3-cpucfg.o
 common-obj-$(CONFIG_ALLWINNER_H3) += allwinner-h3-syscon.o
 common-obj-$(CONFIG_REALVIEW) += arm_sysctl.o
 common-obj-$(CONFIG_NSERIES) += cbus.o
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
index 1deb1d08c1..b93089d010 100644
--- a/hw/misc/trace-events
+++ b/hw/misc/trace-events
@@ -1,5 +1,10 @@
 # See docs/devel/tracing.txt for syntax documentation.
 
+# allwinner-h3-cpucfg.c
+allwinner_h3_cpucfg_cpu_reset(uint8_t cpu_id, uint32_t reset_addr) "H3-CPUCFG: cpu_reset: id %u, reset_addr 0x%" PRIu32
+allwinner_h3_cpucfg_read(uint64_t offset, uint64_t data, unsigned size) "H3-CPUCFG: read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32
+allwinner_h3_cpucfg_write(uint64_t offset, uint64_t data, unsigned size) "H3-CPUCFG: write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32
+
 # eccmemctl.c
 ecc_mem_writel_mer(uint32_t val) "Write memory enable 0x%08x"
 ecc_mem_writel_mdr(uint32_t val) "Write memory delay 0x%08x"
-- 
2.17.1



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

* [PATCH v2 08/10] arm: allwinner-h3: add Security Identifier device
  2019-12-16 23:35 [PATCH v2 00/10] Add Allwinner H3 SoC and Orange Pi PC Machine Niek Linnenbank
                   ` (6 preceding siblings ...)
  2019-12-16 23:35 ` [PATCH v2 07/10] arm: allwinner-h3: add CPU Configuration module Niek Linnenbank
@ 2019-12-16 23:35 ` Niek Linnenbank
  2019-12-17  7:45   ` Philippe Mathieu-Daudé
  2019-12-16 23:35 ` [PATCH v2 09/10] arm: allwinner-h3: add SD/MMC host controller Niek Linnenbank
                   ` (2 subsequent siblings)
  10 siblings, 1 reply; 30+ messages in thread
From: Niek Linnenbank @ 2019-12-16 23:35 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, Niek Linnenbank, qemu-arm, philmd

The Security Identifier device in Allwinner H3 System on Chip
gives applications a per-board unique identifier. This commit
adds support for the Allwinner H3 Security Identifier using
a 128-bit UUID value as input.

Signed-off-by: Niek Linnenbank <nieklinnenbank@gmail.com>
---
 include/hw/arm/allwinner-h3.h      |   2 +
 include/hw/misc/allwinner-h3-sid.h |  40 +++++++
 hw/arm/allwinner-h3.c              |   7 ++
 hw/arm/orangepi.c                  |   4 +
 hw/misc/allwinner-h3-sid.c         | 179 +++++++++++++++++++++++++++++
 hw/misc/Makefile.objs              |   1 +
 hw/misc/trace-events               |   4 +
 7 files changed, 237 insertions(+)
 create mode 100644 include/hw/misc/allwinner-h3-sid.h
 create mode 100644 hw/misc/allwinner-h3-sid.c

diff --git a/include/hw/arm/allwinner-h3.h b/include/hw/arm/allwinner-h3.h
index 8128ae6131..c98c1972a6 100644
--- a/include/hw/arm/allwinner-h3.h
+++ b/include/hw/arm/allwinner-h3.h
@@ -29,6 +29,7 @@
 #include "hw/misc/allwinner-h3-clk.h"
 #include "hw/misc/allwinner-h3-cpucfg.h"
 #include "hw/misc/allwinner-h3-syscon.h"
+#include "hw/misc/allwinner-h3-sid.h"
 #include "target/arm/cpu.h"
 
 enum {
@@ -77,6 +78,7 @@ typedef struct AwH3State {
     AwH3ClockState ccu;
     AwH3CpuCfgState cpucfg;
     AwH3SysconState syscon;
+    AwH3SidState sid;
     GICState gic;
     MemoryRegion sram_a1;
     MemoryRegion sram_a2;
diff --git a/include/hw/misc/allwinner-h3-sid.h b/include/hw/misc/allwinner-h3-sid.h
new file mode 100644
index 0000000000..79c9a24459
--- /dev/null
+++ b/include/hw/misc/allwinner-h3-sid.h
@@ -0,0 +1,40 @@
+/*
+ * Allwinner H3 Security ID emulation
+ *
+ * Copyright (C) 2019 Niek Linnenbank <nieklinnenbank@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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_MISC_ALLWINNER_H3_SID_H
+#define HW_MISC_ALLWINNER_H3_SID_H
+
+#include "hw/sysbus.h"
+#include "qemu/uuid.h"
+
+#define TYPE_AW_H3_SID    "allwinner-h3-sid"
+#define AW_H3_SID(obj)    OBJECT_CHECK(AwH3SidState, (obj), TYPE_AW_H3_SID)
+
+typedef struct AwH3SidState {
+    /*< private >*/
+    SysBusDevice parent_obj;
+    /*< public >*/
+
+    MemoryRegion iomem;
+    uint32_t control;
+    uint32_t rdkey;
+    QemuUUID identifier;
+} AwH3SidState;
+
+#endif
diff --git a/hw/arm/allwinner-h3.c b/hw/arm/allwinner-h3.c
index 1a9748ab2e..ba34f905cd 100644
--- a/hw/arm/allwinner-h3.c
+++ b/hw/arm/allwinner-h3.c
@@ -196,6 +196,9 @@ static void aw_h3_init(Object *obj)
 
     sysbus_init_child_obj(obj, "cpucfg", &s->cpucfg, sizeof(s->cpucfg),
                           TYPE_AW_H3_CPUCFG);
+
+    sysbus_init_child_obj(obj, "sid", &s->sid, sizeof(s->sid),
+                          TYPE_AW_H3_SID);
 }
 
 static void aw_h3_realize(DeviceState *dev, Error **errp)
@@ -332,6 +335,10 @@ static void aw_h3_realize(DeviceState *dev, Error **errp)
     qdev_init_nofail(DEVICE(&s->cpucfg));
     sysbus_mmio_map(SYS_BUS_DEVICE(&s->cpucfg), 0, s->memmap[AW_H3_CPUCFG]);
 
+    /* Security Identifier */
+    qdev_init_nofail(DEVICE(&s->sid));
+    sysbus_mmio_map(SYS_BUS_DEVICE(&s->sid), 0, s->memmap[AW_H3_SID]);
+
     /* Universal Serial Bus */
     sysbus_create_simple(TYPE_AW_H3_EHCI, s->memmap[AW_H3_EHCI0],
                          qdev_get_gpio_in(DEVICE(&s->gic),
diff --git a/hw/arm/orangepi.c b/hw/arm/orangepi.c
index 62cefc8c06..b01c4b4f01 100644
--- a/hw/arm/orangepi.c
+++ b/hw/arm/orangepi.c
@@ -62,6 +62,10 @@ static void orangepi_init(MachineState *machine)
         exit(1);
     }
 
+    /* Setup SID properties */
+    qdev_prop_set_string(DEVICE(&s->h3->sid), "identifier",
+                         "8100c002-0001-0002-0003-000044556677");
+
     /* Mark H3 object realized */
     object_property_set_bool(OBJECT(s->h3), true, "realized", &error_abort);
     if (error_abort != NULL) {
diff --git a/hw/misc/allwinner-h3-sid.c b/hw/misc/allwinner-h3-sid.c
new file mode 100644
index 0000000000..c472f2bcc6
--- /dev/null
+++ b/hw/misc/allwinner-h3-sid.c
@@ -0,0 +1,179 @@
+/*
+ * Allwinner H3 Security ID emulation
+ *
+ * Copyright (C) 2019 Niek Linnenbank <nieklinnenbank@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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/units.h"
+#include "hw/sysbus.h"
+#include "migration/vmstate.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "qemu/guest-random.h"
+#include "qapi/error.h"
+#include "hw/qdev-properties.h"
+#include "hw/misc/allwinner-h3-sid.h"
+#include "trace.h"
+
+/* SID register offsets */
+enum {
+    REG_PRCTL = 0x40,   /* Control */
+    REG_RDKEY = 0x60,   /* Read Key */
+};
+
+/* SID register flags */
+enum {
+    REG_PRCTL_WRITE   = 0x0002, /* Unknown write flag */
+    REG_PRCTL_OP_LOCK = 0xAC00, /* Lock operation */
+};
+
+static uint64_t allwinner_h3_sid_read(void *opaque, hwaddr offset,
+                                      unsigned size)
+{
+    const AwH3SidState *s = (AwH3SidState *)opaque;
+    uint64_t val = 0;
+
+    switch (offset) {
+    case REG_PRCTL:    /* Control */
+        val = s->control;
+        break;
+    case REG_RDKEY:    /* Read Key */
+        val = s->rdkey;
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: bad read offset 0x%04x\n",
+                      __func__, (uint32_t)offset);
+        return 0;
+    }
+
+    trace_allwinner_h3_sid_read(offset, val, size);
+
+    return val;
+}
+
+static void allwinner_h3_sid_write(void *opaque, hwaddr offset,
+                                   uint64_t val, unsigned size)
+{
+    AwH3SidState *s = (AwH3SidState *)opaque;
+
+    trace_allwinner_h3_sid_write(offset, val, size);
+
+    switch (offset) {
+    case REG_PRCTL:    /* Control */
+        s->control = val;
+
+        if ((s->control & REG_PRCTL_OP_LOCK) &&
+            (s->control & REG_PRCTL_WRITE)) {
+            uint32_t id = s->control >> 16;
+
+            if (id < sizeof(QemuUUID)) {
+                s->rdkey = (s->identifier.data[id]) |
+                           (s->identifier.data[id + 1] << 8) |
+                           (s->identifier.data[id + 2] << 16) |
+                           (s->identifier.data[id + 3] << 24);
+            }
+        }
+        s->control &= ~REG_PRCTL_WRITE;
+        break;
+    case REG_RDKEY:    /* Read Key */
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write offset 0x%04x\n",
+                      __func__, (uint32_t)offset);
+        break;
+    }
+}
+
+static const MemoryRegionOps allwinner_h3_sid_ops = {
+    .read = allwinner_h3_sid_read,
+    .write = allwinner_h3_sid_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+        .unaligned = false
+    },
+    .impl.min_access_size = 4,
+};
+
+static void allwinner_h3_sid_reset(DeviceState *dev)
+{
+    AwH3SidState *s = AW_H3_SID(dev);
+
+    /* Set default values for registers */
+    s->control = 0;
+    s->rdkey = 0;
+}
+
+static void allwinner_h3_sid_realize(DeviceState *dev, Error **errp)
+{
+}
+
+static void allwinner_h3_sid_init(Object *obj)
+{
+    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+    AwH3SidState *s = AW_H3_SID(obj);
+
+    /* Fill UUID with zeroes by default */
+    qemu_uuid_parse(UUID_NONE, &s->identifier);
+
+    /* Memory mapping */
+    memory_region_init_io(&s->iomem, OBJECT(s), &allwinner_h3_sid_ops, s,
+                          TYPE_AW_H3_SID, 1 * KiB);
+    sysbus_init_mmio(sbd, &s->iomem);
+}
+
+static Property allwinner_h3_sid_properties[] = {
+    DEFINE_PROP_UUID_NODEFAULT("identifier", AwH3SidState, identifier),
+    DEFINE_PROP_END_OF_LIST()
+};
+
+static const VMStateDescription allwinner_h3_sid_vmstate = {
+    .name = "allwinner-h3-sid",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(control, AwH3SidState),
+        VMSTATE_UINT32(rdkey, AwH3SidState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void allwinner_h3_sid_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->reset = allwinner_h3_sid_reset;
+    dc->realize = allwinner_h3_sid_realize;
+    dc->vmsd = &allwinner_h3_sid_vmstate;
+    dc->props = allwinner_h3_sid_properties;
+}
+
+static const TypeInfo allwinner_h3_sid_info = {
+    .name          = TYPE_AW_H3_SID,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_init = allwinner_h3_sid_init,
+    .instance_size = sizeof(AwH3SidState),
+    .class_init    = allwinner_h3_sid_class_init,
+};
+
+static void allwinner_h3_sid_register(void)
+{
+    type_register_static(&allwinner_h3_sid_info);
+}
+
+type_init(allwinner_h3_sid_register)
diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
index c4ca2ed689..f3620eee4e 100644
--- a/hw/misc/Makefile.objs
+++ b/hw/misc/Makefile.objs
@@ -31,6 +31,7 @@ common-obj-$(CONFIG_IVSHMEM_DEVICE) += ivshmem.o
 common-obj-$(CONFIG_ALLWINNER_H3) += allwinner-h3-clk.o
 obj-$(CONFIG_ALLWINNER_H3) += allwinner-h3-cpucfg.o
 common-obj-$(CONFIG_ALLWINNER_H3) += allwinner-h3-syscon.o
+common-obj-$(CONFIG_ALLWINNER_H3) += allwinner-h3-sid.o
 common-obj-$(CONFIG_REALVIEW) += arm_sysctl.o
 common-obj-$(CONFIG_NSERIES) += cbus.o
 common-obj-$(CONFIG_ECCMEMCTL) += eccmemctl.o
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
index b93089d010..a777844ca3 100644
--- a/hw/misc/trace-events
+++ b/hw/misc/trace-events
@@ -5,6 +5,10 @@ allwinner_h3_cpucfg_cpu_reset(uint8_t cpu_id, uint32_t reset_addr) "H3-CPUCFG: c
 allwinner_h3_cpucfg_read(uint64_t offset, uint64_t data, unsigned size) "H3-CPUCFG: read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32
 allwinner_h3_cpucfg_write(uint64_t offset, uint64_t data, unsigned size) "H3-CPUCFG: write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32
 
+# allwinner-h3-sid.c
+allwinner_h3_sid_read(uint64_t offset, uint64_t data, unsigned size) "H3-SID: read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32
+allwinner_h3_sid_write(uint64_t offset, uint64_t data, unsigned size) "H3-SID: write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32
+
 # eccmemctl.c
 ecc_mem_writel_mer(uint32_t val) "Write memory enable 0x%08x"
 ecc_mem_writel_mdr(uint32_t val) "Write memory delay 0x%08x"
-- 
2.17.1



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

* [PATCH v2 09/10] arm: allwinner-h3: add SD/MMC host controller
  2019-12-16 23:35 [PATCH v2 00/10] Add Allwinner H3 SoC and Orange Pi PC Machine Niek Linnenbank
                   ` (7 preceding siblings ...)
  2019-12-16 23:35 ` [PATCH v2 08/10] arm: allwinner-h3: add Security Identifier device Niek Linnenbank
@ 2019-12-16 23:35 ` Niek Linnenbank
  2019-12-16 23:35 ` [PATCH v2 10/10] arm: allwinner-h3: add EMAC ethernet device Niek Linnenbank
  2019-12-30 11:28 ` [PATCH v2 00/10] Add Allwinner H3 SoC and Orange Pi PC Machine Niek Linnenbank
  10 siblings, 0 replies; 30+ messages in thread
From: Niek Linnenbank @ 2019-12-16 23:35 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, Niek Linnenbank, qemu-arm, philmd

The Allwinner H3 System on Chip contains an integrated storage
controller for Secure Digital (SD) and Multi Media Card (MMC)
interfaces. This commit adds support for the Allwinner H3
SD/MMC storage controller with the following emulated features:

 * DMA transfers
 * Direct FIFO I/O
 * Short/Long format command responses
 * Auto-Stop command (CMD12)
 * Insert & remove card detection

Signed-off-by: Niek Linnenbank <nieklinnenbank@gmail.com>
---
 include/hw/arm/allwinner-h3.h       |   2 +
 include/hw/sd/allwinner-h3-sdhost.h |  71 +++
 hw/arm/allwinner-h3.c               |  16 +
 hw/arm/orangepi.c                   |  15 +
 hw/sd/allwinner-h3-sdhost.c         | 813 ++++++++++++++++++++++++++++
 hw/sd/Makefile.objs                 |   1 +
 hw/sd/trace-events                  |   7 +
 7 files changed, 925 insertions(+)
 create mode 100644 include/hw/sd/allwinner-h3-sdhost.h
 create mode 100644 hw/sd/allwinner-h3-sdhost.c

diff --git a/include/hw/arm/allwinner-h3.h b/include/hw/arm/allwinner-h3.h
index c98c1972a6..ab564987be 100644
--- a/include/hw/arm/allwinner-h3.h
+++ b/include/hw/arm/allwinner-h3.h
@@ -30,6 +30,7 @@
 #include "hw/misc/allwinner-h3-cpucfg.h"
 #include "hw/misc/allwinner-h3-syscon.h"
 #include "hw/misc/allwinner-h3-sid.h"
+#include "hw/sd/allwinner-h3-sdhost.h"
 #include "target/arm/cpu.h"
 
 enum {
@@ -79,6 +80,7 @@ typedef struct AwH3State {
     AwH3CpuCfgState cpucfg;
     AwH3SysconState syscon;
     AwH3SidState sid;
+    AwH3SDHostState mmc0;
     GICState gic;
     MemoryRegion sram_a1;
     MemoryRegion sram_a2;
diff --git a/include/hw/sd/allwinner-h3-sdhost.h b/include/hw/sd/allwinner-h3-sdhost.h
new file mode 100644
index 0000000000..4a93405e6c
--- /dev/null
+++ b/include/hw/sd/allwinner-h3-sdhost.h
@@ -0,0 +1,71 @@
+/*
+ * Allwinner H3 SD Host Controller emulation
+ *
+ * Copyright (C) 2019 Niek Linnenbank <nieklinnenbank@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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 ALLWINNER_H3_SDHOST_H
+#define ALLWINNER_H3_SDHOST_H
+
+#include "hw/sysbus.h"
+#include "hw/sd/sd.h"
+
+#define TYPE_AW_H3_SDHOST "allwinner-h3-sdhost"
+#define AW_H3_SDHOST(obj) \
+        OBJECT_CHECK(AwH3SDHostState, (obj), TYPE_AW_H3_SDHOST)
+
+typedef struct {
+    SysBusDevice busdev;
+    SDBus sdbus;
+    MemoryRegion iomem;
+
+    uint32_t global_ctl;
+    uint32_t clock_ctl;
+    uint32_t timeout;
+    uint32_t bus_width;
+    uint32_t block_size;
+    uint32_t byte_count;
+    uint32_t transfer_cnt;
+
+    uint32_t command;
+    uint32_t command_arg;
+    uint32_t response[4];
+
+    uint32_t irq_mask;
+    uint32_t irq_status;
+    uint32_t status;
+
+    uint32_t fifo_wlevel;
+    uint32_t fifo_func_sel;
+    uint32_t debug_enable;
+    uint32_t auto12_arg;
+    uint32_t newtiming_set;
+    uint32_t newtiming_debug;
+    uint32_t hardware_rst;
+    uint32_t dmac;
+    uint32_t desc_base;
+    uint32_t dmac_status;
+    uint32_t dmac_irq;
+    uint32_t card_threshold;
+    uint32_t startbit_detect;
+    uint32_t response_crc;
+    uint32_t data_crc[8];
+    uint32_t status_crc;
+
+    qemu_irq irq;
+} AwH3SDHostState;
+
+#endif
diff --git a/hw/arm/allwinner-h3.c b/hw/arm/allwinner-h3.c
index ba34f905cd..b4ee524ee0 100644
--- a/hw/arm/allwinner-h3.c
+++ b/hw/arm/allwinner-h3.c
@@ -199,6 +199,9 @@ static void aw_h3_init(Object *obj)
 
     sysbus_init_child_obj(obj, "sid", &s->sid, sizeof(s->sid),
                           TYPE_AW_H3_SID);
+
+    sysbus_init_child_obj(obj, "mmc0", &s->mmc0, sizeof(s->mmc0),
+                          TYPE_AW_H3_SDHOST);
 }
 
 static void aw_h3_realize(DeviceState *dev, Error **errp)
@@ -339,6 +342,19 @@ static void aw_h3_realize(DeviceState *dev, Error **errp)
     qdev_init_nofail(DEVICE(&s->sid));
     sysbus_mmio_map(SYS_BUS_DEVICE(&s->sid), 0, s->memmap[AW_H3_SID]);
 
+    /* SD/MMC */
+    qdev_init_nofail(DEVICE(&s->mmc0));
+    sysbus_mmio_map(SYS_BUS_DEVICE(&s->mmc0), 0, s->memmap[AW_H3_MMC0]);
+    sysbus_connect_irq(SYS_BUS_DEVICE(&s->mmc0), 0,
+                       qdev_get_gpio_in(DEVICE(&s->gic), AW_H3_GIC_SPI_MMC0));
+
+    object_property_add_alias(OBJECT(s), "sd-bus", OBJECT(&s->mmc0),
+                              "sd-bus", &error_abort);
+    if (error_abort) {
+        error_propagate(errp, error_abort);
+        return;
+    }
+
     /* Universal Serial Bus */
     sysbus_create_simple(TYPE_AW_H3_EHCI, s->memmap[AW_H3_EHCI0],
                          qdev_get_gpio_in(DEVICE(&s->gic),
diff --git a/hw/arm/orangepi.c b/hw/arm/orangepi.c
index b01c4b4f01..87968505ae 100644
--- a/hw/arm/orangepi.c
+++ b/hw/arm/orangepi.c
@@ -38,6 +38,10 @@ typedef struct OrangePiState {
 static void orangepi_init(MachineState *machine)
 {
     OrangePiState *s = g_new(OrangePiState, 1);
+    DriveInfo *di;
+    BlockBackend *blk;
+    BusState *bus;
+    DeviceState *carddev;
 
     /* Only allow Cortex-A7 for this board */
     if (strcmp(machine->cpu_type, ARM_CPU_TYPE_NAME("cortex-a7")) != 0) {
@@ -73,6 +77,16 @@ static void orangepi_init(MachineState *machine)
         exit(1);
     }
 
+    /* Retrieve SD bus */
+    di = drive_get_next(IF_SD);
+    blk = di ? blk_by_legacy_dinfo(di) : NULL;
+    bus = qdev_get_child_bus(DEVICE(s->h3), "sd-bus");
+
+    /* Plug in SD card */
+    carddev = qdev_create(bus, TYPE_SD_CARD);
+    qdev_prop_set_drive(carddev, "drive", blk, &error_fatal);
+    object_property_set_bool(OBJECT(carddev), true, "realized", &error_fatal);
+
     /* RAM */
     if (machine->ram_size > 1 * GiB) {
         error_report("Requested ram size is too large for this machine: "
@@ -95,6 +109,7 @@ static void orangepi_machine_init(MachineClass *mc)
 {
     mc->desc = "Orange Pi PC";
     mc->init = orangepi_init;
+    mc->block_default_type = IF_SD;
     mc->units_per_default_bus = 1;
     mc->min_cpus = AW_H3_NUM_CPUS;
     mc->max_cpus = AW_H3_NUM_CPUS;
diff --git a/hw/sd/allwinner-h3-sdhost.c b/hw/sd/allwinner-h3-sdhost.c
new file mode 100644
index 0000000000..c6661af614
--- /dev/null
+++ b/hw/sd/allwinner-h3-sdhost.c
@@ -0,0 +1,813 @@
+/*
+ * Allwinner H3 SD Host Controller emulation
+ *
+ * Copyright (C) 2019 Niek Linnenbank <nieklinnenbank@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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 "qemu/module.h"
+#include "qemu/units.h"
+#include "sysemu/blockdev.h"
+#include "hw/irq.h"
+#include "hw/sd/allwinner-h3-sdhost.h"
+#include "migration/vmstate.h"
+#include "trace.h"
+
+#define TYPE_AW_H3_SDHOST_BUS "allwinner-h3-sdhost-bus"
+#define AW_H3_SDHOST_BUS(obj) \
+    OBJECT_CHECK(SDBus, (obj), TYPE_AW_H3_SDHOST_BUS)
+
+/* SD Host register offsets */
+enum {
+    REG_SD_GCTL       = 0x00,  /* Global Control */
+    REG_SD_CKCR       = 0x04,  /* Clock Control */
+    REG_SD_TMOR       = 0x08,  /* Timeout */
+    REG_SD_BWDR       = 0x0C,  /* Bus Width */
+    REG_SD_BKSR       = 0x10,  /* Block Size */
+    REG_SD_BYCR       = 0x14,  /* Byte Count */
+    REG_SD_CMDR       = 0x18,  /* Command */
+    REG_SD_CAGR       = 0x1C,  /* Command Argument */
+    REG_SD_RESP0      = 0x20,  /* Response Zero */
+    REG_SD_RESP1      = 0x24,  /* Response One */
+    REG_SD_RESP2      = 0x28,  /* Response Two */
+    REG_SD_RESP3      = 0x2C,  /* Response Three */
+    REG_SD_IMKR       = 0x30,  /* Interrupt Mask */
+    REG_SD_MISR       = 0x34,  /* Masked Interrupt Status */
+    REG_SD_RISR       = 0x38,  /* Raw Interrupt Status */
+    REG_SD_STAR       = 0x3C,  /* Status */
+    REG_SD_FWLR       = 0x40,  /* FIFO Water Level */
+    REG_SD_FUNS       = 0x44,  /* FIFO Function Select */
+    REG_SD_DBGC       = 0x50,  /* Debug Enable */
+    REG_SD_A12A       = 0x58,  /* Auto command 12 argument */
+    REG_SD_NTSR       = 0x5C,  /* SD NewTiming Set */
+    REG_SD_SDBG       = 0x60,  /* SD newTiming Set Debug */
+    REG_SD_HWRST      = 0x78,  /* Hardware Reset Register */
+    REG_SD_DMAC       = 0x80,  /* Internal DMA Controller Control */
+    REG_SD_DLBA       = 0x84,  /* Descriptor List Base Address */
+    REG_SD_IDST       = 0x88,  /* Internal DMA Controller Status */
+    REG_SD_IDIE       = 0x8C,  /* Internal DMA Controller IRQ Enable */
+    REG_SD_THLDC      = 0x100, /* Card Threshold Control */
+    REG_SD_DSBD       = 0x10C, /* eMMC DDR Start Bit Detection Control */
+    REG_SD_RES_CRC    = 0x110, /* Response CRC from card/eMMC */
+    REG_SD_DATA7_CRC  = 0x114, /* CRC Data 7 from card/eMMC */
+    REG_SD_DATA6_CRC  = 0x118, /* CRC Data 6 from card/eMMC */
+    REG_SD_DATA5_CRC  = 0x11C, /* CRC Data 5 from card/eMMC */
+    REG_SD_DATA4_CRC  = 0x120, /* CRC Data 4 from card/eMMC */
+    REG_SD_DATA3_CRC  = 0x124, /* CRC Data 3 from card/eMMC */
+    REG_SD_DATA2_CRC  = 0x128, /* CRC Data 2 from card/eMMC */
+    REG_SD_DATA1_CRC  = 0x12C, /* CRC Data 1 from card/eMMC */
+    REG_SD_DATA0_CRC  = 0x130, /* CRC Data 0 from card/eMMC */
+    REG_SD_CRC_STA    = 0x134, /* CRC status from card/eMMC during write */
+    REG_SD_FIFO       = 0x200, /* Read/Write FIFO */
+};
+
+/* SD Host register flags */
+enum {
+    SD_GCTL_FIFO_AC_MOD     = (1 << 31),
+    SD_GCTL_DDR_MOD_SEL     = (1 << 10),
+    SD_GCTL_CD_DBC_ENB      = (1 << 8),
+    SD_GCTL_DMA_ENB         = (1 << 5),
+    SD_GCTL_INT_ENB         = (1 << 4),
+    SD_GCTL_DMA_RST         = (1 << 2),
+    SD_GCTL_FIFO_RST        = (1 << 1),
+    SD_GCTL_SOFT_RST        = (1 << 0),
+};
+
+enum {
+    SD_CMDR_LOAD            = (1 << 31),
+    SD_CMDR_CLKCHANGE       = (1 << 21),
+    SD_CMDR_WRITE           = (1 << 10),
+    SD_CMDR_AUTOSTOP        = (1 << 12),
+    SD_CMDR_DATA            = (1 << 9),
+    SD_CMDR_RESPONSE_LONG   = (1 << 7),
+    SD_CMDR_RESPONSE        = (1 << 6),
+    SD_CMDR_CMDID_MASK      = (0x3f),
+};
+
+enum {
+    SD_RISR_CARD_REMOVE     = (1 << 31),
+    SD_RISR_CARD_INSERT     = (1 << 30),
+    SD_RISR_AUTOCMD_DONE    = (1 << 14),
+    SD_RISR_DATA_COMPLETE   = (1 << 3),
+    SD_RISR_CMD_COMPLETE    = (1 << 2),
+    SD_RISR_NO_RESPONSE     = (1 << 1),
+};
+
+enum {
+    SD_STAR_CARD_PRESENT    = (1 << 8),
+};
+
+enum {
+    SD_IDST_SUM_RECEIVE_IRQ = (1 << 8),
+    SD_IDST_RECEIVE_IRQ     = (1 << 1),
+    SD_IDST_TRANSMIT_IRQ    = (1 << 0),
+    SD_IDST_IRQ_MASK        = (1 << 1) | (1 << 0) | (1 << 8),
+    SD_IDST_WR_MASK         = (0x3ff),
+};
+
+/* SD Host register reset values */
+enum {
+    REG_SD_GCTL_RST         = 0x00000300,
+    REG_SD_CKCR_RST         = 0x0,
+    REG_SD_TMOR_RST         = 0xFFFFFF40,
+    REG_SD_BWDR_RST         = 0x0,
+    REG_SD_BKSR_RST         = 0x00000200,
+    REG_SD_BYCR_RST         = 0x00000200,
+    REG_SD_CMDR_RST         = 0x0,
+    REG_SD_CAGR_RST         = 0x0,
+    REG_SD_RESP_RST         = 0x0,
+    REG_SD_IMKR_RST         = 0x0,
+    REG_SD_MISR_RST         = 0x0,
+    REG_SD_RISR_RST         = 0x0,
+    REG_SD_STAR_RST         = 0x00000100,
+    REG_SD_FWLR_RST         = 0x000F0000,
+    REG_SD_FUNS_RST         = 0x0,
+    REG_SD_DBGC_RST         = 0x0,
+    REG_SD_A12A_RST         = 0x0000FFFF,
+    REG_SD_NTSR_RST         = 0x00000001,
+    REG_SD_SDBG_RST         = 0x0,
+    REG_SD_HWRST_RST        = 0x00000001,
+    REG_SD_DMAC_RST         = 0x0,
+    REG_SD_DLBA_RST         = 0x0,
+    REG_SD_IDST_RST         = 0x0,
+    REG_SD_IDIE_RST         = 0x0,
+    REG_SD_THLDC_RST        = 0x0,
+    REG_SD_DSBD_RST         = 0x0,
+    REG_SD_RES_CRC_RST      = 0x0,
+    REG_SD_DATA_CRC_RST     = 0x0,
+    REG_SD_CRC_STA_RST      = 0x0,
+    REG_SD_FIFO_RST         = 0x0,
+};
+
+/* Data transfer descriptor for DMA */
+typedef struct TransferDescriptor {
+    uint32_t status; /* Status flags */
+    uint32_t size;   /* Data buffer size */
+    uint32_t addr;   /* Data buffer address */
+    uint32_t next;   /* Physical address of next descriptor */
+} TransferDescriptor;
+
+/* Data transfer descriptor flags */
+enum {
+    DESC_STATUS_HOLD   = (1 << 31), /* Set when descriptor is in use by DMA */
+    DESC_STATUS_ERROR  = (1 << 30), /* Set when DMA transfer error occurred */
+    DESC_STATUS_CHAIN  = (1 << 4),  /* Indicates chained descriptor. */
+    DESC_STATUS_FIRST  = (1 << 3),  /* Set on the first descriptor */
+    DESC_STATUS_LAST   = (1 << 2),  /* Set on the last descriptor */
+    DESC_STATUS_NOIRQ  = (1 << 1),  /* Skip raising interrupt after transfer */
+    DESC_SIZE_MASK     = (0xfffffffc)
+};
+
+static void aw_h3_sdhost_update_irq(AwH3SDHostState *s)
+{
+    uint32_t irq;
+
+    if (s->global_ctl & SD_GCTL_INT_ENB) {
+        irq = s->irq_status & s->irq_mask;
+    } else {
+        irq = 0;
+    }
+
+    trace_aw_h3_sdhost_update_irq(irq);
+    qemu_set_irq(s->irq, irq);
+}
+
+static void aw_h3_sdhost_update_transfer_cnt(AwH3SDHostState *s, uint32_t bytes)
+{
+    if (s->transfer_cnt > bytes) {
+        s->transfer_cnt -= bytes;
+    } else {
+        s->transfer_cnt = 0;
+    }
+
+    if (!s->transfer_cnt) {
+        s->irq_status |= SD_RISR_DATA_COMPLETE | SD_RISR_AUTOCMD_DONE;
+    }
+}
+
+static void aw_h3_sdhost_set_inserted(DeviceState *dev, bool inserted)
+{
+    AwH3SDHostState *s = AW_H3_SDHOST(dev);
+
+    trace_aw_h3_sdhost_set_inserted(inserted);
+
+    if (inserted) {
+        s->irq_status |= SD_RISR_CARD_INSERT;
+        s->irq_status &= ~SD_RISR_CARD_REMOVE;
+        s->status |= SD_STAR_CARD_PRESENT;
+    } else {
+        s->irq_status &= ~SD_RISR_CARD_INSERT;
+        s->irq_status |= SD_RISR_CARD_REMOVE;
+        s->status &= ~SD_STAR_CARD_PRESENT;
+    }
+
+    aw_h3_sdhost_update_irq(s);
+}
+
+static void aw_h3_sdhost_send_command(AwH3SDHostState *s)
+{
+    SDRequest request;
+    uint8_t resp[16];
+    int rlen;
+
+    /* Auto clear load flag */
+    s->command &= ~SD_CMDR_LOAD;
+
+    /* Clock change does not actually interact with the SD bus */
+    if (!(s->command & SD_CMDR_CLKCHANGE)) {
+
+        /* Prepare request */
+        request.cmd = s->command & SD_CMDR_CMDID_MASK;
+        request.arg = s->command_arg;
+
+        /* Send request to SD bus */
+        rlen = sdbus_do_command(&s->sdbus, &request, resp);
+        if (rlen < 0) {
+            goto error;
+        }
+
+        /* If the command has a response, store it in the response registers */
+        if ((s->command & SD_CMDR_RESPONSE)) {
+            if (rlen == 4 && !(s->command & SD_CMDR_RESPONSE_LONG)) {
+                s->response[0] = ldl_be_p(&resp[0]);
+                s->response[1] = s->response[2] = s->response[3] = 0;
+
+            } else if (rlen == 16 && (s->command & SD_CMDR_RESPONSE_LONG)) {
+                s->response[0] = ldl_be_p(&resp[12]);
+                s->response[1] = ldl_be_p(&resp[8]);
+                s->response[2] = ldl_be_p(&resp[4]);
+                s->response[3] = ldl_be_p(&resp[0]);
+            } else {
+                goto error;
+            }
+        }
+    }
+
+    /* Set interrupt status bits */
+    s->irq_status |= SD_RISR_CMD_COMPLETE;
+    return;
+
+error:
+    s->irq_status |= SD_RISR_NO_RESPONSE;
+}
+
+static void aw_h3_sdhost_auto_stop(AwH3SDHostState *s)
+{
+    /*
+     * The stop command (CMD12) ensures the SD bus
+     * returns to the transfer state.
+     */
+    if ((s->command & SD_CMDR_AUTOSTOP) && (s->transfer_cnt == 0)) {
+        /* First save current command registers */
+        uint32_t saved_cmd = s->command;
+        uint32_t saved_arg = s->command_arg;
+
+        /* Prepare stop command (CMD12) */
+        s->command &= ~SD_CMDR_CMDID_MASK;
+        s->command |= 12; /* CMD12 */
+        s->command_arg = 0;
+
+        /* Put the command on SD bus */
+        aw_h3_sdhost_send_command(s);
+
+        /* Restore command values */
+        s->command = saved_cmd;
+        s->command_arg = saved_arg;
+    }
+}
+
+static uint32_t aw_h3_sdhost_process_desc(AwH3SDHostState *s,
+                                          hwaddr desc_addr,
+                                          TransferDescriptor *desc,
+                                          bool is_write, uint32_t max_bytes)
+{
+    uint32_t num_done = 0;
+    uint32_t num_bytes = max_bytes;
+    uint8_t buf[1024];
+
+    /* Read descriptor */
+    cpu_physical_memory_read(desc_addr, desc, sizeof(*desc));
+    if (desc->size == 0) {
+        desc->size = 64 * KiB;
+    }
+    if (desc->size < num_bytes) {
+        num_bytes = desc->size;
+    }
+
+    trace_aw_h3_sdhost_process_desc(desc_addr, desc->size, is_write, max_bytes);
+
+    while (num_done < num_bytes) {
+        /* Try to completely fill the local buffer */
+        uint32_t buf_bytes = num_bytes - num_done;
+        if (buf_bytes > sizeof(buf)) {
+            buf_bytes = sizeof(buf);
+        }
+
+        /* Write to SD bus */
+        if (is_write) {
+            cpu_physical_memory_read((desc->addr & DESC_SIZE_MASK) + num_done,
+                                      buf, buf_bytes);
+
+            for (uint32_t i = 0; i < buf_bytes; i++) {
+                sdbus_write_data(&s->sdbus, buf[i]);
+            }
+
+        /* Read from SD bus */
+        } else {
+            for (uint32_t i = 0; i < buf_bytes; i++) {
+                buf[i] = sdbus_read_data(&s->sdbus);
+            }
+            cpu_physical_memory_write((desc->addr & DESC_SIZE_MASK) + num_done,
+                                       buf, buf_bytes);
+        }
+        num_done += buf_bytes;
+    }
+
+    /* Clear hold flag and flush descriptor */
+    desc->status &= ~DESC_STATUS_HOLD;
+    cpu_physical_memory_write(desc_addr, desc, sizeof(*desc));
+
+    return num_done;
+}
+
+static void aw_h3_sdhost_dma(AwH3SDHostState *s)
+{
+    TransferDescriptor desc;
+    hwaddr desc_addr = s->desc_base;
+    bool is_write = (s->command & SD_CMDR_WRITE);
+    uint32_t bytes_done = 0;
+
+    /* Check if DMA can be performed */
+    if (s->byte_count == 0 || s->block_size == 0 ||
+      !(s->global_ctl & SD_GCTL_DMA_ENB)) {
+        return;
+    }
+
+    /*
+     * For read operations, data must be available on the SD bus
+     * If not, it is an error and we should not act at all
+     */
+    if (!is_write && !sdbus_data_ready(&s->sdbus)) {
+        return;
+    }
+
+    /* Process the DMA descriptors until all data is copied */
+    while (s->byte_count > 0) {
+        bytes_done = aw_h3_sdhost_process_desc(s, desc_addr, &desc,
+                                               is_write, s->byte_count);
+        aw_h3_sdhost_update_transfer_cnt(s, bytes_done);
+
+        if (bytes_done <= s->byte_count) {
+            s->byte_count -= bytes_done;
+        } else {
+            s->byte_count = 0;
+        }
+
+        if (desc.status & DESC_STATUS_LAST) {
+            break;
+        } else {
+            desc_addr = desc.next;
+        }
+    }
+
+    /* Raise IRQ to signal DMA is completed */
+    s->irq_status |= SD_RISR_DATA_COMPLETE | SD_RISR_AUTOCMD_DONE;
+
+    /* Update DMAC bits */
+    if (is_write) {
+        s->dmac_status |= SD_IDST_TRANSMIT_IRQ;
+    } else {
+        s->dmac_status |= (SD_IDST_SUM_RECEIVE_IRQ | SD_IDST_RECEIVE_IRQ);
+    }
+}
+
+static uint64_t aw_h3_sdhost_read(void *opaque, hwaddr offset,
+                                  unsigned size)
+{
+    AwH3SDHostState *s = (AwH3SDHostState *)opaque;
+    uint32_t res = 0;
+
+    switch (offset) {
+    case REG_SD_GCTL:      /* Global Control */
+        res = s->global_ctl;
+        break;
+    case REG_SD_CKCR:      /* Clock Control */
+        res = s->clock_ctl;
+        break;
+    case REG_SD_TMOR:      /* Timeout */
+        res = s->timeout;
+        break;
+    case REG_SD_BWDR:      /* Bus Width */
+        res = s->bus_width;
+        break;
+    case REG_SD_BKSR:      /* Block Size */
+        res = s->block_size;
+        break;
+    case REG_SD_BYCR:      /* Byte Count */
+        res = s->byte_count;
+        break;
+    case REG_SD_CMDR:      /* Command */
+        res = s->command;
+        break;
+    case REG_SD_CAGR:      /* Command Argument */
+        res = s->command_arg;
+        break;
+    case REG_SD_RESP0:     /* Response Zero */
+        res = s->response[0];
+        break;
+    case REG_SD_RESP1:     /* Response One */
+        res = s->response[1];
+        break;
+    case REG_SD_RESP2:     /* Response Two */
+        res = s->response[2];
+        break;
+    case REG_SD_RESP3:     /* Response Three */
+        res = s->response[3];
+        break;
+    case REG_SD_IMKR:      /* Interrupt Mask */
+        res = s->irq_mask;
+        break;
+    case REG_SD_MISR:      /* Masked Interrupt Status */
+        res = s->irq_status & s->irq_mask;
+        break;
+    case REG_SD_RISR:      /* Raw Interrupt Status */
+        res = s->irq_status;
+        break;
+    case REG_SD_STAR:      /* Status */
+        res = s->status;
+        break;
+    case REG_SD_FWLR:      /* FIFO Water Level */
+        res = s->fifo_wlevel;
+        break;
+    case REG_SD_FUNS:      /* FIFO Function Select */
+        res = s->fifo_func_sel;
+        break;
+    case REG_SD_DBGC:      /* Debug Enable */
+        res = s->debug_enable;
+        break;
+    case REG_SD_A12A:      /* Auto command 12 argument */
+        res = s->auto12_arg;
+        break;
+    case REG_SD_NTSR:      /* SD NewTiming Set */
+        res = s->newtiming_set;
+        break;
+    case REG_SD_SDBG:      /* SD newTiming Set Debug */
+        res = s->newtiming_debug;
+        break;
+    case REG_SD_HWRST:     /* Hardware Reset Register */
+        res = s->hardware_rst;
+        break;
+    case REG_SD_DMAC:      /* Internal DMA Controller Control */
+        res = s->dmac;
+        break;
+    case REG_SD_DLBA:      /* Descriptor List Base Address */
+        res = s->desc_base;
+        break;
+    case REG_SD_IDST:      /* Internal DMA Controller Status */
+        res = s->dmac_status;
+        break;
+    case REG_SD_IDIE:      /* Internal DMA Controller Interrupt Enable */
+        res = s->dmac_irq;
+        break;
+    case REG_SD_THLDC:     /* Card Threshold Control */
+        res = s->card_threshold;
+        break;
+    case REG_SD_DSBD:      /* eMMC DDR Start Bit Detection Control */
+        res = s->startbit_detect;
+        break;
+    case REG_SD_RES_CRC:   /* Response CRC from card/eMMC */
+        res = s->response_crc;
+        break;
+    case REG_SD_DATA7_CRC: /* CRC Data 7 from card/eMMC */
+    case REG_SD_DATA6_CRC: /* CRC Data 6 from card/eMMC */
+    case REG_SD_DATA5_CRC: /* CRC Data 5 from card/eMMC */
+    case REG_SD_DATA4_CRC: /* CRC Data 4 from card/eMMC */
+    case REG_SD_DATA3_CRC: /* CRC Data 3 from card/eMMC */
+    case REG_SD_DATA2_CRC: /* CRC Data 2 from card/eMMC */
+    case REG_SD_DATA1_CRC: /* CRC Data 1 from card/eMMC */
+    case REG_SD_DATA0_CRC: /* CRC Data 0 from card/eMMC */
+        res = s->data_crc[((offset - REG_SD_DATA7_CRC) / sizeof(uint32_t))];
+        break;
+    case REG_SD_CRC_STA:   /* CRC status from card/eMMC in write operation */
+        res = s->status_crc;
+        break;
+    case REG_SD_FIFO:      /* Read/Write FIFO */
+        if (sdbus_data_ready(&s->sdbus)) {
+            res = sdbus_read_data(&s->sdbus);
+            res |= sdbus_read_data(&s->sdbus) << 8;
+            res |= sdbus_read_data(&s->sdbus) << 16;
+            res |= sdbus_read_data(&s->sdbus) << 24;
+            aw_h3_sdhost_update_transfer_cnt(s, sizeof(uint32_t));
+            aw_h3_sdhost_auto_stop(s);
+            aw_h3_sdhost_update_irq(s);
+        } else {
+            qemu_log_mask(LOG_GUEST_ERROR, "%s: no data ready on SD bus\n",
+                          __func__);
+        }
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
+                      __func__, offset);
+        res = 0;
+        break;
+    }
+
+    trace_aw_h3_sdhost_read(offset, res, size);
+    return res;
+}
+
+static void aw_h3_sdhost_write(void *opaque, hwaddr offset,
+                               uint64_t value, unsigned size)
+{
+    AwH3SDHostState *s = (AwH3SDHostState *)opaque;
+
+    trace_aw_h3_sdhost_write(offset, value, size);
+
+    switch (offset) {
+    case REG_SD_GCTL:      /* Global Control */
+        s->global_ctl = value;
+        s->global_ctl &= ~(SD_GCTL_DMA_RST | SD_GCTL_FIFO_RST |
+                           SD_GCTL_SOFT_RST);
+        aw_h3_sdhost_update_irq(s);
+        break;
+    case REG_SD_CKCR:      /* Clock Control */
+        s->clock_ctl = value;
+        break;
+    case REG_SD_TMOR:      /* Timeout */
+        s->timeout = value;
+        break;
+    case REG_SD_BWDR:      /* Bus Width */
+        s->bus_width = value;
+        break;
+    case REG_SD_BKSR:      /* Block Size */
+        s->block_size = value;
+        break;
+    case REG_SD_BYCR:      /* Byte Count */
+        s->byte_count = value;
+        s->transfer_cnt = value;
+        break;
+    case REG_SD_CMDR:      /* Command */
+        s->command = value;
+        if (value & SD_CMDR_LOAD) {
+            aw_h3_sdhost_send_command(s);
+            aw_h3_sdhost_dma(s);
+            aw_h3_sdhost_auto_stop(s);
+        }
+        aw_h3_sdhost_update_irq(s);
+        break;
+    case REG_SD_CAGR:      /* Command Argument */
+        s->command_arg = value;
+        break;
+    case REG_SD_RESP0:     /* Response Zero */
+        s->response[0] = value;
+        break;
+    case REG_SD_RESP1:     /* Response One */
+        s->response[1] = value;
+        break;
+    case REG_SD_RESP2:     /* Response Two */
+        s->response[2] = value;
+        break;
+    case REG_SD_RESP3:     /* Response Three */
+        s->response[3] = value;
+        break;
+    case REG_SD_IMKR:      /* Interrupt Mask */
+        s->irq_mask = value;
+        aw_h3_sdhost_update_irq(s);
+        break;
+    case REG_SD_MISR:      /* Masked Interrupt Status */
+    case REG_SD_RISR:      /* Raw Interrupt Status */
+        s->irq_status &= ~value;
+        aw_h3_sdhost_update_irq(s);
+        break;
+    case REG_SD_STAR:      /* Status */
+        s->status &= ~value;
+        aw_h3_sdhost_update_irq(s);
+        break;
+    case REG_SD_FWLR:      /* FIFO Water Level */
+        s->fifo_wlevel = value;
+        break;
+    case REG_SD_FUNS:      /* FIFO Function Select */
+        s->fifo_func_sel = value;
+        break;
+    case REG_SD_DBGC:      /* Debug Enable */
+        s->debug_enable = value;
+        break;
+    case REG_SD_A12A:      /* Auto command 12 argument */
+        s->auto12_arg = value;
+        break;
+    case REG_SD_NTSR:      /* SD NewTiming Set */
+        s->newtiming_set = value;
+        break;
+    case REG_SD_SDBG:      /* SD newTiming Set Debug */
+        s->newtiming_debug = value;
+        break;
+    case REG_SD_HWRST:     /* Hardware Reset Register */
+        s->hardware_rst = value;
+        break;
+    case REG_SD_DMAC:      /* Internal DMA Controller Control */
+        s->dmac = value;
+        aw_h3_sdhost_update_irq(s);
+        break;
+    case REG_SD_DLBA:      /* Descriptor List Base Address */
+        s->desc_base = value;
+        break;
+    case REG_SD_IDST:      /* Internal DMA Controller Status */
+        s->dmac_status &= (~SD_IDST_WR_MASK) | (~value & SD_IDST_WR_MASK);
+        aw_h3_sdhost_update_irq(s);
+        break;
+    case REG_SD_IDIE:      /* Internal DMA Controller Interrupt Enable */
+        s->dmac_irq = value;
+        aw_h3_sdhost_update_irq(s);
+        break;
+    case REG_SD_THLDC:     /* Card Threshold Control */
+        s->card_threshold = value;
+        break;
+    case REG_SD_DSBD:      /* eMMC DDR Start Bit Detection Control */
+        s->startbit_detect = value;
+        break;
+    case REG_SD_FIFO:      /* Read/Write FIFO */
+        sdbus_write_data(&s->sdbus, value & 0xff);
+        sdbus_write_data(&s->sdbus, (value >> 8) & 0xff);
+        sdbus_write_data(&s->sdbus, (value >> 16) & 0xff);
+        sdbus_write_data(&s->sdbus, (value >> 24) & 0xff);
+        aw_h3_sdhost_update_transfer_cnt(s, sizeof(uint32_t));
+        aw_h3_sdhost_auto_stop(s);
+        aw_h3_sdhost_update_irq(s);
+        break;
+    case REG_SD_RES_CRC:   /* Response CRC from card/eMMC */
+    case REG_SD_DATA7_CRC: /* CRC Data 7 from card/eMMC */
+    case REG_SD_DATA6_CRC: /* CRC Data 6 from card/eMMC */
+    case REG_SD_DATA5_CRC: /* CRC Data 5 from card/eMMC */
+    case REG_SD_DATA4_CRC: /* CRC Data 4 from card/eMMC */
+    case REG_SD_DATA3_CRC: /* CRC Data 3 from card/eMMC */
+    case REG_SD_DATA2_CRC: /* CRC Data 2 from card/eMMC */
+    case REG_SD_DATA1_CRC: /* CRC Data 1 from card/eMMC */
+    case REG_SD_DATA0_CRC: /* CRC Data 0 from card/eMMC */
+    case REG_SD_CRC_STA:   /* CRC status from card/eMMC in write operation */
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
+                      __func__, offset);
+        break;
+    }
+}
+
+static const MemoryRegionOps aw_h3_sdhost_ops = {
+    .read = aw_h3_sdhost_read,
+    .write = aw_h3_sdhost_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+        .unaligned = false
+    },
+    .impl.min_access_size = 4,
+};
+
+static const VMStateDescription vmstate_aw_h3_sdhost = {
+    .name = "allwinner-h3-sdhost",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(global_ctl, AwH3SDHostState),
+        VMSTATE_UINT32(clock_ctl, AwH3SDHostState),
+        VMSTATE_UINT32(timeout, AwH3SDHostState),
+        VMSTATE_UINT32(bus_width, AwH3SDHostState),
+        VMSTATE_UINT32(block_size, AwH3SDHostState),
+        VMSTATE_UINT32(byte_count, AwH3SDHostState),
+        VMSTATE_UINT32(transfer_cnt, AwH3SDHostState),
+        VMSTATE_UINT32(command, AwH3SDHostState),
+        VMSTATE_UINT32(command_arg, AwH3SDHostState),
+        VMSTATE_UINT32_ARRAY(response, AwH3SDHostState, 4),
+        VMSTATE_UINT32(irq_mask, AwH3SDHostState),
+        VMSTATE_UINT32(irq_status, AwH3SDHostState),
+        VMSTATE_UINT32(status, AwH3SDHostState),
+        VMSTATE_UINT32(fifo_wlevel, AwH3SDHostState),
+        VMSTATE_UINT32(fifo_func_sel, AwH3SDHostState),
+        VMSTATE_UINT32(debug_enable, AwH3SDHostState),
+        VMSTATE_UINT32(auto12_arg, AwH3SDHostState),
+        VMSTATE_UINT32(newtiming_set, AwH3SDHostState),
+        VMSTATE_UINT32(newtiming_debug, AwH3SDHostState),
+        VMSTATE_UINT32(hardware_rst, AwH3SDHostState),
+        VMSTATE_UINT32(dmac, AwH3SDHostState),
+        VMSTATE_UINT32(desc_base, AwH3SDHostState),
+        VMSTATE_UINT32(dmac_status, AwH3SDHostState),
+        VMSTATE_UINT32(dmac_irq, AwH3SDHostState),
+        VMSTATE_UINT32(card_threshold, AwH3SDHostState),
+        VMSTATE_UINT32(startbit_detect, AwH3SDHostState),
+        VMSTATE_UINT32(response_crc, AwH3SDHostState),
+        VMSTATE_UINT32_ARRAY(data_crc, AwH3SDHostState, 8),
+        VMSTATE_UINT32(status_crc, AwH3SDHostState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void aw_h3_sdhost_init(Object *obj)
+{
+    AwH3SDHostState *s = AW_H3_SDHOST(obj);
+
+    qbus_create_inplace(&s->sdbus, sizeof(s->sdbus),
+                        TYPE_AW_H3_SDHOST_BUS, DEVICE(s), "sd-bus");
+
+    memory_region_init_io(&s->iomem, obj, &aw_h3_sdhost_ops, s,
+                          TYPE_AW_H3_SDHOST, 4 * KiB);
+    sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
+    sysbus_init_irq(SYS_BUS_DEVICE(s), &s->irq);
+}
+
+static void aw_h3_sdhost_reset(DeviceState *dev)
+{
+    AwH3SDHostState *s = AW_H3_SDHOST(dev);
+
+    s->global_ctl = REG_SD_GCTL_RST;
+    s->clock_ctl = REG_SD_CKCR_RST;
+    s->timeout = REG_SD_TMOR_RST;
+    s->bus_width = REG_SD_BWDR_RST;
+    s->block_size = REG_SD_BKSR_RST;
+    s->byte_count = REG_SD_BYCR_RST;
+    s->transfer_cnt = 0;
+
+    s->command = REG_SD_CMDR_RST;
+    s->command_arg = REG_SD_CAGR_RST;
+
+    for (int i = 0; i < ARRAY_SIZE(s->response); i++) {
+        s->response[i] = REG_SD_RESP_RST;
+    }
+
+    s->irq_mask = REG_SD_IMKR_RST;
+    s->irq_status = REG_SD_RISR_RST;
+    s->status = REG_SD_STAR_RST;
+
+    s->fifo_wlevel = REG_SD_FWLR_RST;
+    s->fifo_func_sel = REG_SD_FUNS_RST;
+    s->debug_enable = REG_SD_DBGC_RST;
+    s->auto12_arg = REG_SD_A12A_RST;
+    s->newtiming_set = REG_SD_NTSR_RST;
+    s->newtiming_debug = REG_SD_SDBG_RST;
+    s->hardware_rst = REG_SD_HWRST_RST;
+    s->dmac = REG_SD_DMAC_RST;
+    s->desc_base = REG_SD_DLBA_RST;
+    s->dmac_status = REG_SD_IDST_RST;
+    s->dmac_irq = REG_SD_IDIE_RST;
+    s->card_threshold = REG_SD_THLDC_RST;
+    s->startbit_detect = REG_SD_DSBD_RST;
+    s->response_crc = REG_SD_RES_CRC_RST;
+
+    for (int i = 0; i < ARRAY_SIZE(s->data_crc); i++) {
+        s->data_crc[i] = REG_SD_DATA_CRC_RST;
+    }
+
+    s->status_crc = REG_SD_CRC_STA_RST;
+}
+
+static void aw_h3_sdhost_bus_class_init(ObjectClass *klass, void *data)
+{
+    SDBusClass *sbc = SD_BUS_CLASS(klass);
+
+    sbc->set_inserted = aw_h3_sdhost_set_inserted;
+}
+
+static void aw_h3_sdhost_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->reset = aw_h3_sdhost_reset;
+    dc->vmsd = &vmstate_aw_h3_sdhost;
+}
+
+static TypeInfo aw_h3_sdhost_info = {
+    .name          = TYPE_AW_H3_SDHOST,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(AwH3SDHostState),
+    .class_init    = aw_h3_sdhost_class_init,
+    .instance_init = aw_h3_sdhost_init,
+};
+
+static const TypeInfo aw_h3_sdhost_bus_info = {
+    .name = TYPE_AW_H3_SDHOST_BUS,
+    .parent = TYPE_SD_BUS,
+    .instance_size = sizeof(SDBus),
+    .class_init = aw_h3_sdhost_bus_class_init,
+};
+
+static void aw_h3_sdhost_register_types(void)
+{
+    type_register_static(&aw_h3_sdhost_info);
+    type_register_static(&aw_h3_sdhost_bus_info);
+}
+
+type_init(aw_h3_sdhost_register_types)
diff --git a/hw/sd/Makefile.objs b/hw/sd/Makefile.objs
index a884c238df..e7cc5ab739 100644
--- a/hw/sd/Makefile.objs
+++ b/hw/sd/Makefile.objs
@@ -4,6 +4,7 @@ common-obj-$(CONFIG_SD) += sd.o core.o sdmmc-internal.o
 common-obj-$(CONFIG_SDHCI) += sdhci.o
 common-obj-$(CONFIG_SDHCI_PCI) += sdhci-pci.o
 
+obj-$(CONFIG_ALLWINNER_H3) += allwinner-h3-sdhost.o
 obj-$(CONFIG_MILKYMIST) += milkymist-memcard.o
 obj-$(CONFIG_OMAP) += omap_mmc.o
 obj-$(CONFIG_PXA2XX) += pxa2xx_mmci.o
diff --git a/hw/sd/trace-events b/hw/sd/trace-events
index efcff666a2..5016cefc78 100644
--- a/hw/sd/trace-events
+++ b/hw/sd/trace-events
@@ -1,5 +1,12 @@
 # See docs/devel/tracing.txt for syntax documentation.
 
+# allwinner-h3-sdhost.c
+aw_h3_sdhost_set_inserted(bool inserted) "inserted %u"
+aw_h3_sdhost_process_desc(uint64_t desc_addr, uint32_t desc_size, bool is_write, uint32_t max_bytes) "desc_addr 0x%" PRIx64 " desc_size %" PRIu32 " is_write %u max_bytes %" PRIu32
+aw_h3_sdhost_read(uint64_t offset, uint64_t data, unsigned size) "offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32
+aw_h3_sdhost_write(uint64_t offset, uint64_t data, unsigned size) "offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32
+aw_h3_sdhost_update_irq(uint32_t irq) "IRQ bits 0x%" PRIx32
+
 # bcm2835_sdhost.c
 bcm2835_sdhost_read(uint64_t offset, uint64_t data, unsigned size) "offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
 bcm2835_sdhost_write(uint64_t offset, uint64_t data, unsigned size) "offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
-- 
2.17.1



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

* [PATCH v2 10/10] arm: allwinner-h3: add EMAC ethernet device
  2019-12-16 23:35 [PATCH v2 00/10] Add Allwinner H3 SoC and Orange Pi PC Machine Niek Linnenbank
                   ` (8 preceding siblings ...)
  2019-12-16 23:35 ` [PATCH v2 09/10] arm: allwinner-h3: add SD/MMC host controller Niek Linnenbank
@ 2019-12-16 23:35 ` Niek Linnenbank
  2019-12-30 11:28 ` [PATCH v2 00/10] Add Allwinner H3 SoC and Orange Pi PC Machine Niek Linnenbank
  10 siblings, 0 replies; 30+ messages in thread
From: Niek Linnenbank @ 2019-12-16 23:35 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, Niek Linnenbank, qemu-arm, philmd

The Allwinner H3 System on Chip includes an Ethernet MAC (EMAC)
which provides 10M/100M/1000M Ethernet connectivity. This commit
adds support for the Allwinner H3 EMAC, including emulation for
the following functionality:

 * DMA transfers
 * MII interface
 * Transmit CRC calculation

Signed-off-by: Niek Linnenbank <nieklinnenbank@gmail.com>
---
 include/hw/arm/allwinner-h3.h      |   2 +
 include/hw/net/allwinner-h3-emac.h |  67 +++
 hw/arm/allwinner-h3.c              |  13 +
 hw/arm/orangepi.c                  |   7 +
 hw/net/allwinner-h3-emac.c         | 831 +++++++++++++++++++++++++++++
 hw/arm/Kconfig                     |   1 +
 hw/net/Kconfig                     |   3 +
 hw/net/Makefile.objs               |   1 +
 hw/net/trace-events                |  10 +
 9 files changed, 935 insertions(+)
 create mode 100644 include/hw/net/allwinner-h3-emac.h
 create mode 100644 hw/net/allwinner-h3-emac.c

diff --git a/include/hw/arm/allwinner-h3.h b/include/hw/arm/allwinner-h3.h
index ab564987be..357bdfa711 100644
--- a/include/hw/arm/allwinner-h3.h
+++ b/include/hw/arm/allwinner-h3.h
@@ -31,6 +31,7 @@
 #include "hw/misc/allwinner-h3-syscon.h"
 #include "hw/misc/allwinner-h3-sid.h"
 #include "hw/sd/allwinner-h3-sdhost.h"
+#include "hw/net/allwinner-h3-emac.h"
 #include "target/arm/cpu.h"
 
 enum {
@@ -81,6 +82,7 @@ typedef struct AwH3State {
     AwH3SysconState syscon;
     AwH3SidState sid;
     AwH3SDHostState mmc0;
+    AwH3EmacState emac;
     GICState gic;
     MemoryRegion sram_a1;
     MemoryRegion sram_a2;
diff --git a/include/hw/net/allwinner-h3-emac.h b/include/hw/net/allwinner-h3-emac.h
new file mode 100644
index 0000000000..8fb2bd6e87
--- /dev/null
+++ b/include/hw/net/allwinner-h3-emac.h
@@ -0,0 +1,67 @@
+/*
+ * Allwinner H3 EMAC emulation
+ *
+ * Copyright (C) 2019 Niek Linnenbank <nieklinnenbank@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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 ALLWINNER_H3_EMAC_H
+#define ALLWINNER_H3_EMAC_H
+
+#include "qemu/units.h"
+#include "net/net.h"
+#include "qemu/fifo8.h"
+#include "hw/net/mii.h"
+#include "hw/sysbus.h"
+
+#define TYPE_AW_H3_EMAC "allwinner-h3-emac"
+#define AW_H3_EMAC(obj) OBJECT_CHECK(AwH3EmacState, (obj), TYPE_AW_H3_EMAC)
+
+typedef struct AwH3EmacState {
+    /*< private >*/
+    SysBusDevice  parent_obj;
+    /*< public >*/
+
+    MemoryRegion iomem;
+    qemu_irq     irq;
+    NICState     *nic;
+    NICConf      conf;
+
+    uint8_t      mii_phy_addr;
+    uint32_t     mii_cmd;
+    uint32_t     mii_data;
+    uint32_t     mii_cr;
+    uint32_t     mii_st;
+
+    uint32_t     basic_ctl0;
+    uint32_t     basic_ctl1;
+    uint32_t     int_en;
+    uint32_t     int_sta;
+    uint32_t     frm_flt;
+
+    uint32_t     rx_ctl0;
+    uint32_t     rx_ctl1;
+    uint32_t     rx_desc_head;
+    uint32_t     rx_desc_curr;
+
+    uint32_t     tx_ctl0;
+    uint32_t     tx_ctl1;
+    uint32_t     tx_desc_head;
+    uint32_t     tx_desc_curr;
+    uint32_t     tx_flowctl;
+
+} AwH3EmacState;
+
+#endif
diff --git a/hw/arm/allwinner-h3.c b/hw/arm/allwinner-h3.c
index b4ee524ee0..b49f8d81ac 100644
--- a/hw/arm/allwinner-h3.c
+++ b/hw/arm/allwinner-h3.c
@@ -202,6 +202,9 @@ static void aw_h3_init(Object *obj)
 
     sysbus_init_child_obj(obj, "mmc0", &s->mmc0, sizeof(s->mmc0),
                           TYPE_AW_H3_SDHOST);
+
+    sysbus_init_child_obj(obj, "emac", &s->emac, sizeof(s->emac),
+                          TYPE_AW_H3_EMAC);
 }
 
 static void aw_h3_realize(DeviceState *dev, Error **errp)
@@ -355,6 +358,16 @@ static void aw_h3_realize(DeviceState *dev, Error **errp)
         return;
     }
 
+    /* EMAC */
+    if (nd_table[0].used) {
+        qemu_check_nic_model(&nd_table[0], TYPE_AW_H3_EMAC);
+        qdev_set_nic_properties(DEVICE(&s->emac), &nd_table[0]);
+    }
+    qdev_init_nofail(DEVICE(&s->emac));
+    sysbus_mmio_map(SYS_BUS_DEVICE(&s->emac), 0, s->memmap[AW_H3_EMAC]);
+    sysbus_connect_irq(SYS_BUS_DEVICE(&s->emac), 0,
+                       qdev_get_gpio_in(DEVICE(&s->gic), AW_H3_GIC_SPI_EMAC));
+
     /* Universal Serial Bus */
     sysbus_create_simple(TYPE_AW_H3_EHCI, s->memmap[AW_H3_EHCI0],
                          qdev_get_gpio_in(DEVICE(&s->gic),
diff --git a/hw/arm/orangepi.c b/hw/arm/orangepi.c
index 87968505ae..119f370924 100644
--- a/hw/arm/orangepi.c
+++ b/hw/arm/orangepi.c
@@ -70,6 +70,13 @@ static void orangepi_init(MachineState *machine)
     qdev_prop_set_string(DEVICE(&s->h3->sid), "identifier",
                          "8100c002-0001-0002-0003-000044556677");
 
+    /* Setup EMAC properties */
+    object_property_set_int(OBJECT(&s->h3->emac), 1, "phy-addr", &error_abort);
+    if (error_abort != NULL) {
+        error_reportf_err(error_abort, "Couldn't set phy address: ");
+        exit(1);
+    }
+
     /* Mark H3 object realized */
     object_property_set_bool(OBJECT(s->h3), true, "realized", &error_abort);
     if (error_abort != NULL) {
diff --git a/hw/net/allwinner-h3-emac.c b/hw/net/allwinner-h3-emac.c
new file mode 100644
index 0000000000..7a0daced83
--- /dev/null
+++ b/hw/net/allwinner-h3-emac.c
@@ -0,0 +1,831 @@
+/*
+ * Allwinner H3 EMAC emulation
+ *
+ * Copyright (C) 2019 Niek Linnenbank <nieklinnenbank@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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/units.h"
+#include "hw/sysbus.h"
+#include "migration/vmstate.h"
+#include "net/net.h"
+#include "hw/irq.h"
+#include "hw/qdev-properties.h"
+#include "qemu/log.h"
+#include "trace.h"
+#include "net/checksum.h"
+#include "qemu/module.h"
+#include "exec/cpu-common.h"
+#include "hw/net/allwinner-h3-emac.h"
+
+/* EMAC register offsets */
+enum {
+    REG_BASIC_CTL_0        = 0x0000, /* Basic Control 0 */
+    REG_BASIC_CTL_1        = 0x0004, /* Basic Control 1 */
+    REG_INT_STA            = 0x0008, /* Interrupt Status */
+    REG_INT_EN             = 0x000C, /* Interrupt Enable */
+    REG_TX_CTL_0           = 0x0010, /* Transmit Control 0 */
+    REG_TX_CTL_1           = 0x0014, /* Transmit Control 1 */
+    REG_TX_FLOW_CTL        = 0x001C, /* Transmit Flow Control */
+    REG_TX_DMA_DESC_LIST   = 0x0020, /* Transmit Descriptor List Address */
+    REG_RX_CTL_0           = 0x0024, /* Receive Control 0 */
+    REG_RX_CTL_1           = 0x0028, /* Receive Control 1 */
+    REG_RX_DMA_DESC_LIST   = 0x0034, /* Receive Descriptor List Address */
+    REG_FRM_FLT            = 0x0038, /* Receive Frame Filter */
+    REG_RX_HASH_0          = 0x0040, /* Receive Hash Table 0 */
+    REG_RX_HASH_1          = 0x0044, /* Receive Hash Table 1 */
+    REG_MII_CMD            = 0x0048, /* Management Interface Command */
+    REG_MII_DATA           = 0x004C, /* Management Interface Data */
+    REG_ADDR_HIGH          = 0x0050, /* MAC Address High */
+    REG_ADDR_LOW           = 0x0054, /* MAC Address Low */
+    REG_TX_DMA_STA         = 0x00B0, /* Transmit DMA Status */
+    REG_TX_CUR_DESC        = 0x00B4, /* Transmit Current Descriptor */
+    REG_TX_CUR_BUF         = 0x00B8, /* Transmit Current Buffer */
+    REG_RX_DMA_STA         = 0x00C0, /* Receive DMA Status */
+    REG_RX_CUR_DESC        = 0x00C4, /* Receive Current Descriptor */
+    REG_RX_CUR_BUF         = 0x00C8, /* Receive Current Buffer */
+    REG_RGMII_STA          = 0x00D0, /* RGMII Status */
+};
+
+/* EMAC register flags */
+enum {
+    BASIC_CTL0_100Mbps     = (0b11 << 2),
+    BASIC_CTL0_FD          = (1 << 0),
+    BASIC_CTL1_SOFTRST     = (1 << 0),
+};
+
+enum {
+    INT_STA_RGMII_LINK     = (1 << 16),
+    INT_STA_RX_EARLY       = (1 << 13),
+    INT_STA_RX_OVERFLOW    = (1 << 12),
+    INT_STA_RX_TIMEOUT     = (1 << 11),
+    INT_STA_RX_DMA_STOP    = (1 << 10),
+    INT_STA_RX_BUF_UA      = (1 << 9),
+    INT_STA_RX             = (1 << 8),
+    INT_STA_TX_EARLY       = (1 << 5),
+    INT_STA_TX_UNDERFLOW   = (1 << 4),
+    INT_STA_TX_TIMEOUT     = (1 << 3),
+    INT_STA_TX_BUF_UA      = (1 << 2),
+    INT_STA_TX_DMA_STOP    = (1 << 1),
+    INT_STA_TX             = (1 << 0),
+};
+
+enum {
+    INT_EN_RX_EARLY        = (1 << 13),
+    INT_EN_RX_OVERFLOW     = (1 << 12),
+    INT_EN_RX_TIMEOUT      = (1 << 11),
+    INT_EN_RX_DMA_STOP     = (1 << 10),
+    INT_EN_RX_BUF_UA       = (1 << 9),
+    INT_EN_RX              = (1 << 8),
+    INT_EN_TX_EARLY        = (1 << 5),
+    INT_EN_TX_UNDERFLOW    = (1 << 4),
+    INT_EN_TX_TIMEOUT      = (1 << 3),
+    INT_EN_TX_BUF_UA       = (1 << 2),
+    INT_EN_TX_DMA_STOP     = (1 << 1),
+    INT_EN_TX              = (1 << 0),
+};
+
+enum {
+    TX_CTL0_TX_EN          = (1 << 31),
+    TX_CTL1_TX_DMA_START   = (1 << 31),
+    TX_CTL1_TX_DMA_EN      = (1 << 30),
+    TX_CTL1_TX_FLUSH       = (1 << 0),
+};
+
+enum {
+    RX_CTL0_RX_EN          = (1 << 31),
+    RX_CTL0_STRIP_FCS      = (1 << 28),
+    RX_CTL0_CRC_IPV4       = (1 << 27),
+};
+
+enum {
+    RX_CTL1_RX_DMA_START   = (1 << 31),
+    RX_CTL1_RX_DMA_EN      = (1 << 30),
+    RX_CTL1_RX_MD          = (1 << 1),
+};
+
+enum {
+    RX_FRM_FLT_DIS_ADDR    = (1 << 31),
+};
+
+enum {
+    MII_CMD_PHY_ADDR_SHIFT = (12),
+    MII_CMD_PHY_ADDR_MASK  = (0xf000),
+    MII_CMD_PHY_REG_SHIFT  = (4),
+    MII_CMD_PHY_REG_MASK   = (0xf0),
+    MII_CMD_PHY_RW         = (1 << 1),
+    MII_CMD_PHY_BUSY       = (1 << 0),
+};
+
+enum {
+    TX_DMA_STA_STOP        = (0b000),
+    TX_DMA_STA_RUN_FETCH   = (0b001),
+    TX_DMA_STA_WAIT_STA    = (0b010),
+};
+
+enum {
+    RX_DMA_STA_STOP        = (0b000),
+    RX_DMA_STA_RUN_FETCH   = (0b001),
+    RX_DMA_STA_WAIT_FRM    = (0b011),
+};
+
+enum {
+    RGMII_LINK_UP          = (1 << 3),
+    RGMII_FD               = (1 << 0),
+};
+
+/* EMAC register reset values */
+enum {
+    REG_BASIC_CTL_1_RST    = 0x08000000,
+};
+
+/* EMAC constants */
+enum {
+    AW_H3_EMAC_MIN_PKT_SZ  = 64
+};
+
+/* Transmit/receive frame descriptor */
+typedef struct FrameDescriptor {
+    uint32_t status;
+    uint32_t status2;
+    uint32_t addr;
+    uint32_t next;
+} FrameDescriptor;
+
+/* Frame descriptor flags */
+enum {
+    DESC_STATUS_CTL                 = (1 << 31),
+    DESC_STATUS2_BUF_SIZE_MASK      = (0x7ff),
+};
+
+/* Transmit frame descriptor flags */
+enum {
+    TX_DESC_STATUS_LENGTH_ERR       = (1 << 14),
+    TX_DESC_STATUS2_FIRST_DESC      = (1 << 29),
+    TX_DESC_STATUS2_LAST_DESC       = (1 << 30),
+    TX_DESC_STATUS2_CHECKSUM_MASK   = (0x3 << 27),
+};
+
+/* Receive frame descriptor flags */
+enum {
+    RX_DESC_STATUS_FIRST_DESC       = (1 << 9),
+    RX_DESC_STATUS_LAST_DESC        = (1 << 8),
+    RX_DESC_STATUS_FRM_LEN_MASK     = (0x3fff0000),
+    RX_DESC_STATUS_FRM_LEN_SHIFT    = (16),
+    RX_DESC_STATUS_NO_BUF           = (1 << 14),
+    RX_DESC_STATUS_HEADER_ERR       = (1 << 7),
+    RX_DESC_STATUS_LENGTH_ERR       = (1 << 4),
+    RX_DESC_STATUS_CRC_ERR          = (1 << 1),
+    RX_DESC_STATUS_PAYLOAD_ERR      = (1 << 0),
+    RX_DESC_STATUS2_RX_INT_CTL      = (1 << 31),
+};
+
+/* MII register offsets */
+enum {
+    MII_REG_CR                      = (0x0),
+    MII_REG_ST                      = (0x1),
+    MII_REG_ID_HIGH                 = (0x2),
+    MII_REG_ID_LOW                  = (0x3),
+};
+
+/* MII register flags */
+enum {
+    MII_REG_CR_RESET                = (1 << 15),
+    MII_REG_CR_POWERDOWN            = (1 << 11),
+    MII_REG_CR_10Mbit               = (0),
+    MII_REG_CR_100Mbit              = (1 << 13),
+    MII_REG_CR_1000Mbit             = (1 << 6),
+    MII_REG_CR_AUTO_NEG             = (1 << 12),
+    MII_REG_CR_AUTO_NEG_RESTART     = (1 << 9),
+    MII_REG_CR_FULLDUPLEX           = (1 << 8),
+};
+
+enum {
+    MII_REG_ST_100BASE_T4           = (1 << 15),
+    MII_REG_ST_100BASE_X_FD         = (1 << 14),
+    MII_REG_ST_100BASE_X_HD         = (1 << 13),
+    MII_REG_ST_10_FD                = (1 << 12),
+    MII_REG_ST_10_HD                = (1 << 11),
+    MII_REG_ST_100BASE_T2_FD        = (1 << 10),
+    MII_REG_ST_100BASE_T2_HD        = (1 << 9),
+    MII_REG_ST_AUTONEG_COMPLETE     = (1 << 5),
+    MII_REG_ST_AUTONEG_AVAIL        = (1 << 3),
+    MII_REG_ST_LINK_UP              = (1 << 2),
+};
+
+/* MII constants */
+enum {
+    MII_PHY_ID_HIGH                 = 0x0044,
+    MII_PHY_ID_LOW                  = 0x1400,
+};
+
+static void aw_h3_emac_mii_set_link(AwH3EmacState *s, bool link_active)
+{
+    if (link_active) {
+        s->mii_st |= MII_REG_ST_LINK_UP;
+    } else {
+        s->mii_st &= ~MII_REG_ST_LINK_UP;
+    }
+}
+
+static void aw_h3_emac_mii_reset(AwH3EmacState *s, bool link_active)
+{
+    s->mii_cr = MII_REG_CR_100Mbit | MII_REG_CR_AUTO_NEG |
+                MII_REG_CR_FULLDUPLEX;
+    s->mii_st = MII_REG_ST_100BASE_T4 | MII_REG_ST_100BASE_X_FD |
+                MII_REG_ST_100BASE_X_HD | MII_REG_ST_10_FD | MII_REG_ST_10_HD |
+                MII_REG_ST_100BASE_T2_FD | MII_REG_ST_100BASE_T2_HD |
+                MII_REG_ST_AUTONEG_COMPLETE | MII_REG_ST_AUTONEG_AVAIL;
+
+    aw_h3_emac_mii_set_link(s, link_active);
+}
+
+static void aw_h3_emac_mii_cmd(AwH3EmacState *s)
+{
+    uint8_t addr, reg;
+
+    addr = (s->mii_cmd & MII_CMD_PHY_ADDR_MASK) >> MII_CMD_PHY_ADDR_SHIFT;
+    reg = (s->mii_cmd & MII_CMD_PHY_REG_MASK) >> MII_CMD_PHY_REG_SHIFT;
+
+    if (addr != s->mii_phy_addr) {
+        return;
+    }
+
+    /* Read or write a PHY register? */
+    if (s->mii_cmd & MII_CMD_PHY_RW) {
+        trace_aw_h3_emac_mii_write_reg(reg, s->mii_data);
+
+        switch (reg) {
+        case MII_REG_CR:
+            if (s->mii_data & MII_REG_CR_RESET) {
+                aw_h3_emac_mii_reset(s, s->mii_st & MII_REG_ST_LINK_UP);
+            } else {
+                s->mii_cr = s->mii_data & ~(MII_REG_CR_RESET |
+                                            MII_REG_CR_AUTO_NEG_RESTART);
+            }
+            break;
+        default:
+            qemu_log_mask(LOG_UNIMP, "allwinner-h3-emac: write access to "
+                                     "unknown MII register 0x%x\n", reg);
+            break;
+        }
+    } else {
+        switch (reg) {
+        case MII_REG_CR:
+            s->mii_data = s->mii_cr;
+            break;
+        case MII_REG_ST:
+            s->mii_data = s->mii_st;
+            break;
+        case MII_REG_ID_HIGH:
+            s->mii_data = MII_PHY_ID_HIGH;
+            break;
+        case MII_REG_ID_LOW:
+            s->mii_data = MII_PHY_ID_LOW;
+            break;
+        default:
+            qemu_log_mask(LOG_UNIMP, "allwinner-h3-emac: read access to "
+                                     "unknown MII register 0x%x\n", reg);
+            s->mii_data = 0;
+            break;
+        }
+
+        trace_aw_h3_emac_mii_read_reg(reg, s->mii_data);
+    }
+}
+
+static void aw_h3_emac_update_irq(AwH3EmacState *s)
+{
+    qemu_set_irq(s->irq, (s->int_sta & s->int_en) != 0);
+}
+
+static uint32_t aw_h3_emac_next_desc(FrameDescriptor *desc, size_t min_size)
+{
+    uint32_t paddr = desc->next;
+
+    cpu_physical_memory_read(paddr, desc, sizeof(*desc));
+
+    if ((desc->status & DESC_STATUS_CTL) &&
+        (desc->status2 & DESC_STATUS2_BUF_SIZE_MASK) >= min_size) {
+        return paddr;
+    } else {
+        return 0;
+    }
+}
+
+static uint32_t aw_h3_emac_get_desc(FrameDescriptor *desc, uint32_t start_addr,
+                                    size_t min_size)
+{
+    uint32_t desc_addr = start_addr;
+
+    /* Note that the list is a cycle. Last entry points back to the head. */
+    while (desc_addr != 0) {
+        cpu_physical_memory_read(desc_addr, desc, sizeof(*desc));
+
+        if ((desc->status & DESC_STATUS_CTL) &&
+            (desc->status2 & DESC_STATUS2_BUF_SIZE_MASK) >= min_size) {
+            return desc_addr;
+        } else if (desc->next == start_addr) {
+            break;
+        } else {
+            desc_addr = desc->next;
+        }
+    }
+
+    return 0;
+}
+
+static uint32_t aw_h3_emac_get_rx_desc(AwH3EmacState *s, FrameDescriptor *desc,
+                                       size_t min_size)
+{
+    return aw_h3_emac_get_desc(desc, s->rx_desc_curr, min_size);
+}
+
+static uint32_t aw_h3_emac_get_tx_desc(AwH3EmacState *s, FrameDescriptor *desc,
+                                       size_t min_size)
+{
+    return aw_h3_emac_get_desc(desc, s->tx_desc_head, min_size);
+}
+
+static void aw_h3_emac_flush_desc(FrameDescriptor *desc, uint32_t phys_addr)
+{
+    cpu_physical_memory_write(phys_addr, desc, sizeof(*desc));
+}
+
+static int aw_h3_emac_can_receive(NetClientState *nc)
+{
+    AwH3EmacState *s = qemu_get_nic_opaque(nc);
+    FrameDescriptor desc;
+
+    return (s->rx_ctl0 & RX_CTL0_RX_EN) &&
+           (aw_h3_emac_get_rx_desc(s, &desc, 0) != 0);
+}
+
+static ssize_t aw_h3_emac_receive(NetClientState *nc, const uint8_t *buf,
+                                  size_t size)
+{
+    AwH3EmacState *s = qemu_get_nic_opaque(nc);
+    FrameDescriptor desc;
+    size_t bytes_left = size;
+    size_t desc_bytes = 0;
+    size_t pad_fcs_size = 4;
+    size_t padding = 0;
+
+    if (!(s->rx_ctl0 & RX_CTL0_RX_EN)) {
+        return -1;
+    }
+
+    s->rx_desc_curr = aw_h3_emac_get_rx_desc(s, &desc, AW_H3_EMAC_MIN_PKT_SZ);
+    if (!s->rx_desc_curr) {
+        s->int_sta |= INT_STA_RX_BUF_UA;
+    }
+
+    /* Keep filling RX descriptors until the whole frame is written */
+    while (s->rx_desc_curr && bytes_left > 0) {
+        desc.status &= ~DESC_STATUS_CTL;
+        desc.status &= ~RX_DESC_STATUS_FRM_LEN_MASK;
+
+        if (bytes_left == size) {
+            desc.status |= RX_DESC_STATUS_FIRST_DESC;
+        }
+
+        if ((desc.status2 & DESC_STATUS2_BUF_SIZE_MASK) <
+            (bytes_left + pad_fcs_size)) {
+            desc_bytes = desc.status2 & DESC_STATUS2_BUF_SIZE_MASK;
+            desc.status |= desc_bytes << RX_DESC_STATUS_FRM_LEN_SHIFT;
+        } else {
+            padding = pad_fcs_size;
+            if (bytes_left < AW_H3_EMAC_MIN_PKT_SZ) {
+                padding += (AW_H3_EMAC_MIN_PKT_SZ - bytes_left);
+            }
+
+            desc_bytes = (bytes_left);
+            desc.status |= RX_DESC_STATUS_LAST_DESC;
+            desc.status |= (bytes_left + padding)
+                            << RX_DESC_STATUS_FRM_LEN_SHIFT;
+        }
+
+        cpu_physical_memory_write(desc.addr, buf, desc_bytes);
+        aw_h3_emac_flush_desc(&desc, s->rx_desc_curr);
+        trace_aw_h3_emac_receive(s->rx_desc_curr, desc.addr, desc_bytes);
+
+        /* Check if frame needs to raise the receive interrupt */
+        if (!(desc.status2 & RX_DESC_STATUS2_RX_INT_CTL)) {
+            s->int_sta |= INT_STA_RX;
+        }
+
+        /* Increment variables */
+        buf += desc_bytes;
+        bytes_left -= desc_bytes;
+
+        /* Move to the next descriptor */
+        s->rx_desc_curr = aw_h3_emac_next_desc(&desc, 64);
+        if (!s->rx_desc_curr) {
+            /* Not enough buffer space available */
+            s->int_sta |= INT_STA_RX_BUF_UA;
+            s->rx_desc_curr = s->rx_desc_head;
+            break;
+        }
+    }
+
+    /* Report receive DMA is finished */
+    s->rx_ctl1 &= ~RX_CTL1_RX_DMA_START;
+    aw_h3_emac_update_irq(s);
+
+    return size;
+}
+
+static void aw_h3_emac_transmit(AwH3EmacState *s)
+{
+    NetClientState *nc = qemu_get_queue(s->nic);
+    FrameDescriptor desc;
+    size_t bytes = 0;
+    size_t packet_bytes = 0;
+    size_t transmitted = 0;
+    static uint8_t packet_buf[2048];
+
+    s->tx_desc_curr = aw_h3_emac_get_tx_desc(s, &desc, 0);
+
+    /* Read all transmit descriptors */
+    while (s->tx_desc_curr != 0) {
+
+        /* Read from physical memory into packet buffer */
+        bytes = desc.status2 & DESC_STATUS2_BUF_SIZE_MASK;
+        if (bytes + packet_bytes > sizeof(packet_buf)) {
+            desc.status |= TX_DESC_STATUS_LENGTH_ERR;
+            break;
+        }
+        cpu_physical_memory_read(desc.addr, packet_buf + packet_bytes, bytes);
+        packet_bytes += bytes;
+        desc.status &= ~DESC_STATUS_CTL;
+        aw_h3_emac_flush_desc(&desc, s->tx_desc_curr);
+
+        /* After the last descriptor, send the packet */
+        if (desc.status2 & TX_DESC_STATUS2_LAST_DESC) {
+            if (desc.status2 & TX_DESC_STATUS2_CHECKSUM_MASK) {
+                net_checksum_calculate(packet_buf, packet_bytes);
+            }
+
+            qemu_send_packet(nc, packet_buf, packet_bytes);
+            trace_aw_h3_emac_transmit(s->tx_desc_curr, desc.addr, bytes);
+
+            packet_bytes = 0;
+            transmitted++;
+        }
+        s->tx_desc_curr = aw_h3_emac_next_desc(&desc, 0);
+    }
+
+    /* Raise transmit completed interrupt */
+    if (transmitted > 0) {
+        s->int_sta |= INT_STA_TX;
+        s->tx_ctl1 &= ~TX_CTL1_TX_DMA_START;
+        aw_h3_emac_update_irq(s);
+    }
+}
+
+static void aw_h3_emac_reset(DeviceState *dev)
+{
+    AwH3EmacState *s = AW_H3_EMAC(dev);
+    NetClientState *nc = qemu_get_queue(s->nic);
+
+    trace_aw_h3_emac_reset();
+
+    s->mii_cmd = 0;
+    s->mii_data = 0;
+    s->basic_ctl0 = 0;
+    s->basic_ctl1 = 0;
+    s->int_en = 0;
+    s->int_sta = 0;
+    s->frm_flt = 0;
+    s->rx_ctl0 = 0;
+    s->rx_ctl1 = RX_CTL1_RX_MD;
+    s->rx_desc_head = 0;
+    s->rx_desc_curr = 0;
+    s->tx_ctl0 = 0;
+    s->tx_ctl1 = 0;
+    s->tx_desc_head = 0;
+    s->tx_desc_curr = 0;
+    s->tx_flowctl = 0;
+
+    aw_h3_emac_mii_reset(s, !nc->link_down);
+}
+
+static uint64_t aw_h3_emac_read(void *opaque, hwaddr offset, unsigned size)
+{
+    AwH3EmacState *s = AW_H3_EMAC(opaque);
+    uint64_t value = 0;
+    FrameDescriptor desc;
+
+    switch (offset) {
+    case REG_BASIC_CTL_0:       /* Basic Control 0 */
+        value = s->basic_ctl0;
+        break;
+    case REG_BASIC_CTL_1:       /* Basic Control 1 */
+        value = s->basic_ctl1;
+        break;
+    case REG_INT_STA:           /* Interrupt Status */
+        value = s->int_sta;
+        break;
+    case REG_INT_EN:            /* Interupt Enable */
+        value = s->int_en;
+        break;
+    case REG_TX_CTL_0:          /* Transmit Control 0 */
+        value = s->tx_ctl0;
+        break;
+    case REG_TX_CTL_1:          /* Transmit Control 1 */
+        value = s->tx_ctl1;
+        break;
+    case REG_TX_FLOW_CTL:       /* Transmit Flow Control */
+        value = s->tx_flowctl;
+        break;
+    case REG_TX_DMA_DESC_LIST:  /* Transmit Descriptor List Address */
+        value = s->tx_desc_head;
+        break;
+    case REG_RX_CTL_0:          /* Receive Control 0 */
+        value = s->rx_ctl0;
+        break;
+    case REG_RX_CTL_1:          /* Receive Control 1 */
+        value = s->rx_ctl1;
+        break;
+    case REG_RX_DMA_DESC_LIST:  /* Receive Descriptor List Address */
+        value = s->rx_desc_head;
+        break;
+    case REG_FRM_FLT:           /* Receive Frame Filter */
+        value = s->frm_flt;
+        break;
+    case REG_RX_HASH_0:         /* Receive Hash Table 0 */
+    case REG_RX_HASH_1:         /* Receive Hash Table 1 */
+        break;
+    case REG_MII_CMD:           /* Management Interface Command */
+        value = s->mii_cmd;
+        break;
+    case REG_MII_DATA:          /* Management Interface Data */
+        value = s->mii_data;
+        break;
+    case REG_ADDR_HIGH:         /* MAC Address High */
+        value = *(((uint32_t *) (s->conf.macaddr.a)) + 1);
+        break;
+    case REG_ADDR_LOW:          /* MAC Address Low */
+        value = *(uint32_t *) (s->conf.macaddr.a);
+        break;
+    case REG_TX_DMA_STA:        /* Transmit DMA Status */
+        break;
+    case REG_TX_CUR_DESC:       /* Transmit Current Descriptor */
+        value = s->tx_desc_curr;
+        break;
+    case REG_TX_CUR_BUF:        /* Transmit Current Buffer */
+        if (s->tx_desc_curr != 0) {
+            cpu_physical_memory_read(s->tx_desc_curr, &desc, sizeof(desc));
+            value = desc.addr;
+        } else {
+            value = 0;
+        }
+        break;
+    case REG_RX_DMA_STA:        /* Receive DMA Status */
+        break;
+    case REG_RX_CUR_DESC:       /* Receive Current Descriptor */
+        value = s->rx_desc_curr;
+        break;
+    case REG_RX_CUR_BUF:        /* Receive Current Buffer */
+        if (s->rx_desc_curr != 0) {
+            cpu_physical_memory_read(s->rx_desc_curr, &desc, sizeof(desc));
+            value = desc.addr;
+        } else {
+            value = 0;
+        }
+        break;
+    default:
+        qemu_log_mask(LOG_UNIMP, "allwinner-h3-emac: read access to unknown "
+                                 "EMAC register 0x" TARGET_FMT_plx "\n",
+                                  offset);
+    }
+
+    trace_aw_h3_emac_read(offset, value);
+    return value;
+}
+
+static void aw_h3_emac_write(void *opaque, hwaddr offset, uint64_t value,
+                             unsigned size)
+{
+    AwH3EmacState *s = AW_H3_EMAC(opaque);
+    NetClientState *nc = qemu_get_queue(s->nic);
+
+    trace_aw_h3_emac_write(offset, value);
+
+    switch (offset) {
+    case REG_BASIC_CTL_0:       /* Basic Control 0 */
+        s->basic_ctl0 = value;
+        break;
+    case REG_BASIC_CTL_1:       /* Basic Control 1 */
+        if (value & BASIC_CTL1_SOFTRST) {
+            aw_h3_emac_reset(DEVICE(s));
+            value &= ~BASIC_CTL1_SOFTRST;
+        }
+        s->basic_ctl1 = value;
+        if (aw_h3_emac_can_receive(nc)) {
+            qemu_flush_queued_packets(nc);
+        }
+        break;
+    case REG_INT_STA:           /* Interrupt Status */
+        s->int_sta &= ~value;
+        aw_h3_emac_update_irq(s);
+        break;
+    case REG_INT_EN:            /* Interrupt Enable */
+        s->int_en = value;
+        aw_h3_emac_update_irq(s);
+        break;
+    case REG_TX_CTL_0:          /* Transmit Control 0 */
+        s->tx_ctl0 = value;
+        break;
+    case REG_TX_CTL_1:          /* Transmit Control 1 */
+        s->tx_ctl1 = value;
+        if (value & TX_CTL1_TX_DMA_EN) {
+            aw_h3_emac_transmit(s);
+        }
+        break;
+    case REG_TX_FLOW_CTL:       /* Transmit Flow Control */
+        s->tx_flowctl = value;
+        break;
+    case REG_TX_DMA_DESC_LIST:  /* Transmit Descriptor List Address */
+        s->tx_desc_head = value;
+        s->tx_desc_curr = value;
+        break;
+    case REG_RX_CTL_0:          /* Receive Control 0 */
+        s->rx_ctl0 = value;
+        break;
+    case REG_RX_CTL_1:          /* Receive Control 1 */
+        s->rx_ctl1 = value | RX_CTL1_RX_MD;
+        if ((value & RX_CTL1_RX_DMA_EN) && aw_h3_emac_can_receive(nc)) {
+            qemu_flush_queued_packets(nc);
+        }
+        break;
+    case REG_RX_DMA_DESC_LIST:  /* Receive Descriptor List Address */
+        s->rx_desc_head = value;
+        s->rx_desc_curr = value;
+        break;
+    case REG_FRM_FLT:           /* Receive Frame Filter */
+        s->frm_flt = value;
+        break;
+    case REG_RX_HASH_0:         /* Receive Hash Table 0 */
+    case REG_RX_HASH_1:         /* Receive Hash Table 1 */
+        break;
+    case REG_MII_CMD:           /* Management Interface Command */
+        s->mii_cmd = value & ~MII_CMD_PHY_BUSY;
+        aw_h3_emac_mii_cmd(s);
+        break;
+    case REG_MII_DATA:          /* Management Interface Data */
+        s->mii_data = value;
+        break;
+    case REG_ADDR_HIGH:         /* MAC Address High */
+        s->conf.macaddr.a[4] = (value & 0xff);
+        s->conf.macaddr.a[5] = (value & 0xff00) >> 8;
+        break;
+    case REG_ADDR_LOW:          /* MAC Address Low */
+        s->conf.macaddr.a[0] = (value & 0xff);
+        s->conf.macaddr.a[1] = (value & 0xff00) >> 8;
+        s->conf.macaddr.a[2] = (value & 0xff0000) >> 16;
+        s->conf.macaddr.a[3] = (value & 0xff000000) >> 24;
+        break;
+    case REG_TX_DMA_STA:        /* Transmit DMA Status */
+    case REG_TX_CUR_DESC:       /* Transmit Current Descriptor */
+    case REG_TX_CUR_BUF:        /* Transmit Current Buffer */
+    case REG_RX_DMA_STA:        /* Receive DMA Status */
+    case REG_RX_CUR_DESC:       /* Receive Current Descriptor */
+    case REG_RX_CUR_BUF:        /* Receive Current Buffer */
+    case REG_RGMII_STA:         /* RGMII Status */
+        break;
+    default:
+        qemu_log_mask(LOG_UNIMP, "allwinner-h3-emac: write access to unknown "
+                                 "EMAC register 0x" TARGET_FMT_plx "\n",
+                                  offset);
+    }
+}
+
+static void aw_h3_emac_set_link(NetClientState *nc)
+{
+    AwH3EmacState *s = qemu_get_nic_opaque(nc);
+
+    trace_aw_h3_emac_set_link(!nc->link_down);
+    aw_h3_emac_mii_set_link(s, !nc->link_down);
+}
+
+static const MemoryRegionOps aw_h3_emac_mem_ops = {
+    .read = aw_h3_emac_read,
+    .write = aw_h3_emac_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+        .unaligned = false,
+    },
+    .impl.min_access_size = 4,
+};
+
+static NetClientInfo net_aw_h3_emac_info = {
+    .type = NET_CLIENT_DRIVER_NIC,
+    .size = sizeof(NICState),
+    .can_receive = aw_h3_emac_can_receive,
+    .receive = aw_h3_emac_receive,
+    .link_status_changed = aw_h3_emac_set_link,
+};
+
+static void aw_h3_emac_init(Object *obj)
+{
+    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+    AwH3EmacState *s = AW_H3_EMAC(obj);
+
+    memory_region_init_io(&s->iomem, OBJECT(s), &aw_h3_emac_mem_ops, s,
+                          TYPE_AW_H3_EMAC, 64 * KiB);
+    sysbus_init_mmio(sbd, &s->iomem);
+    sysbus_init_irq(sbd, &s->irq);
+}
+
+static void aw_h3_emac_realize(DeviceState *dev, Error **errp)
+{
+    AwH3EmacState *s = AW_H3_EMAC(dev);
+
+    qemu_macaddr_default_if_unset(&s->conf.macaddr);
+    s->nic = qemu_new_nic(&net_aw_h3_emac_info, &s->conf,
+                          object_get_typename(OBJECT(dev)), dev->id, s);
+    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
+}
+
+static Property aw_h3_emac_properties[] = {
+    DEFINE_NIC_PROPERTIES(AwH3EmacState, conf),
+    DEFINE_PROP_UINT8("phy-addr", AwH3EmacState, mii_phy_addr, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static int aw_h3_emac_post_load(void *opaque, int version_id)
+{
+    AwH3EmacState *s = opaque;
+
+    aw_h3_emac_set_link(qemu_get_queue(s->nic));
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_aw_emac = {
+    .name = "allwinner-h3-emac",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .post_load = aw_h3_emac_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(mii_phy_addr, AwH3EmacState),
+        VMSTATE_UINT32(mii_cmd, AwH3EmacState),
+        VMSTATE_UINT32(mii_data, AwH3EmacState),
+        VMSTATE_UINT32(basic_ctl0, AwH3EmacState),
+        VMSTATE_UINT32(basic_ctl1, AwH3EmacState),
+        VMSTATE_UINT32(int_en, AwH3EmacState),
+        VMSTATE_UINT32(int_sta, AwH3EmacState),
+        VMSTATE_UINT32(frm_flt, AwH3EmacState),
+        VMSTATE_UINT32(rx_ctl0, AwH3EmacState),
+        VMSTATE_UINT32(rx_ctl1, AwH3EmacState),
+        VMSTATE_UINT32(rx_desc_head, AwH3EmacState),
+        VMSTATE_UINT32(rx_desc_curr, AwH3EmacState),
+        VMSTATE_UINT32(tx_ctl0, AwH3EmacState),
+        VMSTATE_UINT32(tx_ctl1, AwH3EmacState),
+        VMSTATE_UINT32(tx_desc_head, AwH3EmacState),
+        VMSTATE_UINT32(tx_desc_curr, AwH3EmacState),
+        VMSTATE_UINT32(tx_flowctl, AwH3EmacState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void aw_h3_emac_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->realize = aw_h3_emac_realize;
+    dc->props = aw_h3_emac_properties;
+    dc->reset = aw_h3_emac_reset;
+    dc->vmsd = &vmstate_aw_emac;
+}
+
+static const TypeInfo aw_h3_emac_info = {
+    .name           = TYPE_AW_H3_EMAC,
+    .parent         = TYPE_SYS_BUS_DEVICE,
+    .instance_size  = sizeof(AwH3EmacState),
+    .instance_init  = aw_h3_emac_init,
+    .class_init     = aw_h3_emac_class_init,
+};
+
+static void aw_h3_emac_register_types(void)
+{
+    type_register_static(&aw_h3_emac_info);
+}
+
+type_init(aw_h3_emac_register_types)
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index ebf8d2325f..551cff3442 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -294,6 +294,7 @@ config ALLWINNER_A10
 config ALLWINNER_H3
     bool
     select ALLWINNER_A10_PIT
+    select ALLWINNER_H3_EMAC
     select SERIAL
     select ARM_TIMER
     select ARM_GIC
diff --git a/hw/net/Kconfig b/hw/net/Kconfig
index 3856417d42..36d3923992 100644
--- a/hw/net/Kconfig
+++ b/hw/net/Kconfig
@@ -74,6 +74,9 @@ config MIPSNET
 config ALLWINNER_EMAC
     bool
 
+config ALLWINNER_H3_EMAC
+    bool
+
 config IMX_FEC
     bool
 
diff --git a/hw/net/Makefile.objs b/hw/net/Makefile.objs
index 7907d2c199..5548deb07a 100644
--- a/hw/net/Makefile.objs
+++ b/hw/net/Makefile.objs
@@ -23,6 +23,7 @@ common-obj-$(CONFIG_XGMAC) += xgmac.o
 common-obj-$(CONFIG_MIPSNET) += mipsnet.o
 common-obj-$(CONFIG_XILINX_AXI) += xilinx_axienet.o
 common-obj-$(CONFIG_ALLWINNER_EMAC) += allwinner_emac.o
+common-obj-$(CONFIG_ALLWINNER_H3_EMAC) += allwinner-h3-emac.o
 common-obj-$(CONFIG_IMX_FEC) += imx_fec.o
 
 common-obj-$(CONFIG_CADENCE) += cadence_gem.o
diff --git a/hw/net/trace-events b/hw/net/trace-events
index e70f12bee1..b972c53f75 100644
--- a/hw/net/trace-events
+++ b/hw/net/trace-events
@@ -1,5 +1,15 @@
 # See docs/devel/tracing.txt for syntax documentation.
 
+# allwinner-h3-emac.c
+aw_h3_emac_mii_write_reg(uint32_t reg, uint32_t value) "MII write: reg=0x%" PRIx32 " value=0x%" PRIx32
+aw_h3_emac_mii_read_reg(uint32_t reg, uint32_t value) "MII read: reg=0x%" PRIx32 " value=0x%" PRIx32
+aw_h3_emac_receive(uint32_t desc, uint32_t paddr, uint32_t bytes) "RX packet: desc=0x%" PRIx32 " paddr=0x%" PRIx32 " bytes=%" PRIu32
+aw_h3_emac_transmit(uint32_t desc, uint32_t paddr, uint32_t bytes) "TX packet: desc=0x%" PRIx32 " paddr=0x%" PRIx32 " bytes=%" PRIu32
+aw_h3_emac_reset(void) "HW reset"
+aw_h3_emac_set_link(bool active) "Set link: active=%u"
+aw_h3_emac_read(uint64_t offset, uint64_t val) "MMIO read: offset=0x%" PRIx64 " value=0x%" PRIx64
+aw_h3_emac_write(uint64_t offset, uint64_t val) "MMIO write: offset=0x%" PRIx64 " value=0x%" PRIx64
+
 # etraxfs_eth.c
 mdio_phy_read(int regnum, uint16_t value) "read phy_reg:%d value:0x%04x"
 mdio_phy_write(int regnum, uint16_t value) "write phy_reg:%d value:0x%04x"
-- 
2.17.1



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

* Re: [PATCH v2 06/10] arm/arm-powerctl: rebuild hflags after setting CP15 bits in arm_set_cpu_on()
  2019-12-16 23:35 ` [PATCH v2 06/10] arm/arm-powerctl: rebuild hflags after setting CP15 bits in arm_set_cpu_on() Niek Linnenbank
@ 2019-12-16 23:44   ` Niek Linnenbank
  2019-12-17 16:12     ` Peter Maydell
  0 siblings, 1 reply; 30+ messages in thread
From: Niek Linnenbank @ 2019-12-16 23:44 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-arm, Philippe Mathieu-Daudé, QEMU Developers

[-- Attachment #1: Type: text/plain, Size: 2155 bytes --]

Hello Peter,

In the previous version of this patch series I included the fix for setting
CP10,CP11 bits
in arm_set_cpu_on(), which is now in master (0c7f8c43daf65560). While that
worked, I did not
realize that setting those bits require rebuilding the flags. Philippe
reported this [1] initially,
later on during review we discussed [2] and attempted to correct it [3].

Could you please have a short look at this? Right now I don't see anymore
issues, but I'm just not very familiar with this area of the code.

Regards,
Niek

[1] https://lists.gnu.org/archive/html/qemu-devel/2019-12/msg01920.html
[2] https://lists.gnu.org/archive/html/qemu-devel/2019-12/msg02784.html
[3] https://lists.gnu.org/archive/html/qemu-devel/2019-12/msg02785.html


On Tue, Dec 17, 2019 at 12:36 AM Niek Linnenbank <nieklinnenbank@gmail.com>
wrote:

> After setting CP15 bits in arm_set_cpu_on() the cached hflags must
> be rebuild to reflect the changed processor state. Without rebuilding,
> the cached hflags would be inconsistent until the next call to
> arm_rebuild_hflags(). When QEMU is compiled with debugging enabled
> (--enable-debug), this problem is captured shortly after the first
> call to arm_set_cpu_on() for CPUs running in ARM 32-bit non-secure mode:
>
>   qemu-system-arm: target/arm/helper.c:11359: cpu_get_tb_cpu_state:
>   Assertion `flags == rebuild_hflags_internal(env)' failed.
>   Aborted (core dumped)
>
> Fixes: 0c7f8c43daf65
> Signed-off-by: Niek Linnenbank <nieklinnenbank@gmail.com>
> ---
>  target/arm/arm-powerctl.c | 3 +++
>  1 file changed, 3 insertions(+)
>
> diff --git a/target/arm/arm-powerctl.c b/target/arm/arm-powerctl.c
> index b064513d44..b75f813b40 100644
> --- a/target/arm/arm-powerctl.c
> +++ b/target/arm/arm-powerctl.c
> @@ -127,6 +127,9 @@ static void arm_set_cpu_on_async_work(CPUState
> *target_cpu_state,
>          target_cpu->env.regs[0] = info->context_id;
>      }
>
> +    /* CP15 update requires rebuilding hflags */
> +    arm_rebuild_hflags(&target_cpu->env);
> +
>      /* Start the new CPU at the requested address */
>      cpu_set_pc(target_cpu_state, info->entry);
>
> --
> 2.17.1
>
>

-- 
Niek Linnenbank

[-- Attachment #2: Type: text/html, Size: 3343 bytes --]

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

* Re: [PATCH v2 02/10] hw: arm: add Xunlong Orange Pi PC machine
  2019-12-16 23:35 ` [PATCH v2 02/10] hw: arm: add Xunlong Orange Pi PC machine Niek Linnenbank
@ 2019-12-17  7:31   ` Philippe Mathieu-Daudé
  2019-12-18 20:14     ` Niek Linnenbank
  0 siblings, 1 reply; 30+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-12-17  7:31 UTC (permalink / raw)
  To: Niek Linnenbank, qemu-devel; +Cc: peter.maydell, qemu-arm

Hi Niek,

On 12/17/19 12:35 AM, Niek Linnenbank wrote:
> The Xunlong Orange Pi PC is an Allwinner H3 System on Chip
> based embedded computer with mainline support in both U-Boot
> and Linux. The board comes with a Quad Core Cortex A7 @ 1.3GHz,
> 512MB RAM, 100Mbit ethernet, USB, SD/MMC, USB, HDMI and
> various other I/O. This commit add support for the Xunlong
> Orange Pi PC machine.
> 
> Signed-off-by: Niek Linnenbank <nieklinnenbank@gmail.com>
> Tested-by: KONRAD Frederic <frederic.konrad@adacore.com>
> ---
>   hw/arm/orangepi.c    | 101 +++++++++++++++++++++++++++++++++++++++++++
>   MAINTAINERS          |   1 +
>   hw/arm/Makefile.objs |   2 +-
>   3 files changed, 103 insertions(+), 1 deletion(-)
>   create mode 100644 hw/arm/orangepi.c
> 
> diff --git a/hw/arm/orangepi.c b/hw/arm/orangepi.c
> new file mode 100644
> index 0000000000..62cefc8c06
> --- /dev/null
> +++ b/hw/arm/orangepi.c
> @@ -0,0 +1,101 @@
> +/*
> + * Orange Pi emulation
> + *
> + * Copyright (C) 2019 Niek Linnenbank <nieklinnenbank@gmail.com>
> + *
> + * This program is free software: you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * 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 "exec/address-spaces.h"
> +#include "qapi/error.h"
> +#include "cpu.h"
> +#include "hw/sysbus.h"
> +#include "hw/boards.h"
> +#include "hw/qdev-properties.h"
> +#include "hw/arm/allwinner-h3.h"
> +
> +static struct arm_boot_info orangepi_binfo = {
> +    .board_id = -1,
> +};
> +
> +typedef struct OrangePiState {
> +    AwH3State *h3;
> +    MemoryRegion sdram;
> +} OrangePiState;
> +
> +static void orangepi_init(MachineState *machine)
> +{
> +    OrangePiState *s = g_new(OrangePiState, 1);
> +
> +    /* Only allow Cortex-A7 for this board */
> +    if (strcmp(machine->cpu_type, ARM_CPU_TYPE_NAME("cortex-a7")) != 0) {
> +        error_report("This board can only be used with cortex-a7 CPU");
> +        exit(1);
> +    }
> +
> +    s->h3 = AW_H3(object_new(TYPE_AW_H3));
> +
> +    /* Setup timer properties */
> +    object_property_set_int(OBJECT(&s->h3->timer), 32768, "clk0-freq",
> +                            &error_abort);

You access the timer object which is contained inside the soc object, 
but the soc isn't realized yet... I wonder if this is OK. Usually what 
we do is, either:
- add a 'xtal-freq-hz' property to the SoC, set it here in the board, 
then in soc::realize() set the property to the timer
- add an alias in the SoC to the timer 'freq-hz' property:
     object_property_add_alias(soc, "xtal-freq-hz", OBJECT(&s->timer),
                                    "freq-hz", &error_abort);

Also, if you use &error_abort, a failure in object_property_set_int() 
triggers abort(). See "qapi/error.h":

  * If @errp is &error_abort, print a suitable message and abort().
  * If @errp is &error_fatal, print a suitable message and exit(1).

> +    if (error_abort != NULL) {
> +        error_reportf_err(error_abort, "Couldn't set clk0 frequency: ");
> +        exit(1);
> +    }

So this if() block is useless.

> +
> +    object_property_set_int(OBJECT(&s->h3->timer), 24000000, "clk1-freq",
> +                            &error_abort);
> +    if (error_abort != NULL) {
> +        error_reportf_err(error_abort, "Couldn't set clk1 frequency: ");
> +        exit(1);
> +    }

Similarly, remove if() block.

> +
> +    /* Mark H3 object realized */
> +    object_property_set_bool(OBJECT(s->h3), true, "realized", &error_abort);
> +    if (error_abort != NULL) {
> +        error_reportf_err(error_abort, "Couldn't realize Allwinner H3: ");
> +        exit(1);
> +    }

Similarly, remove if() block.

> +
> +    /* RAM */
> +    if (machine->ram_size > 1 * GiB) {
> +        error_report("Requested ram size is too large for this machine: "
> +                     "maximum is 1GB");

Per http://www.orangepi.org/orangepipc/ this board comes with a specific 
amount of RAM. I'd enforce the default (1GiB) and refuse other cases.

I noticed this by testing your series, without specifying the memory 
size you suggested in the cover (512) it defaults to 128 MiB, and the 
Raspian userland fails:

[ ***  ] (2 of 4) A start job is running for…Persistent Storage (37s / 
2min 1s)
[  *** ] (2 of 4) A start job is running for…Persistent Storage (38s / 
2min 1s)
[  OK  ] Started Flush Journal to Persistent Storage.
Starting Create Volatile Files and Directories...
Starting Armbian ZRAM config...
[    **] (3 of 6) A start job is running for…s and Directories (55s / no 
limit)
[     *] (3 of 6) A start job is running for…s and Directories (55s / no 
limit)
[    **] (3 of 6) A start job is running for…s and Directories (56s / no 
limit)
[  OK  ] Started Create Volatile Files and Directories.
[***   ] (5 of 6) A start job is running for… ZRAM config (1min 10s / 
1min 19s)
[**    ] (5 of 6) A start job is running for… ZRAM config (1min 12s / 
1min 19s)
[*     ] (5 of 6) A start job is running for… ZRAM config (1min 13s / 
1min 19s)
[FAILED] Failed to start Armbian ZRAM config.
See 'systemctl status armbian-zram-config.service' for details.

> +        exit(1);
> +    }
> +    memory_region_allocate_system_memory(&s->sdram, NULL, "orangepi.ram",

There is only one type of ram on this machine, I'd simply name this "sdram".

> +                                         machine->ram_size);
> +    memory_region_add_subregion(get_system_memory(), s->h3->memmap[AW_H3_SDRAM],
> +                                &s->sdram);
> +
> +    /* Load target kernel */
> +    orangepi_binfo.loader_start = s->h3->memmap[AW_H3_SDRAM];
> +    orangepi_binfo.ram_size = machine->ram_size;
> +    orangepi_binfo.nb_cpus  = AW_H3_NUM_CPUS;
> +    arm_load_kernel(ARM_CPU(first_cpu), machine, &orangepi_binfo);

I wonder if we should tell the user '-bios' is not supported on this 
machine.

> +}
> +
> +static void orangepi_machine_init(MachineClass *mc)
> +{
> +    mc->desc = "Orange Pi PC";
> +    mc->init = orangepi_init;
> +    mc->units_per_default_bus = 1;

Maybe "units_per_default_bus = 1" belongs to patch 9 "add SD/MMC host 
controller".

> +    mc->min_cpus = AW_H3_NUM_CPUS;
> +    mc->max_cpus = AW_H3_NUM_CPUS;
> +    mc->default_cpus = AW_H3_NUM_CPUS;
> +    mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a7");

Please add:

        mc->default_ram_size = 1 * GiB;

> +}
> +
> +DEFINE_MACHINE("orangepi-pc", orangepi_machine_init)
> diff --git a/MAINTAINERS b/MAINTAINERS
> index aae1a049b4..db682e49ca 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -486,6 +486,7 @@ L: qemu-arm@nongnu.org
>   S: Maintained
>   F: hw/*/allwinner-h3*
>   F: include/hw/*/allwinner-h3*
> +F: hw/arm/orangepi.c
>   
>   ARM PrimeCell and CMSDK devices
>   M: Peter Maydell <peter.maydell@linaro.org>
> diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
> index 956e496052..8d5ea453d5 100644
> --- a/hw/arm/Makefile.objs
> +++ b/hw/arm/Makefile.objs
> @@ -34,7 +34,7 @@ obj-$(CONFIG_DIGIC) += digic.o
>   obj-$(CONFIG_OMAP) += omap1.o omap2.o
>   obj-$(CONFIG_STRONGARM) += strongarm.o
>   obj-$(CONFIG_ALLWINNER_A10) += allwinner-a10.o cubieboard.o
> -obj-$(CONFIG_ALLWINNER_H3) += allwinner-h3.o
> +obj-$(CONFIG_ALLWINNER_H3) += allwinner-h3.o orangepi.o
>   obj-$(CONFIG_RASPI) += bcm2835_peripherals.o bcm2836.o raspi.o
>   obj-$(CONFIG_STM32F205_SOC) += stm32f205_soc.o
>   obj-$(CONFIG_XLNX_ZYNQMP_ARM) += xlnx-zynqmp.o xlnx-zcu102.o
> 



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

* Re: [PATCH v2 08/10] arm: allwinner-h3: add Security Identifier device
  2019-12-16 23:35 ` [PATCH v2 08/10] arm: allwinner-h3: add Security Identifier device Niek Linnenbank
@ 2019-12-17  7:45   ` Philippe Mathieu-Daudé
  2019-12-18 20:49     ` Niek Linnenbank
  0 siblings, 1 reply; 30+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-12-17  7:45 UTC (permalink / raw)
  To: Niek Linnenbank, qemu-devel; +Cc: peter.maydell, qemu-arm

Hi Niek,

On 12/17/19 12:35 AM, Niek Linnenbank wrote:
> The Security Identifier device in Allwinner H3 System on Chip
> gives applications a per-board unique identifier. This commit
> adds support for the Allwinner H3 Security Identifier using
> a 128-bit UUID value as input.
> 
> Signed-off-by: Niek Linnenbank <nieklinnenbank@gmail.com>
> ---
>   include/hw/arm/allwinner-h3.h      |   2 +
>   include/hw/misc/allwinner-h3-sid.h |  40 +++++++
>   hw/arm/allwinner-h3.c              |   7 ++
>   hw/arm/orangepi.c                  |   4 +
>   hw/misc/allwinner-h3-sid.c         | 179 +++++++++++++++++++++++++++++
>   hw/misc/Makefile.objs              |   1 +
>   hw/misc/trace-events               |   4 +
>   7 files changed, 237 insertions(+)
>   create mode 100644 include/hw/misc/allwinner-h3-sid.h
>   create mode 100644 hw/misc/allwinner-h3-sid.c
> 
> diff --git a/include/hw/arm/allwinner-h3.h b/include/hw/arm/allwinner-h3.h
> index 8128ae6131..c98c1972a6 100644
> --- a/include/hw/arm/allwinner-h3.h
> +++ b/include/hw/arm/allwinner-h3.h
> @@ -29,6 +29,7 @@
>   #include "hw/misc/allwinner-h3-clk.h"
>   #include "hw/misc/allwinner-h3-cpucfg.h"
>   #include "hw/misc/allwinner-h3-syscon.h"
> +#include "hw/misc/allwinner-h3-sid.h"
>   #include "target/arm/cpu.h"
>   
>   enum {
> @@ -77,6 +78,7 @@ typedef struct AwH3State {
>       AwH3ClockState ccu;
>       AwH3CpuCfgState cpucfg;
>       AwH3SysconState syscon;
> +    AwH3SidState sid;
>       GICState gic;
>       MemoryRegion sram_a1;
>       MemoryRegion sram_a2;
> diff --git a/include/hw/misc/allwinner-h3-sid.h b/include/hw/misc/allwinner-h3-sid.h
> new file mode 100644
> index 0000000000..79c9a24459
> --- /dev/null
> +++ b/include/hw/misc/allwinner-h3-sid.h
> @@ -0,0 +1,40 @@
> +/*
> + * Allwinner H3 Security ID emulation
> + *
> + * Copyright (C) 2019 Niek Linnenbank <nieklinnenbank@gmail.com>
> + *
> + * This program is free software: you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * 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_MISC_ALLWINNER_H3_SID_H
> +#define HW_MISC_ALLWINNER_H3_SID_H
> +
> +#include "hw/sysbus.h"
> +#include "qemu/uuid.h"
> +
> +#define TYPE_AW_H3_SID    "allwinner-h3-sid"
> +#define AW_H3_SID(obj)    OBJECT_CHECK(AwH3SidState, (obj), TYPE_AW_H3_SID)
> +
> +typedef struct AwH3SidState {
> +    /*< private >*/
> +    SysBusDevice parent_obj;
> +    /*< public >*/
> +
> +    MemoryRegion iomem;
> +    uint32_t control;
> +    uint32_t rdkey;
> +    QemuUUID identifier;
> +} AwH3SidState;
> +
> +#endif
> diff --git a/hw/arm/allwinner-h3.c b/hw/arm/allwinner-h3.c
> index 1a9748ab2e..ba34f905cd 100644
> --- a/hw/arm/allwinner-h3.c
> +++ b/hw/arm/allwinner-h3.c
> @@ -196,6 +196,9 @@ static void aw_h3_init(Object *obj)
>   
>       sysbus_init_child_obj(obj, "cpucfg", &s->cpucfg, sizeof(s->cpucfg),
>                             TYPE_AW_H3_CPUCFG);
> +
> +    sysbus_init_child_obj(obj, "sid", &s->sid, sizeof(s->sid),
> +                          TYPE_AW_H3_SID);

Here add a property alias:

        object_property_add_alias(obj, "identifier", OBJECT(&s->sid),
                                  "identifier", &error_abort);

>   }
>   
>   static void aw_h3_realize(DeviceState *dev, Error **errp)
> @@ -332,6 +335,10 @@ static void aw_h3_realize(DeviceState *dev, Error **errp)
>       qdev_init_nofail(DEVICE(&s->cpucfg));
>       sysbus_mmio_map(SYS_BUS_DEVICE(&s->cpucfg), 0, s->memmap[AW_H3_CPUCFG]);
>   
> +    /* Security Identifier */
> +    qdev_init_nofail(DEVICE(&s->sid));
> +    sysbus_mmio_map(SYS_BUS_DEVICE(&s->sid), 0, s->memmap[AW_H3_SID]);
> +
>       /* Universal Serial Bus */
>       sysbus_create_simple(TYPE_AW_H3_EHCI, s->memmap[AW_H3_EHCI0],
>                            qdev_get_gpio_in(DEVICE(&s->gic),
> diff --git a/hw/arm/orangepi.c b/hw/arm/orangepi.c
> index 62cefc8c06..b01c4b4f01 100644
> --- a/hw/arm/orangepi.c
> +++ b/hw/arm/orangepi.c
> @@ -62,6 +62,10 @@ static void orangepi_init(MachineState *machine)
>           exit(1);
>       }
>   
> +    /* Setup SID properties */
> +    qdev_prop_set_string(DEVICE(&s->h3->sid), "identifier",
> +                         "8100c002-0001-0002-0003-000044556677");

And here use the alias:

        qdev_prop_set_string(DEVICE(&s->h3), "identifier",
                             "8100c002-0001-0002-0003-000044556677");

What means this value? Don't you want to be able to set it from command 
line?

>       /* Mark H3 object realized */
>       object_property_set_bool(OBJECT(s->h3), true, "realized", &error_abort);
>       if (error_abort != NULL) {
> diff --git a/hw/misc/allwinner-h3-sid.c b/hw/misc/allwinner-h3-sid.c
> new file mode 100644
> index 0000000000..c472f2bcc6
> --- /dev/null
> +++ b/hw/misc/allwinner-h3-sid.c
> @@ -0,0 +1,179 @@
> +/*
> + * Allwinner H3 Security ID emulation
> + *
> + * Copyright (C) 2019 Niek Linnenbank <nieklinnenbank@gmail.com>
> + *
> + * This program is free software: you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * 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/units.h"
> +#include "hw/sysbus.h"
> +#include "migration/vmstate.h"
> +#include "qemu/log.h"
> +#include "qemu/module.h"
> +#include "qemu/guest-random.h"
> +#include "qapi/error.h"
> +#include "hw/qdev-properties.h"
> +#include "hw/misc/allwinner-h3-sid.h"
> +#include "trace.h"
> +
> +/* SID register offsets */
> +enum {
> +    REG_PRCTL = 0x40,   /* Control */
> +    REG_RDKEY = 0x60,   /* Read Key */
> +};
> +
> +/* SID register flags */
> +enum {
> +    REG_PRCTL_WRITE   = 0x0002, /* Unknown write flag */
> +    REG_PRCTL_OP_LOCK = 0xAC00, /* Lock operation */
> +};
> +
> +static uint64_t allwinner_h3_sid_read(void *opaque, hwaddr offset,
> +                                      unsigned size)
> +{
> +    const AwH3SidState *s = (AwH3SidState *)opaque;
> +    uint64_t val = 0;
> +
> +    switch (offset) {
> +    case REG_PRCTL:    /* Control */
> +        val = s->control;
> +        break;
> +    case REG_RDKEY:    /* Read Key */
> +        val = s->rdkey;
> +        break;
> +    default:
> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: bad read offset 0x%04x\n",
> +                      __func__, (uint32_t)offset);
> +        return 0;
> +    }
> +
> +    trace_allwinner_h3_sid_read(offset, val, size);
> +
> +    return val;
> +}
> +
> +static void allwinner_h3_sid_write(void *opaque, hwaddr offset,
> +                                   uint64_t val, unsigned size)
> +{
> +    AwH3SidState *s = (AwH3SidState *)opaque;
> +
> +    trace_allwinner_h3_sid_write(offset, val, size);
> +
> +    switch (offset) {
> +    case REG_PRCTL:    /* Control */
> +        s->control = val;
> +
> +        if ((s->control & REG_PRCTL_OP_LOCK) &&
> +            (s->control & REG_PRCTL_WRITE)) {
> +            uint32_t id = s->control >> 16;
> +
> +            if (id < sizeof(QemuUUID)) {
> +                s->rdkey = (s->identifier.data[id]) |
> +                           (s->identifier.data[id + 1] << 8) |
> +                           (s->identifier.data[id + 2] << 16) |
> +                           (s->identifier.data[id + 3] << 24);

This is:

                    s->rdkey = ldl_le_p(&s->identifier.data[id]);

> +            }
> +        }
> +        s->control &= ~REG_PRCTL_WRITE;
> +        break;
> +    case REG_RDKEY:    /* Read Key */

Read in a write()?

Maybe we can simply /* fall through */ LOG_GUEST_ERROR?

> +        break;
> +    default:
> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write offset 0x%04x\n",
> +                      __func__, (uint32_t)offset);
> +        break;
> +    }
> +}
> +
> +static const MemoryRegionOps allwinner_h3_sid_ops = {
> +    .read = allwinner_h3_sid_read,
> +    .write = allwinner_h3_sid_write,
> +    .endianness = DEVICE_NATIVE_ENDIAN,
> +    .valid = {
> +        .min_access_size = 4,
> +        .max_access_size = 4,
> +        .unaligned = false

'false' is the default value, maybe we can omit it?

> +    },
> +    .impl.min_access_size = 4,
> +};
> +
> +static void allwinner_h3_sid_reset(DeviceState *dev)
> +{
> +    AwH3SidState *s = AW_H3_SID(dev);
> +
> +    /* Set default values for registers */
> +    s->control = 0;
> +    s->rdkey = 0;
> +}
> +
> +static void allwinner_h3_sid_realize(DeviceState *dev, Error **errp)
> +{
> +}

If you don't need realize(), just remove it. However maybe we want to 
check if the identifier is null, either warn/abort or generate a random one?

> +
> +static void allwinner_h3_sid_init(Object *obj)
> +{
> +    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
> +    AwH3SidState *s = AW_H3_SID(obj);
> +
> +    /* Fill UUID with zeroes by default */
> +    qemu_uuid_parse(UUID_NONE, &s->identifier);

AwH3SidState is zeroed just before this init() call. I think we don't 
need to zeroes the UUID again.

> +
> +    /* Memory mapping */
> +    memory_region_init_io(&s->iomem, OBJECT(s), &allwinner_h3_sid_ops, s,
> +                          TYPE_AW_H3_SID, 1 * KiB);
> +    sysbus_init_mmio(sbd, &s->iomem);
> +}
> +
> +static Property allwinner_h3_sid_properties[] = {
> +    DEFINE_PROP_UUID_NODEFAULT("identifier", AwH3SidState, identifier),
> +    DEFINE_PROP_END_OF_LIST()
> +};
> +
> +static const VMStateDescription allwinner_h3_sid_vmstate = {
> +    .name = "allwinner-h3-sid",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT32(control, AwH3SidState),
> +        VMSTATE_UINT32(rdkey, AwH3SidState),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static void allwinner_h3_sid_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->reset = allwinner_h3_sid_reset;
> +    dc->realize = allwinner_h3_sid_realize;
> +    dc->vmsd = &allwinner_h3_sid_vmstate;
> +    dc->props = allwinner_h3_sid_properties;
> +}
> +
> +static const TypeInfo allwinner_h3_sid_info = {
> +    .name          = TYPE_AW_H3_SID,
> +    .parent        = TYPE_SYS_BUS_DEVICE,
> +    .instance_init = allwinner_h3_sid_init,
> +    .instance_size = sizeof(AwH3SidState),
> +    .class_init    = allwinner_h3_sid_class_init,
> +};
> +
> +static void allwinner_h3_sid_register(void)
> +{
> +    type_register_static(&allwinner_h3_sid_info);
> +}
> +
> +type_init(allwinner_h3_sid_register)
> diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
> index c4ca2ed689..f3620eee4e 100644
> --- a/hw/misc/Makefile.objs
> +++ b/hw/misc/Makefile.objs
> @@ -31,6 +31,7 @@ common-obj-$(CONFIG_IVSHMEM_DEVICE) += ivshmem.o
>   common-obj-$(CONFIG_ALLWINNER_H3) += allwinner-h3-clk.o
>   obj-$(CONFIG_ALLWINNER_H3) += allwinner-h3-cpucfg.o
>   common-obj-$(CONFIG_ALLWINNER_H3) += allwinner-h3-syscon.o
> +common-obj-$(CONFIG_ALLWINNER_H3) += allwinner-h3-sid.o
>   common-obj-$(CONFIG_REALVIEW) += arm_sysctl.o
>   common-obj-$(CONFIG_NSERIES) += cbus.o
>   common-obj-$(CONFIG_ECCMEMCTL) += eccmemctl.o
> diff --git a/hw/misc/trace-events b/hw/misc/trace-events
> index b93089d010..a777844ca3 100644
> --- a/hw/misc/trace-events
> +++ b/hw/misc/trace-events
> @@ -5,6 +5,10 @@ allwinner_h3_cpucfg_cpu_reset(uint8_t cpu_id, uint32_t reset_addr) "H3-CPUCFG: c
>   allwinner_h3_cpucfg_read(uint64_t offset, uint64_t data, unsigned size) "H3-CPUCFG: read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32
>   allwinner_h3_cpucfg_write(uint64_t offset, uint64_t data, unsigned size) "H3-CPUCFG: write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32
>   
> +# allwinner-h3-sid.c
> +allwinner_h3_sid_read(uint64_t offset, uint64_t data, unsigned size) "H3-SID: read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32
> +allwinner_h3_sid_write(uint64_t offset, uint64_t data, unsigned size) "H3-SID: write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32
> +
>   # eccmemctl.c
>   ecc_mem_writel_mer(uint32_t val) "Write memory enable 0x%08x"
>   ecc_mem_writel_mdr(uint32_t val) "Write memory delay 0x%08x"
> 



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

* Re: [PATCH v2 06/10] arm/arm-powerctl: rebuild hflags after setting CP15 bits in arm_set_cpu_on()
  2019-12-16 23:44   ` Niek Linnenbank
@ 2019-12-17 16:12     ` Peter Maydell
  2019-12-17 16:41       ` Richard Henderson
  0 siblings, 1 reply; 30+ messages in thread
From: Peter Maydell @ 2019-12-17 16:12 UTC (permalink / raw)
  To: Niek Linnenbank
  Cc: Richard Henderson, qemu-arm, Philippe Mathieu-Daudé,
	QEMU Developers

Cc'ing Richard : this is one for you I think... (surely we
need to rebuild the hflags from scratch when we power up
a CPU anyway?)

thanks
-- PMM

On Mon, 16 Dec 2019 at 23:44, Niek Linnenbank <nieklinnenbank@gmail.com> wrote:
>
> Hello Peter,
>
> In the previous version of this patch series I included the fix for setting CP10,CP11 bits
> in arm_set_cpu_on(), which is now in master (0c7f8c43daf65560). While that worked, I did not
> realize that setting those bits require rebuilding the flags. Philippe reported this [1] initially,
> later on during review we discussed [2] and attempted to correct it [3].
>
> Could you please have a short look at this? Right now I don't see anymore
> issues, but I'm just not very familiar with this area of the code.
>
> Regards,
> Niek
>
> [1] https://lists.gnu.org/archive/html/qemu-devel/2019-12/msg01920.html
> [2] https://lists.gnu.org/archive/html/qemu-devel/2019-12/msg02784.html
> [3] https://lists.gnu.org/archive/html/qemu-devel/2019-12/msg02785.html
>
>
> On Tue, Dec 17, 2019 at 12:36 AM Niek Linnenbank <nieklinnenbank@gmail.com> wrote:
>>
>> After setting CP15 bits in arm_set_cpu_on() the cached hflags must
>> be rebuild to reflect the changed processor state. Without rebuilding,
>> the cached hflags would be inconsistent until the next call to
>> arm_rebuild_hflags(). When QEMU is compiled with debugging enabled
>> (--enable-debug), this problem is captured shortly after the first
>> call to arm_set_cpu_on() for CPUs running in ARM 32-bit non-secure mode:
>>
>>   qemu-system-arm: target/arm/helper.c:11359: cpu_get_tb_cpu_state:
>>   Assertion `flags == rebuild_hflags_internal(env)' failed.
>>   Aborted (core dumped)
>>
>> Fixes: 0c7f8c43daf65
>> Signed-off-by: Niek Linnenbank <nieklinnenbank@gmail.com>
>> ---
>>  target/arm/arm-powerctl.c | 3 +++
>>  1 file changed, 3 insertions(+)
>>
>> diff --git a/target/arm/arm-powerctl.c b/target/arm/arm-powerctl.c
>> index b064513d44..b75f813b40 100644
>> --- a/target/arm/arm-powerctl.c
>> +++ b/target/arm/arm-powerctl.c
>> @@ -127,6 +127,9 @@ static void arm_set_cpu_on_async_work(CPUState *target_cpu_state,
>>          target_cpu->env.regs[0] = info->context_id;
>>      }
>>
>> +    /* CP15 update requires rebuilding hflags */
>> +    arm_rebuild_hflags(&target_cpu->env);
>> +
>>      /* Start the new CPU at the requested address */
>>      cpu_set_pc(target_cpu_state, info->entry);
>>
>> --
>> 2.17.1
>>
>
>
> --
> Niek Linnenbank


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

* Re: [PATCH v2 06/10] arm/arm-powerctl: rebuild hflags after setting CP15 bits in arm_set_cpu_on()
  2019-12-17 16:12     ` Peter Maydell
@ 2019-12-17 16:41       ` Richard Henderson
  2019-12-17 17:39         ` Peter Maydell
  2019-12-18 21:01         ` Niek Linnenbank
  0 siblings, 2 replies; 30+ messages in thread
From: Richard Henderson @ 2019-12-17 16:41 UTC (permalink / raw)
  To: Peter Maydell, Niek Linnenbank
  Cc: qemu-arm, Philippe Mathieu-Daudé, QEMU Developers

On 12/17/19 6:12 AM, Peter Maydell wrote:
> Cc'ing Richard : this is one for you I think... (surely we
> need to rebuild the hflags from scratch when we power up
> a CPU anyway?)

We do compute hflags from scratch in reset.

It has also turned out that there were a few board models that poked at the
contents of the cpu and needed special help.  Some of that I would imagine
would be fixed properly with the multi-phase reset patches, where we could
rebuild hflags when *leaving* reset.

In arm_set_cpu_on_async_work, we start by resetting the cpu and then start
poking at the contents of some system registers.  So, yes, we do need to
rebuild after doing that.  Also, I'm not sure how this function should fit into
the multi-phase reset future.

So:

>> On Tue, Dec 17, 2019 at 12:36 AM Niek Linnenbank <nieklinnenbank@gmail.com> wrote:
>>>
>>> After setting CP15 bits in arm_set_cpu_on() the cached hflags must
>>> be rebuild to reflect the changed processor state. Without rebuilding,
>>> the cached hflags would be inconsistent until the next call to
>>> arm_rebuild_hflags(). When QEMU is compiled with debugging enabled
>>> (--enable-debug), this problem is captured shortly after the first
>>> call to arm_set_cpu_on() for CPUs running in ARM 32-bit non-secure mode:
>>>
>>>   qemu-system-arm: target/arm/helper.c:11359: cpu_get_tb_cpu_state:
>>>   Assertion `flags == rebuild_hflags_internal(env)' failed.
>>>   Aborted (core dumped)
>>>
>>> Fixes: 0c7f8c43daf65
>>> Signed-off-by: Niek Linnenbank <nieklinnenbank@gmail.com>
>>> ---
>>>  target/arm/arm-powerctl.c | 3 +++
>>>  1 file changed, 3 insertions(+)
>>>
>>> diff --git a/target/arm/arm-powerctl.c b/target/arm/arm-powerctl.c
>>> index b064513d44..b75f813b40 100644
>>> --- a/target/arm/arm-powerctl.c
>>> +++ b/target/arm/arm-powerctl.c
>>> @@ -127,6 +127,9 @@ static void arm_set_cpu_on_async_work(CPUState *target_cpu_state,
>>>          target_cpu->env.regs[0] = info->context_id;
>>>      }
>>>
>>> +    /* CP15 update requires rebuilding hflags */
>>> +    arm_rebuild_hflags(&target_cpu->env);
>>> +
>>>      /* Start the new CPU at the requested address */
>>>      cpu_set_pc(target_cpu_state, info->entry);
>>>

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


r~


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

* Re: [PATCH v2 06/10] arm/arm-powerctl: rebuild hflags after setting CP15 bits in arm_set_cpu_on()
  2019-12-17 16:41       ` Richard Henderson
@ 2019-12-17 17:39         ` Peter Maydell
  2019-12-18 21:01         ` Niek Linnenbank
  1 sibling, 0 replies; 30+ messages in thread
From: Peter Maydell @ 2019-12-17 17:39 UTC (permalink / raw)
  To: Richard Henderson
  Cc: Niek Linnenbank, qemu-arm, Philippe Mathieu-Daudé, QEMU Developers

On Tue, 17 Dec 2019 at 16:41, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> On 12/17/19 6:12 AM, Peter Maydell wrote:
> > Cc'ing Richard : this is one for you I think... (surely we
> > need to rebuild the hflags from scratch when we power up
> > a CPU anyway?)
>
> We do compute hflags from scratch in reset.
>
> It has also turned out that there were a few board models that poked at the
> contents of the cpu and needed special help.  Some of that I would imagine
> would be fixed properly with the multi-phase reset patches, where we could
> rebuild hflags when *leaving* reset.
>
> In arm_set_cpu_on_async_work, we start by resetting the cpu and then start
> poking at the contents of some system registers.  So, yes, we do need to
> rebuild after doing that.  Also, I'm not sure how this function should fit into
> the multi-phase reset future.
>
> So:
>
> Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

Thanks; I've applied this patch to target-arm.next.

-- PMM


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

* Re: [PATCH v2 02/10] hw: arm: add Xunlong Orange Pi PC machine
  2019-12-17  7:31   ` Philippe Mathieu-Daudé
@ 2019-12-18 20:14     ` Niek Linnenbank
  2019-12-19 19:06       ` Philippe Mathieu-Daudé
  0 siblings, 1 reply; 30+ messages in thread
From: Niek Linnenbank @ 2019-12-18 20:14 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé; +Cc: Peter Maydell, qemu-arm, QEMU Developers

[-- Attachment #1: Type: text/plain, Size: 12270 bytes --]

Hi Philippe,

Thanks again for your quick and helpful feedback! :-)

On Tue, Dec 17, 2019 at 8:31 AM Philippe Mathieu-Daudé <philmd@redhat.com>
wrote:

> Hi Niek,
>
> On 12/17/19 12:35 AM, Niek Linnenbank wrote:
> > The Xunlong Orange Pi PC is an Allwinner H3 System on Chip
> > based embedded computer with mainline support in both U-Boot
> > and Linux. The board comes with a Quad Core Cortex A7 @ 1.3GHz,
> > 512MB RAM, 100Mbit ethernet, USB, SD/MMC, USB, HDMI and
> > various other I/O. This commit add support for the Xunlong
> > Orange Pi PC machine.
> >
> > Signed-off-by: Niek Linnenbank <nieklinnenbank@gmail.com>
> > Tested-by: KONRAD Frederic <frederic.konrad@adacore.com>
> > ---
> >   hw/arm/orangepi.c    | 101 +++++++++++++++++++++++++++++++++++++++++++
> >   MAINTAINERS          |   1 +
> >   hw/arm/Makefile.objs |   2 +-
> >   3 files changed, 103 insertions(+), 1 deletion(-)
> >   create mode 100644 hw/arm/orangepi.c
> >
> > diff --git a/hw/arm/orangepi.c b/hw/arm/orangepi.c
> > new file mode 100644
> > index 0000000000..62cefc8c06
> > --- /dev/null
> > +++ b/hw/arm/orangepi.c
> > @@ -0,0 +1,101 @@
> > +/*
> > + * Orange Pi emulation
> > + *
> > + * Copyright (C) 2019 Niek Linnenbank <nieklinnenbank@gmail.com>
> > + *
> > + * This program is free software: you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License as published by
> > + * the Free Software Foundation, either version 2 of the License, or
> > + * (at your option) any later version.
> > + *
> > + * This program is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > + * GNU General Public License for more details.
> > + *
> > + * 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 "exec/address-spaces.h"
> > +#include "qapi/error.h"
> > +#include "cpu.h"
> > +#include "hw/sysbus.h"
> > +#include "hw/boards.h"
> > +#include "hw/qdev-properties.h"
> > +#include "hw/arm/allwinner-h3.h"
> > +
> > +static struct arm_boot_info orangepi_binfo = {
> > +    .board_id = -1,
> > +};
> > +
> > +typedef struct OrangePiState {
> > +    AwH3State *h3;
> > +    MemoryRegion sdram;
> > +} OrangePiState;
> > +
> > +static void orangepi_init(MachineState *machine)
> > +{
> > +    OrangePiState *s = g_new(OrangePiState, 1);
> > +
> > +    /* Only allow Cortex-A7 for this board */
> > +    if (strcmp(machine->cpu_type, ARM_CPU_TYPE_NAME("cortex-a7")) != 0)
> {
> > +        error_report("This board can only be used with cortex-a7 CPU");
> > +        exit(1);
> > +    }
> > +
> > +    s->h3 = AW_H3(object_new(TYPE_AW_H3));
> > +
> > +    /* Setup timer properties */
> > +    object_property_set_int(OBJECT(&s->h3->timer), 32768, "clk0-freq",
> > +                            &error_abort);
>
> You access the timer object which is contained inside the soc object,
> but the soc isn't realized yet... I wonder if this is OK. Usually what
> we do is, either:
> - add a 'xtal-freq-hz' property to the SoC, set it here in the board,
> then in soc::realize() set the property to the timer
> - add an alias in the SoC to the timer 'freq-hz' property:
>      object_property_add_alias(soc, "xtal-freq-hz", OBJECT(&s->timer),
>                                     "freq-hz", &error_abort);
>
Good point. I shall rework that part using your suggestion.
Actually, I copied the timer support code from the existing cubieboard.c
that has
the Allwinner A10, so potentially the same problem is there.

While looking more closer at this part, I now also discovered that the
timer module from the Allwinner H3 is
mostly a stripped down version of the timer module in the Allwinner A10:

  Allwinner A10, 10.2 Timer Register List, page 85:
  https://linux-sunxi.org/images/1/1e/Allwinner_A10_User_manual_V1.5.pdf

The A10 version has six timers, where the H3 has only two. That should be
fine I would say, the guest would simply
use those available on H3 and ignore the rest. There is however one
conflicting difference: the WDOG0 registers in the Allwinner H3 start
at a different offset and are also different. The current A10 timer does
not currently implement the watchdog part.

The watchdog part of this timer is relevant for the 'reset' command in
U-Boot: that does not work right now, because
U-Boot implements the reset for the Allwinner H3 boards by letting this
watchdog expire (and we dont emulate it).
Also, this timer module is required for booting Linux, without it the
kernel crashes using the sunxi_defconfig:

[    0.000000] PC is at sun4i_timer_init+0x34/0x168
[    0.000000] LR is at sun4i_timer_init+0x2c/0x168
[    0.000000] pc : [<c07fa634>]    lr : [<c07fa62c>]    psr: 600000d3
[    0.000000] sp : c0a03f70  ip : eec00188  fp : ef7ed040
...
[    0.000000] [<c07fa634>] (sun4i_timer_init) from [<c07fa4e8>]
(timer_probe+0x74/0xe4)
[    0.000000] [<c07fa4e8>] (timer_probe) from [<c07d9c10>]
(start_kernel+0x2e0/0x440)
[    0.000000] [<c07d9c10>] (start_kernel) from [<00000000>] (0x0)


So in my opinion its a bit of a trade off here: we can keep it like this
and re-use the A10 timer for now, and perhaps
attempt to generalize that module for proper use in both SoCs. Or we can
introduce a new H3 specific timer module.
What do you think?


>
> Also, if you use &error_abort, a failure in object_property_set_int()
> triggers abort(). See "qapi/error.h":
>
>   * If @errp is &error_abort, print a suitable message and abort().
>   * If @errp is &error_fatal, print a suitable message and exit(1).
>
> > +    if (error_abort != NULL) {
> > +        error_reportf_err(error_abort, "Couldn't set clk0 frequency: ");
> > +        exit(1);
> > +    }
>
> So this if() block is useless.
>
> Ah ok, I'll remove them.


> > +
> > +    object_property_set_int(OBJECT(&s->h3->timer), 24000000,
> "clk1-freq",
> > +                            &error_abort);
> > +    if (error_abort != NULL) {
> > +        error_reportf_err(error_abort, "Couldn't set clk1 frequency: ");
> > +        exit(1);
> > +    }
>
> Similarly, remove if() block.
>
> > +
> > +    /* Mark H3 object realized */
> > +    object_property_set_bool(OBJECT(s->h3), true, "realized",
> &error_abort);
> > +    if (error_abort != NULL) {
> > +        error_reportf_err(error_abort, "Couldn't realize Allwinner H3:
> ");
> > +        exit(1);
> > +    }
>
> Similarly, remove if() block.
>
> > +
> > +    /* RAM */
> > +    if (machine->ram_size > 1 * GiB) {
> > +        error_report("Requested ram size is too large for this machine:
> "
> > +                     "maximum is 1GB");
>
> Per http://www.orangepi.org/orangepipc/ this board comes with a specific
> amount of RAM. I'd enforce the default (1GiB) and refuse other cases.
>

OK sure, I'll change it to a enforcing 1GiB. I do recall we briefly
discussed this
in v1. Then we agreed to make it an upper limit for use cases where
resources are
limited which is why I changed it like this.


> I noticed this by testing your series, without specifying the memory
> size you suggested in the cover (512) it defaults to 128 MiB, and the
> Raspian userland fails:
>

Indeed! By the way, this is also the case for U-Boot: it freezes when using
128MiB.
Actually when working on the initial code I searched a bit for a way
to set a default ram size, but could not find it at that time. But now I
see in your comment below,
it can be done simply with mc->default_ram_size. Thanks a lot, I will
surely add that!


>
> [ ***  ] (2 of 4) A start job is running for…Persistent Storage (37s /
> 2min 1s)
> [  *** ] (2 of 4) A start job is running for…Persistent Storage (38s /
> 2min 1s)
> [  OK  ] Started Flush Journal to Persistent Storage.
> Starting Create Volatile Files and Directories...
> Starting Armbian ZRAM config...
> [    **] (3 of 6) A start job is running for…s and Directories (55s / no
> limit)
> [     *] (3 of 6) A start job is running for…s and Directories (55s / no
> limit)
> [    **] (3 of 6) A start job is running for…s and Directories (56s / no
> limit)
> [  OK  ] Started Create Volatile Files and Directories.
> [***   ] (5 of 6) A start job is running for… ZRAM config (1min 10s /
> 1min 19s)
> [**    ] (5 of 6) A start job is running for… ZRAM config (1min 12s /
> 1min 19s)
> [*     ] (5 of 6) A start job is running for… ZRAM config (1min 13s /
> 1min 19s)
> [FAILED] Failed to start Armbian ZRAM config.
> See 'systemctl status armbian-zram-config.service' for details.
>
> > +        exit(1);
> > +    }
> > +    memory_region_allocate_system_memory(&s->sdram, NULL,
> "orangepi.ram",
>
> There is only one type of ram on this machine, I'd simply name this
> "sdram".
>

OK!


> > +                                         machine->ram_size);
> > +    memory_region_add_subregion(get_system_memory(),
> s->h3->memmap[AW_H3_SDRAM],
> > +                                &s->sdram);
> > +
> > +    /* Load target kernel */
> > +    orangepi_binfo.loader_start = s->h3->memmap[AW_H3_SDRAM];
> > +    orangepi_binfo.ram_size = machine->ram_size;
> > +    orangepi_binfo.nb_cpus  = AW_H3_NUM_CPUS;
> > +    arm_load_kernel(ARM_CPU(first_cpu), machine, &orangepi_binfo);
>
> I wonder if we should tell the user '-bios' is not supported on this
> machine.
>

Good suggestion, its not handled, at least not anywhere in the code I added
for H3 support.
Shall I make it an error_report followed by exit(1), similar to the 1GiB
check?


>
> > +}
> > +
> > +static void orangepi_machine_init(MachineClass *mc)
> > +{
> > +    mc->desc = "Orange Pi PC";
> > +    mc->init = orangepi_init;
> > +    mc->units_per_default_bus = 1;
>
> Maybe "units_per_default_bus = 1" belongs to patch 9 "add SD/MMC host
> controller".
>
True, it should be in patch 9 indeed. I overlooked this when separating the
work in individual patches.
Now I am also wondering if I actually need this setting. Without it, the SD
device still works fine.
I did some greps in the code to discover what it is used for, but its not
very clear to me yet. Is this ment to
restrict machines to only one harddisk (or SD card)? If I try to supply
multiple SD cards with multiple -sd arguments,
this error is printed, regardless of having units_per_default_bus=1 or not:
   qemu-system-arm: -sd test3.ext2: machine type does not support
if=sd,bus=1,unit=0


>
> > +    mc->min_cpus = AW_H3_NUM_CPUS;
> > +    mc->max_cpus = AW_H3_NUM_CPUS;
> > +    mc->default_cpus = AW_H3_NUM_CPUS;
> > +    mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a7");
>
> Please add:
>
>         mc->default_ram_size = 1 * GiB;
>
Yes, thanks!


>
> > +}
> > +
> > +DEFINE_MACHINE("orangepi-pc", orangepi_machine_init)
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index aae1a049b4..db682e49ca 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -486,6 +486,7 @@ L: qemu-arm@nongnu.org
> >   S: Maintained
> >   F: hw/*/allwinner-h3*
> >   F: include/hw/*/allwinner-h3*
> > +F: hw/arm/orangepi.c
> >
> >   ARM PrimeCell and CMSDK devices
> >   M: Peter Maydell <peter.maydell@linaro.org>
> > diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
> > index 956e496052..8d5ea453d5 100644
> > --- a/hw/arm/Makefile.objs
> > +++ b/hw/arm/Makefile.objs
> > @@ -34,7 +34,7 @@ obj-$(CONFIG_DIGIC) += digic.o
> >   obj-$(CONFIG_OMAP) += omap1.o omap2.o
> >   obj-$(CONFIG_STRONGARM) += strongarm.o
> >   obj-$(CONFIG_ALLWINNER_A10) += allwinner-a10.o cubieboard.o
> > -obj-$(CONFIG_ALLWINNER_H3) += allwinner-h3.o
> > +obj-$(CONFIG_ALLWINNER_H3) += allwinner-h3.o orangepi.o
> >   obj-$(CONFIG_RASPI) += bcm2835_peripherals.o bcm2836.o raspi.o
> >   obj-$(CONFIG_STM32F205_SOC) += stm32f205_soc.o
> >   obj-$(CONFIG_XLNX_ZYNQMP_ARM) += xlnx-zynqmp.o xlnx-zcu102.o
> >
>
>
Regards,
Niek

-- 
Niek Linnenbank

[-- Attachment #2: Type: text/html, Size: 16700 bytes --]

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

* Re: [PATCH v2 08/10] arm: allwinner-h3: add Security Identifier device
  2019-12-17  7:45   ` Philippe Mathieu-Daudé
@ 2019-12-18 20:49     ` Niek Linnenbank
  2019-12-30 14:49       ` Philippe Mathieu-Daudé
  0 siblings, 1 reply; 30+ messages in thread
From: Niek Linnenbank @ 2019-12-18 20:49 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé; +Cc: Peter Maydell, qemu-arm, QEMU Developers

[-- Attachment #1: Type: text/plain, Size: 16346 bytes --]

Hi Philippe,

On Tue, Dec 17, 2019 at 8:45 AM Philippe Mathieu-Daudé <philmd@redhat.com>
wrote:

> Hi Niek,
>
> On 12/17/19 12:35 AM, Niek Linnenbank wrote:
> > The Security Identifier device in Allwinner H3 System on Chip
> > gives applications a per-board unique identifier. This commit
> > adds support for the Allwinner H3 Security Identifier using
> > a 128-bit UUID value as input.
> >
> > Signed-off-by: Niek Linnenbank <nieklinnenbank@gmail.com>
> > ---
> >   include/hw/arm/allwinner-h3.h      |   2 +
> >   include/hw/misc/allwinner-h3-sid.h |  40 +++++++
> >   hw/arm/allwinner-h3.c              |   7 ++
> >   hw/arm/orangepi.c                  |   4 +
> >   hw/misc/allwinner-h3-sid.c         | 179 +++++++++++++++++++++++++++++
> >   hw/misc/Makefile.objs              |   1 +
> >   hw/misc/trace-events               |   4 +
> >   7 files changed, 237 insertions(+)
> >   create mode 100644 include/hw/misc/allwinner-h3-sid.h
> >   create mode 100644 hw/misc/allwinner-h3-sid.c
> >
> > diff --git a/include/hw/arm/allwinner-h3.h
> b/include/hw/arm/allwinner-h3.h
> > index 8128ae6131..c98c1972a6 100644
> > --- a/include/hw/arm/allwinner-h3.h
> > +++ b/include/hw/arm/allwinner-h3.h
> > @@ -29,6 +29,7 @@
> >   #include "hw/misc/allwinner-h3-clk.h"
> >   #include "hw/misc/allwinner-h3-cpucfg.h"
> >   #include "hw/misc/allwinner-h3-syscon.h"
> > +#include "hw/misc/allwinner-h3-sid.h"
> >   #include "target/arm/cpu.h"
> >
> >   enum {
> > @@ -77,6 +78,7 @@ typedef struct AwH3State {
> >       AwH3ClockState ccu;
> >       AwH3CpuCfgState cpucfg;
> >       AwH3SysconState syscon;
> > +    AwH3SidState sid;
> >       GICState gic;
> >       MemoryRegion sram_a1;
> >       MemoryRegion sram_a2;
> > diff --git a/include/hw/misc/allwinner-h3-sid.h
> b/include/hw/misc/allwinner-h3-sid.h
> > new file mode 100644
> > index 0000000000..79c9a24459
> > --- /dev/null
> > +++ b/include/hw/misc/allwinner-h3-sid.h
> > @@ -0,0 +1,40 @@
> > +/*
> > + * Allwinner H3 Security ID emulation
> > + *
> > + * Copyright (C) 2019 Niek Linnenbank <nieklinnenbank@gmail.com>
> > + *
> > + * This program is free software: you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License as published by
> > + * the Free Software Foundation, either version 2 of the License, or
> > + * (at your option) any later version.
> > + *
> > + * This program is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > + * GNU General Public License for more details.
> > + *
> > + * 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_MISC_ALLWINNER_H3_SID_H
> > +#define HW_MISC_ALLWINNER_H3_SID_H
> > +
> > +#include "hw/sysbus.h"
> > +#include "qemu/uuid.h"
> > +
> > +#define TYPE_AW_H3_SID    "allwinner-h3-sid"
> > +#define AW_H3_SID(obj)    OBJECT_CHECK(AwH3SidState, (obj),
> TYPE_AW_H3_SID)
> > +
> > +typedef struct AwH3SidState {
> > +    /*< private >*/
> > +    SysBusDevice parent_obj;
> > +    /*< public >*/
> > +
> > +    MemoryRegion iomem;
> > +    uint32_t control;
> > +    uint32_t rdkey;
> > +    QemuUUID identifier;
> > +} AwH3SidState;
> > +
> > +#endif
> > diff --git a/hw/arm/allwinner-h3.c b/hw/arm/allwinner-h3.c
> > index 1a9748ab2e..ba34f905cd 100644
> > --- a/hw/arm/allwinner-h3.c
> > +++ b/hw/arm/allwinner-h3.c
> > @@ -196,6 +196,9 @@ static void aw_h3_init(Object *obj)
> >
> >       sysbus_init_child_obj(obj, "cpucfg", &s->cpucfg, sizeof(s->cpucfg),
> >                             TYPE_AW_H3_CPUCFG);
> > +
> > +    sysbus_init_child_obj(obj, "sid", &s->sid, sizeof(s->sid),
> > +                          TYPE_AW_H3_SID);
>
> Here add a property alias:
>
>         object_property_add_alias(obj, "identifier", OBJECT(&s->sid),
>                                   "identifier", &error_abort);
>
> >   }
> >
> >   static void aw_h3_realize(DeviceState *dev, Error **errp)
> > @@ -332,6 +335,10 @@ static void aw_h3_realize(DeviceState *dev, Error
> **errp)
> >       qdev_init_nofail(DEVICE(&s->cpucfg));
> >       sysbus_mmio_map(SYS_BUS_DEVICE(&s->cpucfg), 0,
> s->memmap[AW_H3_CPUCFG]);
> >
> > +    /* Security Identifier */
> > +    qdev_init_nofail(DEVICE(&s->sid));
> > +    sysbus_mmio_map(SYS_BUS_DEVICE(&s->sid), 0, s->memmap[AW_H3_SID]);
> > +
> >       /* Universal Serial Bus */
> >       sysbus_create_simple(TYPE_AW_H3_EHCI, s->memmap[AW_H3_EHCI0],
> >                            qdev_get_gpio_in(DEVICE(&s->gic),
> > diff --git a/hw/arm/orangepi.c b/hw/arm/orangepi.c
> > index 62cefc8c06..b01c4b4f01 100644
> > --- a/hw/arm/orangepi.c
> > +++ b/hw/arm/orangepi.c
> > @@ -62,6 +62,10 @@ static void orangepi_init(MachineState *machine)
> >           exit(1);
> >       }
> >
> > +    /* Setup SID properties */
> > +    qdev_prop_set_string(DEVICE(&s->h3->sid), "identifier",
> > +                         "8100c002-0001-0002-0003-000044556677");
>
> And here use the alias:
>
>         qdev_prop_set_string(DEVICE(&s->h3), "identifier",
>                              "8100c002-0001-0002-0003-000044556677");
>

Ah OK, I see what you mean. The boards should be using the SoC object only
and
not directly any of its sub devices, correct?



>
> What means this value? Don't you want to be able to set it from command
> line?
>
The first word 0x02c00081 is the identifying word for the H3 SoC in the SID
data.
After that come the per-device unique specific bytes. This is documented at
the end of this page in 'Currently known SID's' on the linux-sunxi.org Wiki:
  https://linux-sunxi.org/SID_Register_Guide

The remaining parts of this value I simply made up without any real meaning.
And yes, it would in fact make sense to have the user be able to override
it from the command line.
It is used by U-boot as an input for generating the MAC address. Linux also
reads it, but I did not investigate
how it us used there. I think I did make a TODO of using a cmdline
argument, but later forgot to actually implement it.

Do you have a suggestion how to best provide the command line argument? I
do see '-device driver[,prop=value]'
is there in the --help for qemu-system-arm, but it looks like that should
be used by the user for adding PCI / USB devices?


> >       /* Mark H3 object realized */
> >       object_property_set_bool(OBJECT(s->h3), true, "realized",
> &error_abort);
> >       if (error_abort != NULL) {
> > diff --git a/hw/misc/allwinner-h3-sid.c b/hw/misc/allwinner-h3-sid.c
> > new file mode 100644
> > index 0000000000..c472f2bcc6
> > --- /dev/null
> > +++ b/hw/misc/allwinner-h3-sid.c
> > @@ -0,0 +1,179 @@
> > +/*
> > + * Allwinner H3 Security ID emulation
> > + *
> > + * Copyright (C) 2019 Niek Linnenbank <nieklinnenbank@gmail.com>
> > + *
> > + * This program is free software: you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License as published by
> > + * the Free Software Foundation, either version 2 of the License, or
> > + * (at your option) any later version.
> > + *
> > + * This program is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > + * GNU General Public License for more details.
> > + *
> > + * 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/units.h"
> > +#include "hw/sysbus.h"
> > +#include "migration/vmstate.h"
> > +#include "qemu/log.h"
> > +#include "qemu/module.h"
> > +#include "qemu/guest-random.h"
> > +#include "qapi/error.h"
> > +#include "hw/qdev-properties.h"
> > +#include "hw/misc/allwinner-h3-sid.h"
> > +#include "trace.h"
> > +
> > +/* SID register offsets */
> > +enum {
> > +    REG_PRCTL = 0x40,   /* Control */
> > +    REG_RDKEY = 0x60,   /* Read Key */
> > +};
> > +
> > +/* SID register flags */
> > +enum {
> > +    REG_PRCTL_WRITE   = 0x0002, /* Unknown write flag */
> > +    REG_PRCTL_OP_LOCK = 0xAC00, /* Lock operation */
> > +};
> > +
> > +static uint64_t allwinner_h3_sid_read(void *opaque, hwaddr offset,
> > +                                      unsigned size)
> > +{
> > +    const AwH3SidState *s = (AwH3SidState *)opaque;
> > +    uint64_t val = 0;
> > +
> > +    switch (offset) {
> > +    case REG_PRCTL:    /* Control */
> > +        val = s->control;
> > +        break;
> > +    case REG_RDKEY:    /* Read Key */
> > +        val = s->rdkey;
> > +        break;
> > +    default:
> > +        qemu_log_mask(LOG_GUEST_ERROR, "%s: bad read offset 0x%04x\n",
> > +                      __func__, (uint32_t)offset);
> > +        return 0;
> > +    }
> > +
> > +    trace_allwinner_h3_sid_read(offset, val, size);
> > +
> > +    return val;
> > +}
> > +
> > +static void allwinner_h3_sid_write(void *opaque, hwaddr offset,
> > +                                   uint64_t val, unsigned size)
> > +{
> > +    AwH3SidState *s = (AwH3SidState *)opaque;
> > +
> > +    trace_allwinner_h3_sid_write(offset, val, size);
> > +
> > +    switch (offset) {
> > +    case REG_PRCTL:    /* Control */
> > +        s->control = val;
> > +
> > +        if ((s->control & REG_PRCTL_OP_LOCK) &&
> > +            (s->control & REG_PRCTL_WRITE)) {
> > +            uint32_t id = s->control >> 16;
> > +
> > +            if (id < sizeof(QemuUUID)) {
> > +                s->rdkey = (s->identifier.data[id]) |
> > +                           (s->identifier.data[id + 1] << 8) |
> > +                           (s->identifier.data[id + 2] << 16) |
> > +                           (s->identifier.data[id + 3] << 24);
>
> This is:
>
>                     s->rdkey = ldl_le_p(&s->identifier.data[id]);
>
> > +            }
> > +        }
> > +        s->control &= ~REG_PRCTL_WRITE;
> > +        break;
> > +    case REG_RDKEY:    /* Read Key */
>
> Read in a write()?
>
> Maybe we can simply /* fall through */ LOG_GUEST_ERROR?
>

When writing this module, I looked at how U-Boot is using the SID registers
and simply
named the registers after the names used by U-Boot. You can find this part
in arch/arm/mach-sunxi/cpu_info.c:111,
functions sun8i_efuse_read() and sunxi_get_sid(). U-Boot defines
SIDC_RDKEY, so I named the register also rdkey.
I used the U-Boot source because the Allwinner H3 datasheet does not
document the registers. Later I
found the SID page on the linux-sunxi wiki that I mentioned earlier, and
they also describe the same register names:

   https://linux-sunxi.org/SID_Register_Guide

I suspect the information on this page is written based on the source code
from the original SDK (which I did not study btw)


>
> > +        break;
> > +    default:
> > +        qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write offset 0x%04x\n",
> > +                      __func__, (uint32_t)offset);
> > +        break;
> > +    }
> > +}
> > +
> > +static const MemoryRegionOps allwinner_h3_sid_ops = {
> > +    .read = allwinner_h3_sid_read,
> > +    .write = allwinner_h3_sid_write,
> > +    .endianness = DEVICE_NATIVE_ENDIAN,
> > +    .valid = {
> > +        .min_access_size = 4,
> > +        .max_access_size = 4,
> > +        .unaligned = false
>
> 'false' is the default value, maybe we can omit it?
>

Sure, I'll remove it.


>
> > +    },
> > +    .impl.min_access_size = 4,
> > +};
> > +
> > +static void allwinner_h3_sid_reset(DeviceState *dev)
> > +{
> > +    AwH3SidState *s = AW_H3_SID(dev);
> > +
> > +    /* Set default values for registers */
> > +    s->control = 0;
> > +    s->rdkey = 0;
> > +}
> > +
> > +static void allwinner_h3_sid_realize(DeviceState *dev, Error **errp)
> > +{
> > +}
>
> If you don't need realize(), just remove it. However maybe we want to
> check if the identifier is null, either warn/abort or generate a random
> one?
>
OK, removing it!


>
> > +
> > +static void allwinner_h3_sid_init(Object *obj)
> > +{
> > +    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
> > +    AwH3SidState *s = AW_H3_SID(obj);
> > +
> > +    /* Fill UUID with zeroes by default */
> > +    qemu_uuid_parse(UUID_NONE, &s->identifier);
>
> AwH3SidState is zeroed just before this init() call. I think we don't
> need to zeroes the UUID again.
>

Ah OK, so you mean new objects are always zeroed. That makes it
much easier indeed. Thanks, I'll remove those lines.


>
> > +
> > +    /* Memory mapping */
> > +    memory_region_init_io(&s->iomem, OBJECT(s), &allwinner_h3_sid_ops,
> s,
> > +                          TYPE_AW_H3_SID, 1 * KiB);
> > +    sysbus_init_mmio(sbd, &s->iomem);
> > +}
> > +
> > +static Property allwinner_h3_sid_properties[] = {
> > +    DEFINE_PROP_UUID_NODEFAULT("identifier", AwH3SidState, identifier),
> > +    DEFINE_PROP_END_OF_LIST()
> > +};
> > +
> > +static const VMStateDescription allwinner_h3_sid_vmstate = {
> > +    .name = "allwinner-h3-sid",
> > +    .version_id = 1,
> > +    .minimum_version_id = 1,
> > +    .fields = (VMStateField[]) {
> > +        VMSTATE_UINT32(control, AwH3SidState),
> > +        VMSTATE_UINT32(rdkey, AwH3SidState),
> > +        VMSTATE_END_OF_LIST()
> > +    }
> > +};
> > +
> > +static void allwinner_h3_sid_class_init(ObjectClass *klass, void *data)
> > +{
> > +    DeviceClass *dc = DEVICE_CLASS(klass);
> > +
> > +    dc->reset = allwinner_h3_sid_reset;
> > +    dc->realize = allwinner_h3_sid_realize;
> > +    dc->vmsd = &allwinner_h3_sid_vmstate;
> > +    dc->props = allwinner_h3_sid_properties;
> > +}
> > +
> > +static const TypeInfo allwinner_h3_sid_info = {
> > +    .name          = TYPE_AW_H3_SID,
> > +    .parent        = TYPE_SYS_BUS_DEVICE,
> > +    .instance_init = allwinner_h3_sid_init,
> > +    .instance_size = sizeof(AwH3SidState),
> > +    .class_init    = allwinner_h3_sid_class_init,
> > +};
> > +
> > +static void allwinner_h3_sid_register(void)
> > +{
> > +    type_register_static(&allwinner_h3_sid_info);
> > +}
> > +
> > +type_init(allwinner_h3_sid_register)
> > diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
> > index c4ca2ed689..f3620eee4e 100644
> > --- a/hw/misc/Makefile.objs
> > +++ b/hw/misc/Makefile.objs
> > @@ -31,6 +31,7 @@ common-obj-$(CONFIG_IVSHMEM_DEVICE) += ivshmem.o
> >   common-obj-$(CONFIG_ALLWINNER_H3) += allwinner-h3-clk.o
> >   obj-$(CONFIG_ALLWINNER_H3) += allwinner-h3-cpucfg.o
> >   common-obj-$(CONFIG_ALLWINNER_H3) += allwinner-h3-syscon.o
> > +common-obj-$(CONFIG_ALLWINNER_H3) += allwinner-h3-sid.o
> >   common-obj-$(CONFIG_REALVIEW) += arm_sysctl.o
> >   common-obj-$(CONFIG_NSERIES) += cbus.o
> >   common-obj-$(CONFIG_ECCMEMCTL) += eccmemctl.o
> > diff --git a/hw/misc/trace-events b/hw/misc/trace-events
> > index b93089d010..a777844ca3 100644
> > --- a/hw/misc/trace-events
> > +++ b/hw/misc/trace-events
> > @@ -5,6 +5,10 @@ allwinner_h3_cpucfg_cpu_reset(uint8_t cpu_id, uint32_t
> reset_addr) "H3-CPUCFG: c
> >   allwinner_h3_cpucfg_read(uint64_t offset, uint64_t data, unsigned
> size) "H3-CPUCFG: read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %"
> PRIu32
> >   allwinner_h3_cpucfg_write(uint64_t offset, uint64_t data, unsigned
> size) "H3-CPUCFG: write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %"
> PRIu32
> >
> > +# allwinner-h3-sid.c
> > +allwinner_h3_sid_read(uint64_t offset, uint64_t data, unsigned size)
> "H3-SID: read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32
> > +allwinner_h3_sid_write(uint64_t offset, uint64_t data, unsigned size)
> "H3-SID: write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32
> > +
> >   # eccmemctl.c
> >   ecc_mem_writel_mer(uint32_t val) "Write memory enable 0x%08x"
> >   ecc_mem_writel_mdr(uint32_t val) "Write memory delay 0x%08x"
> >
>
>
Regards,
Niek

-- 
Niek Linnenbank

[-- Attachment #2: Type: text/html, Size: 21657 bytes --]

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

* Re: [PATCH v2 06/10] arm/arm-powerctl: rebuild hflags after setting CP15 bits in arm_set_cpu_on()
  2019-12-17 16:41       ` Richard Henderson
  2019-12-17 17:39         ` Peter Maydell
@ 2019-12-18 21:01         ` Niek Linnenbank
  2019-12-18 23:25           ` Richard Henderson
  1 sibling, 1 reply; 30+ messages in thread
From: Niek Linnenbank @ 2019-12-18 21:01 UTC (permalink / raw)
  To: Richard Henderson
  Cc: Peter Maydell, qemu-arm, Philippe Mathieu-Daudé, QEMU Developers

[-- Attachment #1: Type: text/plain, Size: 3142 bytes --]

Hello Richard,

On Tue, Dec 17, 2019 at 5:41 PM Richard Henderson <
richard.henderson@linaro.org> wrote:

> On 12/17/19 6:12 AM, Peter Maydell wrote:
> > Cc'ing Richard : this is one for you I think... (surely we
> > need to rebuild the hflags from scratch when we power up
> > a CPU anyway?)
>
> We do compute hflags from scratch in reset.
>
> It has also turned out that there were a few board models that poked at the
> contents of the cpu and needed special help.  Some of that I would imagine
> would be fixed properly with the multi-phase reset patches, where we could
> rebuild hflags when *leaving* reset.
>
> In arm_set_cpu_on_async_work, we start by resetting the cpu and then start
> poking at the contents of some system registers.  So, yes, we do need to
> rebuild after doing that.  Also, I'm not sure how this function should fit
> into
> the multi-phase reset future.
>

Great, thanks a lot for confirming and clarifying this!
You mention the multi-phase reset feature, is that going to replace the
arm_set_cpu_on() functionality?
Currently I chose to use this function for implementing the CPU
configuration module in the Allwinner H3 Soc.
U-Boot needs the CPU configuration module to provide PSCI which Linux uses
to bring up the secondary cores.
And basically the CPU configuration module needs something to let the
secondary CPUs power on, reset and start executing at some address.

Would you suggest to keep using arm_set_cpu_on() for this, or should I
instead use a different function?

Regards,
Niek

>
> So:
>
> >> On Tue, Dec 17, 2019 at 12:36 AM Niek Linnenbank <
> nieklinnenbank@gmail.com> wrote:
> >>>
> >>> After setting CP15 bits in arm_set_cpu_on() the cached hflags must
> >>> be rebuild to reflect the changed processor state. Without rebuilding,
> >>> the cached hflags would be inconsistent until the next call to
> >>> arm_rebuild_hflags(). When QEMU is compiled with debugging enabled
> >>> (--enable-debug), this problem is captured shortly after the first
> >>> call to arm_set_cpu_on() for CPUs running in ARM 32-bit non-secure
> mode:
> >>>
> >>>   qemu-system-arm: target/arm/helper.c:11359: cpu_get_tb_cpu_state:
> >>>   Assertion `flags == rebuild_hflags_internal(env)' failed.
> >>>   Aborted (core dumped)
> >>>
> >>> Fixes: 0c7f8c43daf65
> >>> Signed-off-by: Niek Linnenbank <nieklinnenbank@gmail.com>
> >>> ---
> >>>  target/arm/arm-powerctl.c | 3 +++
> >>>  1 file changed, 3 insertions(+)
> >>>
> >>> diff --git a/target/arm/arm-powerctl.c b/target/arm/arm-powerctl.c
> >>> index b064513d44..b75f813b40 100644
> >>> --- a/target/arm/arm-powerctl.c
> >>> +++ b/target/arm/arm-powerctl.c
> >>> @@ -127,6 +127,9 @@ static void arm_set_cpu_on_async_work(CPUState
> *target_cpu_state,
> >>>          target_cpu->env.regs[0] = info->context_id;
> >>>      }
> >>>
> >>> +    /* CP15 update requires rebuilding hflags */
> >>> +    arm_rebuild_hflags(&target_cpu->env);
> >>> +
> >>>      /* Start the new CPU at the requested address */
> >>>      cpu_set_pc(target_cpu_state, info->entry);
> >>>
>
> Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
>
>
> r~
>


-- 
Niek Linnenbank

[-- Attachment #2: Type: text/html, Size: 4557 bytes --]

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

* Re: [PATCH v2 06/10] arm/arm-powerctl: rebuild hflags after setting CP15 bits in arm_set_cpu_on()
  2019-12-18 21:01         ` Niek Linnenbank
@ 2019-12-18 23:25           ` Richard Henderson
  0 siblings, 0 replies; 30+ messages in thread
From: Richard Henderson @ 2019-12-18 23:25 UTC (permalink / raw)
  To: Niek Linnenbank
  Cc: Peter Maydell, qemu-arm, Philippe Mathieu-Daudé, QEMU Developers

On 12/18/19 11:01 AM, Niek Linnenbank wrote:
> Hello Richard,
> 
> On Tue, Dec 17, 2019 at 5:41 PM Richard Henderson <richard.henderson@linaro.org
> <mailto:richard.henderson@linaro.org>> wrote:
> 
>     On 12/17/19 6:12 AM, Peter Maydell wrote:
>     > Cc'ing Richard : this is one for you I think... (surely we
>     > need to rebuild the hflags from scratch when we power up
>     > a CPU anyway?)
> 
>     We do compute hflags from scratch in reset.
> 
>     It has also turned out that there were a few board models that poked at the
>     contents of the cpu and needed special help.  Some of that I would imagine
>     would be fixed properly with the multi-phase reset patches, where we could
>     rebuild hflags when *leaving* reset.
> 
>     In arm_set_cpu_on_async_work, we start by resetting the cpu and then start
>     poking at the contents of some system registers.  So, yes, we do need to
>     rebuild after doing that.  Also, I'm not sure how this function should fit into
>     the multi-phase reset future.
> 
> 
> Great, thanks a lot for confirming and clarifying this!
> You mention the multi-phase reset feature, is that going to replace the
> arm_set_cpu_on() functionality?

I don't think so, but I'm not sure.  As I said above, I don't immediately see
how arm_set_cpu_on() will integrate.

In any case, multi-phase reset is still pending, though I believe it is high on
Peter's priority queue for the 5.0 development cycle.


r~


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

* Re: [PATCH v2 02/10] hw: arm: add Xunlong Orange Pi PC machine
  2019-12-18 20:14     ` Niek Linnenbank
@ 2019-12-19 19:06       ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 30+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-12-19 19:06 UTC (permalink / raw)
  To: Niek Linnenbank; +Cc: Peter Maydell, qemu-arm, QEMU Developers

On 12/18/19 9:14 PM, Niek Linnenbank wrote:
> Hi Philippe,
> 
> Thanks again for your quick and helpful feedback! :-)
> 
> On Tue, Dec 17, 2019 at 8:31 AM Philippe Mathieu-Daudé 
> <philmd@redhat.com <mailto:philmd@redhat.com>> wrote:
> 
>     Hi Niek,
> 
>     On 12/17/19 12:35 AM, Niek Linnenbank wrote:
>      > The Xunlong Orange Pi PC is an Allwinner H3 System on Chip
>      > based embedded computer with mainline support in both U-Boot
>      > and Linux. The board comes with a Quad Core Cortex A7 @ 1.3GHz,
>      > 512MB RAM, 100Mbit ethernet, USB, SD/MMC, USB, HDMI and
>      > various other I/O. This commit add support for the Xunlong
>      > Orange Pi PC machine.
>      >
>      > Signed-off-by: Niek Linnenbank <nieklinnenbank@gmail.com
>     <mailto:nieklinnenbank@gmail.com>>
>      > Tested-by: KONRAD Frederic <frederic.konrad@adacore.com
>     <mailto:frederic.konrad@adacore.com>>
>      > ---
>      >   hw/arm/orangepi.c    | 101
>     +++++++++++++++++++++++++++++++++++++++++++
>      >   MAINTAINERS          |   1 +
>      >   hw/arm/Makefile.objs |   2 +-
>      >   3 files changed, 103 insertions(+), 1 deletion(-)
>      >   create mode 100644 hw/arm/orangepi.c
>      >
>      > diff --git a/hw/arm/orangepi.c b/hw/arm/orangepi.c
>      > new file mode 100644
>      > index 0000000000..62cefc8c06
>      > --- /dev/null
>      > +++ b/hw/arm/orangepi.c
>      > @@ -0,0 +1,101 @@
>      > +/*
>      > + * Orange Pi emulation
>      > + *
>      > + * Copyright (C) 2019 Niek Linnenbank <nieklinnenbank@gmail.com
>     <mailto:nieklinnenbank@gmail.com>>
>      > + *
>      > + * This program is free software: you can redistribute it and/or
>     modify
>      > + * it under the terms of the GNU General Public License as
>     published by
>      > + * the Free Software Foundation, either version 2 of the License, or
>      > + * (at your option) any later version.
>      > + *
>      > + * This program is distributed in the hope that it will be useful,
>      > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>      > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>      > + * GNU General Public License for more details.
>      > + *
>      > + * 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 "exec/address-spaces.h"
>      > +#include "qapi/error.h"
>      > +#include "cpu.h"
>      > +#include "hw/sysbus.h"
>      > +#include "hw/boards.h"
>      > +#include "hw/qdev-properties.h"
>      > +#include "hw/arm/allwinner-h3.h"
>      > +
>      > +static struct arm_boot_info orangepi_binfo = {
>      > +    .board_id = -1,
>      > +};
>      > +
>      > +typedef struct OrangePiState {
>      > +    AwH3State *h3;
>      > +    MemoryRegion sdram;
>      > +} OrangePiState;
>      > +
>      > +static void orangepi_init(MachineState *machine)
>      > +{
>      > +    OrangePiState *s = g_new(OrangePiState, 1);
>      > +
>      > +    /* Only allow Cortex-A7 for this board */
>      > +    if (strcmp(machine->cpu_type,
>     ARM_CPU_TYPE_NAME("cortex-a7")) != 0) {
>      > +        error_report("This board can only be used with cortex-a7
>     CPU");
>      > +        exit(1);
>      > +    }
>      > +
>      > +    s->h3 = AW_H3(object_new(TYPE_AW_H3));
>      > +
>      > +    /* Setup timer properties */
>      > +    object_property_set_int(OBJECT(&s->h3->timer), 32768,
>     "clk0-freq",
>      > +                            &error_abort);
> 
>     You access the timer object which is contained inside the soc object,
>     but the soc isn't realized yet... I wonder if this is OK. Usually what
>     we do is, either:
>     - add a 'xtal-freq-hz' property to the SoC, set it here in the board,
>     then in soc::realize() set the property to the timer
>     - add an alias in the SoC to the timer 'freq-hz' property:
>           object_property_add_alias(soc, "xtal-freq-hz", OBJECT(&s->timer),
>                                          "freq-hz", &error_abort);
> 
> Good point. I shall rework that part using your suggestion.
> Actually, I copied the timer support code from the existing cubieboard.c 
> that has
> the Allwinner A10, so potentially the same problem is there.
> 
> While looking more closer at this part, I now also discovered that the 
> timer module from the Allwinner H3 is
> mostly a stripped down version of the timer module in the Allwinner A10:
> 
>    Allwinner A10, 10.2 Timer Register List, page 85:
> https://linux-sunxi.org/images/1/1e/Allwinner_A10_User_manual_V1.5.pdf
> 
> The A10 version has six timers, where the H3 has only two. That should 
> be fine I would say, the guest would simply
> use those available on H3 and ignore the rest. There is however one 
> conflicting difference: the WDOG0 registers in the Allwinner H3 start
> at a different offset and are also different. The current A10 timer does 
> not currently implement the watchdog part.
> 
> The watchdog part of this timer is relevant for the 'reset' command in 
> U-Boot: that does not work right now, because
> U-Boot implements the reset for the Allwinner H3 boards by letting this 
> watchdog expire (and we dont emulate it).
> Also, this timer module is required for booting Linux, without it the 
> kernel crashes using the sunxi_defconfig:
> 
> [    0.000000] PC is at sun4i_timer_init+0x34/0x168
> [    0.000000] LR is at sun4i_timer_init+0x2c/0x168
> [    0.000000] pc : [<c07fa634>]    lr : [<c07fa62c>]    psr: 600000d3
> [    0.000000] sp : c0a03f70  ip : eec00188  fp : ef7ed040
> ...
> [    0.000000] [<c07fa634>] (sun4i_timer_init) from [<c07fa4e8>] (timer_probe+0x74/0xe4)
> [    0.000000] [<c07fa4e8>] (timer_probe) from [<c07d9c10>] (start_kernel+0x2e0/0x440)
> [    0.000000] [<c07d9c10>] (start_kernel) from [<00000000>] (0x0)
> 
> 
> So in my opinion its a bit of a trade off here: we can keep it like this 
> and re-use the A10 timer for now, and perhaps
> attempt to generalize that module for proper use in both SoCs. Or we can 
> introduce a new H3 specific timer module.
> What do you think?

See my answer about generalize/reuse here:
http://mid.mail-archive.com/20191219185127.24388-1-f4bug@amsat.org



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

* Re: [PATCH v2 00/10] Add Allwinner H3 SoC and Orange Pi PC Machine
  2019-12-16 23:35 [PATCH v2 00/10] Add Allwinner H3 SoC and Orange Pi PC Machine Niek Linnenbank
                   ` (9 preceding siblings ...)
  2019-12-16 23:35 ` [PATCH v2 10/10] arm: allwinner-h3: add EMAC ethernet device Niek Linnenbank
@ 2019-12-30 11:28 ` Niek Linnenbank
  2019-12-30 14:56   ` Philippe Mathieu-Daudé
  10 siblings, 1 reply; 30+ messages in thread
From: Niek Linnenbank @ 2019-12-30 11:28 UTC (permalink / raw)
  To: QEMU Developers; +Cc: Peter Maydell, qemu-arm, Philippe Mathieu-Daudé

[-- Attachment #1: Type: text/plain, Size: 10533 bytes --]

Hi,

Here a short status report of this patch series.

For V3 update I already prepared the following:
 - reworked all review comments from Philippe, except:
   - patch#8: question for the SID, whether command-line override is
required (and how is the best way for machine-specific cli arg?) [1]
- added BootROM support, allows booting with only specifying -sd <IMG>
- added SDRAM controller driver, for U-Boot SPL
- added Allwinner generic RTC driver (for both Cubieboard and OrangePi PC,
supports sun4i, sun6i, sun7i)
- small fixes for EMAC

My current TODO:
 - integrate Philips acceptance tests in the series
 - integrate Philips work for generalizing the Allwinner timer, and finish
it
 - test and fix BSD targets (NetBSD, FreeBSD) [2, 3]
 - further generalize the series to cover very similar SoCs: H2+, H5

Does anyone have more comments/requests for the V3 update?

[1] https://lists.gnu.org/archive/html/qemu-devel/2019-12/msg04049.html
[2] https://wiki.netbsd.org/ports/evbarm/allwinner/
[3]
https://wiki.freebsd.org/action/show/arm/Allwinner?action=show&redirect=FreeBSD%2Farm%2FAllwinner

On Tue, Dec 17, 2019 at 12:35 AM Niek Linnenbank <nieklinnenbank@gmail.com>
wrote:

> Dear QEMU developers,
>
> Hereby I would like to contribute the following set of patches to QEMU
> which add support for the Allwinner H3 System on Chip and the
> Orange Pi PC machine. The following features and devices are supported:
>
>  * SMP (Quad Core Cortex A7)
>  * Generic Interrupt Controller configuration
>  * SRAM mappings
>  * Timer device (re-used from Allwinner A10)
>  * UART
>  * SD/MMC storage controller
>  * EMAC ethernet connectivity
>  * USB 2.0 interfaces
>  * Clock Control Unit
>  * System Control module
>  * Security Identifier device
>
> Functionality related to graphical output such as HDMI, GPU,
> Display Engine and audio are not included. Recently released
> mainline Linux kernels (4.19 up to latest master) and mainline U-Boot
> are known to work. The SD/MMC code is tested using bonnie++ and
> various tools such as fsck, dd and fdisk. The EMAC is verified with iperf3
> using -netdev socket.
>
> To build a Linux mainline kernel that can be booted by the Orange Pi PC
> machine, simply configure the kernel using the sunxi_defconfig
> configuration:
>  $ ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- make mrproper
>  $ ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- make sunxi_defconfig
>
> To be able to use USB storage, you need to manually enable the
> corresponding
> configuration item. Start the kconfig configuration tool:
>  $ ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- make menuconfig
>
> Navigate to the following item, enable it and save your configuration:
>  Device Drivers > USB support > USB Mass Storage support
>
> Build the Linux kernel with:
>  $ ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- make -j5
>
> To boot the newly build linux kernel in QEMU with the Orange Pi PC
> machine, use:
>  $ qemu-system-arm -M orangepi-pc -m 512 -nic user -nographic \
>      -kernel /path/to/linux/arch/arm/boot/zImage \
>      -append 'console=ttyS0,115200' \
>      -dtb /path/to/linux/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dtb
>
> Note that this kernel does not have a root filesystem. You may provide it
> with an official Orange Pi PC image [1] either as an SD card or as
> USB mass storage. To boot using the Orange Pi PC Debian image on SD card,
> simply add the -sd argument and provide the proper root= kernel parameter:
>  $ qemu-system-arm -M orangepi-pc -m 512 -nic user -nographic \
>      -kernel /path/to/linux/arch/arm/boot/zImage \
>      -append 'console=ttyS0,115200 root=/dev/mmcblk0p2' \
>      -dtb /path/to/linux/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dtb \
>      -sd OrangePi_pc_debian_stretch_server_linux5.3.5_v1.0.img
>
> Alternatively, you can also choose to build and boot a recent buildroot [2]
> using the orangepi_pc_defconfig or Armbian image [3] for Orange Pi PC.
> To attach an USB mass storage device to the machine, simply append to the
> command:
>  -drive if=none,id=stick,file=myimage.img \
>  -device usb-storage,bus=usb-bus.0,drive=stick
>
> U-Boot mainline can be build and configured using the orangepi_pc_defconfig
> using similar commands as describe above for Linux. To start U-Boot using
> the Orange Pi PC machine, provide the u-boot binary to the -kernel
> argument:
>  $ qemu-system-arm -M orangepi-pc -m 512 -nic user -nographic \
>      -kernel /path/to/uboot/u-boot -sd disk.img
>
> Use the following U-boot commands to load and boot a Linux kernel from SD
> card:
>  -> setenv bootargs console=ttyS0,115200
>  -> ext2load mmc 0 0x42000000 zImage
>  -> ext2load mmc 0 0x43000000 sun8i-h3-orangepi-pc.dtb
>  -> bootz 0x42000000 - 0x43000000
>
> Looking forward to your review comments. I will do my best
> to update the patches where needed.
>
> ===== CHANGELOG =====
>
> v2:
>  * hw/arm/allwinner-h3.c: use cpus array in AwH3State instead of
> object_new()
>  * hw/arm/allwinner-h3.c: use error_abort in aw_h3_realize()
>  * hw/arm/allwinner-h3.c: use qdev_init_nofail() in aw_h3_realize()
>  * hw/arm/allwinner-h3.c: use qdev_get_gpio_in() instead of irq array
>  * hw/arm/allwinner-h3.c: add all missing unimplemented devices (memory
> map is complete)
>  * hw/arm/allwinner-h3.c: add UART1, UART2, UART3 and remove 'if
> (serial_hd(...))'
>  * hw/arm/allwinner-h3.c: remove sysbusdev variable and use
> SYS_BUS_DEVICE() directly
>  * include/hw/arm/allwinner-h3.h: move PPI/SPI defines to allwinner-h3.c
> as enum
>  * include/hw/arm/allwinner-h3.h: replace mem base/size defines with enum
> and memmap (like aspeed_soc.h)
>  * hw/arm/orangepi.c: Only allow Cortex-A7 in machine->cpu_type
>  * hw/arm/orangepi.c: Set mc->default_cpu_type to
> ARM_CPU_TYPE_NAME("cortex-a7")
>  * hw/arm/orangepi.c: Use error_abort in orangepi_init()
>  * hw/arm/orangepi.c: only allow maximum 1GiB RAM
>  * hw/arm/orangepi.c: renamed machine name to 'orangepi-pc'
>  * hw/arm/orangepi.c: remove mc->ignore_memory_transaction_failures = true
>  * hw/arm/orangepi.c: remove unnecessary check for 'sd-bus'
>  * hw/net/allwinner-h3-emac.c: use AW_H3_EMAC() for opaque in read/write
> functions
>  * hw/sd/allwinner-h3-sdhost.c: replace register defines with enums
>  * hw/sd/allwinner-h3-sdhost.c: remove 'irq_en' and use if() to set 'irq'
> in update_irq function
>  * hw/sd/allwinner-h3-sdhost.c: simplified if (rlen==) conditions in
> send_command function
>  * hw/sd/allwinner-h3-sdhost.c: use KiB macro to set desc->size
>  * hw/sd/allwinner-h3-sdhost.c: use ARRAY_SIZE() macro in reset function
>  * hw/misc/allwinner-h3-sid.c: replace randomized identifier with QemuUUID
> property
>  * hw/misc/allwinner-h3-sid.c: add tracing for read/write functions
>  * hw/misc/allwinner-h3-sid.c: fix incorrect usage of
> REG_PRCTL_OP_LOCK/REG_PRCTL_WRITE
>  * hw/misc/trace-events: add allwinner_h3_cpucfg* entries in correct patch
> (#7)
>  * hw/*/trace-events: use PRIu32/PRIx32 macros for size and max fields
>  * hw/*/allwinner-h3-*.c: set .impl.min_access_size = 4 to restrict MMIO
> access to 32-bit aligned
>  * hw/*/allwinner-h3-*.c: replace register defines with enums
>  * hw/*/allwinner-h3-*.c: set VMStateDescription.name with inline string
> (dont use TYPE macro)
>  * include/hw/*/allwinner-h3-*.h: remove MEM_SIZE define and use size
> inline in the source file
>  * target/arm/arm-powerctl.c: invoke arm_rebuild_hflags() after setting
> CP15 bits
>
> With kind regards,
>
> Niek Linnenbank
>
> [1] http://www.orangepi.org/downloadresources/
> [2] https://buildroot.org/download.html
> [3] https://www.armbian.com/orange-pi-pc/
>
> Niek Linnenbank (10):
>   hw: arm: add Allwinner H3 System-on-Chip
>   hw: arm: add Xunlong Orange Pi PC machine
>   arm: allwinner-h3: add Clock Control Unit
>   arm: allwinner-h3: add USB host controller
>   arm: allwinner-h3: add System Control module
>   arm/arm-powerctl: rebuild hflags after setting CP15 bits in
>     arm_set_cpu_on()
>   arm: allwinner-h3: add CPU Configuration module
>   arm: allwinner-h3: add Security Identifier device
>   arm: allwinner-h3: add SD/MMC host controller
>   arm: allwinner-h3: add EMAC ethernet device
>
>  default-configs/arm-softmmu.mak       |   1 +
>  hw/usb/hcd-ehci.h                     |   1 +
>  include/hw/arm/allwinner-h3.h         |  93 +++
>  include/hw/misc/allwinner-h3-clk.h    |  40 ++
>  include/hw/misc/allwinner-h3-cpucfg.h |  42 ++
>  include/hw/misc/allwinner-h3-sid.h    |  40 ++
>  include/hw/misc/allwinner-h3-syscon.h |  42 ++
>  include/hw/net/allwinner-h3-emac.h    |  67 +++
>  include/hw/sd/allwinner-h3-sdhost.h   |  71 +++
>  hw/arm/allwinner-h3.c                 | 442 ++++++++++++++
>  hw/arm/orangepi.c                     | 127 ++++
>  hw/misc/allwinner-h3-clk.c            | 238 ++++++++
>  hw/misc/allwinner-h3-cpucfg.c         | 288 +++++++++
>  hw/misc/allwinner-h3-sid.c            | 179 ++++++
>  hw/misc/allwinner-h3-syscon.c         | 146 +++++
>  hw/net/allwinner-h3-emac.c            | 829 ++++++++++++++++++++++++++
>  hw/sd/allwinner-h3-sdhost.c           | 813 +++++++++++++++++++++++++
>  hw/usb/hcd-ehci-sysbus.c              |  17 +
>  target/arm/arm-powerctl.c             |   3 +
>  MAINTAINERS                           |   8 +
>  hw/arm/Kconfig                        |   9 +
>  hw/arm/Makefile.objs                  |   1 +
>  hw/misc/Makefile.objs                 |   4 +
>  hw/misc/trace-events                  |   9 +
>  hw/net/Kconfig                        |   3 +
>  hw/net/Makefile.objs                  |   1 +
>  hw/net/trace-events                   |  10 +
>  hw/sd/Makefile.objs                   |   1 +
>  hw/sd/trace-events                    |   7 +
>  29 files changed, 3532 insertions(+)
>  create mode 100644 include/hw/arm/allwinner-h3.h
>  create mode 100644 include/hw/misc/allwinner-h3-clk.h
>  create mode 100644 include/hw/misc/allwinner-h3-cpucfg.h
>  create mode 100644 include/hw/misc/allwinner-h3-sid.h
>  create mode 100644 include/hw/misc/allwinner-h3-syscon.h
>  create mode 100644 include/hw/net/allwinner-h3-emac.h
>  create mode 100644 include/hw/sd/allwinner-h3-sdhost.h
>  create mode 100644 hw/arm/allwinner-h3.c
>  create mode 100644 hw/arm/orangepi.c
>  create mode 100644 hw/misc/allwinner-h3-clk.c
>  create mode 100644 hw/misc/allwinner-h3-cpucfg.c
>  create mode 100644 hw/misc/allwinner-h3-sid.c
>  create mode 100644 hw/misc/allwinner-h3-syscon.c
>  create mode 100644 hw/net/allwinner-h3-emac.c
>  create mode 100644 hw/sd/allwinner-h3-sdhost.c
>
> --
> 2.17.1
>
>

-- 
Niek Linnenbank

[-- Attachment #2: Type: text/html, Size: 12712 bytes --]

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

* Re: [PATCH v2 08/10] arm: allwinner-h3: add Security Identifier device
  2019-12-18 20:49     ` Niek Linnenbank
@ 2019-12-30 14:49       ` Philippe Mathieu-Daudé
  2020-01-07 21:53         ` Niek Linnenbank
  0 siblings, 1 reply; 30+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-12-30 14:49 UTC (permalink / raw)
  To: Niek Linnenbank; +Cc: Peter Maydell, qemu-arm, QEMU Developers

On 12/18/19 9:49 PM, Niek Linnenbank wrote:
> Hi Philippe,
> 
> On Tue, Dec 17, 2019 at 8:45 AM Philippe Mathieu-Daudé 
> <philmd@redhat.com <mailto:philmd@redhat.com>> wrote:
> 
>     Hi Niek,
> 
>     On 12/17/19 12:35 AM, Niek Linnenbank wrote:
>      > The Security Identifier device in Allwinner H3 System on Chip
>      > gives applications a per-board unique identifier. This commit
>      > adds support for the Allwinner H3 Security Identifier using
>      > a 128-bit UUID value as input.
>      >
>      > Signed-off-by: Niek Linnenbank <nieklinnenbank@gmail.com
>     <mailto:nieklinnenbank@gmail.com>>
>      > ---
>      >   include/hw/arm/allwinner-h3.h      |   2 +
>      >   include/hw/misc/allwinner-h3-sid.h |  40 +++++++
>      >   hw/arm/allwinner-h3.c              |   7 ++
>      >   hw/arm/orangepi.c                  |   4 +
>      >   hw/misc/allwinner-h3-sid.c         | 179
>     +++++++++++++++++++++++++++++
>      >   hw/misc/Makefile.objs              |   1 +
>      >   hw/misc/trace-events               |   4 +
>      >   7 files changed, 237 insertions(+)
>      >   create mode 100644 include/hw/misc/allwinner-h3-sid.h
>      >   create mode 100644 hw/misc/allwinner-h3-sid.c
>      >
>      > diff --git a/include/hw/arm/allwinner-h3.h
>     b/include/hw/arm/allwinner-h3.h
>      > index 8128ae6131..c98c1972a6 100644
>      > --- a/include/hw/arm/allwinner-h3.h
>      > +++ b/include/hw/arm/allwinner-h3.h
>      > @@ -29,6 +29,7 @@
>      >   #include "hw/misc/allwinner-h3-clk.h"
>      >   #include "hw/misc/allwinner-h3-cpucfg.h"
>      >   #include "hw/misc/allwinner-h3-syscon.h"
>      > +#include "hw/misc/allwinner-h3-sid.h"
>      >   #include "target/arm/cpu.h"
>      >
>      >   enum {
>      > @@ -77,6 +78,7 @@ typedef struct AwH3State {
>      >       AwH3ClockState ccu;
>      >       AwH3CpuCfgState cpucfg;
>      >       AwH3SysconState syscon;
>      > +    AwH3SidState sid;
>      >       GICState gic;
>      >       MemoryRegion sram_a1;
>      >       MemoryRegion sram_a2;
>      > diff --git a/include/hw/misc/allwinner-h3-sid.h
>     b/include/hw/misc/allwinner-h3-sid.h
>      > new file mode 100644
>      > index 0000000000..79c9a24459
>      > --- /dev/null
>      > +++ b/include/hw/misc/allwinner-h3-sid.h
>      > @@ -0,0 +1,40 @@
>      > +/*
>      > + * Allwinner H3 Security ID emulation
>      > + *
>      > + * Copyright (C) 2019 Niek Linnenbank <nieklinnenbank@gmail.com
>     <mailto:nieklinnenbank@gmail.com>>
>      > + *
>      > + * This program is free software: you can redistribute it and/or
>     modify
>      > + * it under the terms of the GNU General Public License as
>     published by
>      > + * the Free Software Foundation, either version 2 of the License, or
>      > + * (at your option) any later version.
>      > + *
>      > + * This program is distributed in the hope that it will be useful,
>      > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>      > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>      > + * GNU General Public License for more details.
>      > + *
>      > + * 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_MISC_ALLWINNER_H3_SID_H
>      > +#define HW_MISC_ALLWINNER_H3_SID_H
>      > +
>      > +#include "hw/sysbus.h"
>      > +#include "qemu/uuid.h"
>      > +
>      > +#define TYPE_AW_H3_SID    "allwinner-h3-sid"
>      > +#define AW_H3_SID(obj)    OBJECT_CHECK(AwH3SidState, (obj),
>     TYPE_AW_H3_SID)
>      > +
>      > +typedef struct AwH3SidState {
>      > +    /*< private >*/
>      > +    SysBusDevice parent_obj;
>      > +    /*< public >*/
>      > +
>      > +    MemoryRegion iomem;
>      > +    uint32_t control;
>      > +    uint32_t rdkey;
>      > +    QemuUUID identifier;
>      > +} AwH3SidState;
>      > +
>      > +#endif
>      > diff --git a/hw/arm/allwinner-h3.c b/hw/arm/allwinner-h3.c
>      > index 1a9748ab2e..ba34f905cd 100644
>      > --- a/hw/arm/allwinner-h3.c
>      > +++ b/hw/arm/allwinner-h3.c
>      > @@ -196,6 +196,9 @@ static void aw_h3_init(Object *obj)
>      >
>      >       sysbus_init_child_obj(obj, "cpucfg", &s->cpucfg,
>     sizeof(s->cpucfg),
>      >                             TYPE_AW_H3_CPUCFG);
>      > +
>      > +    sysbus_init_child_obj(obj, "sid", &s->sid, sizeof(s->sid),
>      > +                          TYPE_AW_H3_SID);
> 
>     Here add a property alias:
> 
>              object_property_add_alias(obj, "identifier", OBJECT(&s->sid),
>                                        "identifier", &error_abort);
> 
>      >   }
>      >
>      >   static void aw_h3_realize(DeviceState *dev, Error **errp)
>      > @@ -332,6 +335,10 @@ static void aw_h3_realize(DeviceState *dev,
>     Error **errp)
>      >       qdev_init_nofail(DEVICE(&s->cpucfg));
>      >       sysbus_mmio_map(SYS_BUS_DEVICE(&s->cpucfg), 0,
>     s->memmap[AW_H3_CPUCFG]);
>      >
>      > +    /* Security Identifier */
>      > +    qdev_init_nofail(DEVICE(&s->sid));
>      > +    sysbus_mmio_map(SYS_BUS_DEVICE(&s->sid), 0,
>     s->memmap[AW_H3_SID]);
>      > +
>      >       /* Universal Serial Bus */
>      >       sysbus_create_simple(TYPE_AW_H3_EHCI, s->memmap[AW_H3_EHCI0],
>      >                            qdev_get_gpio_in(DEVICE(&s->gic),
>      > diff --git a/hw/arm/orangepi.c b/hw/arm/orangepi.c
>      > index 62cefc8c06..b01c4b4f01 100644
>      > --- a/hw/arm/orangepi.c
>      > +++ b/hw/arm/orangepi.c
>      > @@ -62,6 +62,10 @@ static void orangepi_init(MachineState *machine)
>      >           exit(1);
>      >       }
>      >
>      > +    /* Setup SID properties */
>      > +    qdev_prop_set_string(DEVICE(&s->h3->sid), "identifier",
>      > +                         "8100c002-0001-0002-0003-000044556677");
> 
>     And here use the alias:
> 
>              qdev_prop_set_string(DEVICE(&s->h3), "identifier",
>                                   "8100c002-0001-0002-0003-000044556677");
> 
> 
> Ah OK, I see what you mean. The boards should be using the SoC object 
> only and
> not directly any of its sub devices, correct?
> 
> 
>     What means this value? Don't you want to be able to set it from command
>     line?
> 
> The first word 0x02c00081 is the identifying word for the H3 SoC in the 
> SID data.
> After that come the per-device unique specific bytes. This is documented 
> at the end of this page in 'Currently known SID's' on the 
> linux-sunxi.org <http://linux-sunxi.org> Wiki:
> https://linux-sunxi.org/SID_Register_Guide
> 
> The remaining parts of this value I simply made up without any real meaning.
> And yes, it would in fact make sense to have the user be able to 
> override it from the command line.
> It is used by U-boot as an input for generating the MAC address. Linux 
> also reads it, but I did not investigate
> how it us used there. I think I did make a TODO of using a cmdline 
> argument, but later forgot to actually implement it.
> 
> Do you have a suggestion how to best provide the command line argument? 
> I do see '-device driver[,prop=value]'
> is there in the --help for qemu-system-arm, but it looks like that 
> should be used by the user for adding PCI / USB devices?

Look for '-global' in the manpage:


   -global driver.prop=value
   -global driver=driver,property=property,value=value

     Set default value of driver's property prop to value.

     In particular, you can use this to set driver properties
     for devices which are created automatically by the machine
     model. To create a device which is not created automatically
     and set properties on it, use -device.

     -global driver.prop=value is shorthand for
     -global driver=driver,property=prop,value=value.

So this should work for your device:

     -global 
allwinner-h3-sid.identifier=8100c002-0001-0002-0003-000044556677

> 
> 
>      >       /* Mark H3 object realized */
>      >       object_property_set_bool(OBJECT(s->h3), true, "realized",
>     &error_abort);
>      >       if (error_abort != NULL) {
>      > diff --git a/hw/misc/allwinner-h3-sid.c b/hw/misc/allwinner-h3-sid.c
>      > new file mode 100644
>      > index 0000000000..c472f2bcc6
>      > --- /dev/null
>      > +++ b/hw/misc/allwinner-h3-sid.c
>      > @@ -0,0 +1,179 @@
>      > +/*
>      > + * Allwinner H3 Security ID emulation
>      > + *
>      > + * Copyright (C) 2019 Niek Linnenbank <nieklinnenbank@gmail.com
>     <mailto:nieklinnenbank@gmail.com>>
>      > + *
>      > + * This program is free software: you can redistribute it and/or
>     modify
>      > + * it under the terms of the GNU General Public License as
>     published by
>      > + * the Free Software Foundation, either version 2 of the License, or
>      > + * (at your option) any later version.
>      > + *
>      > + * This program is distributed in the hope that it will be useful,
>      > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>      > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>      > + * GNU General Public License for more details.
>      > + *
>      > + * 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/units.h"
>      > +#include "hw/sysbus.h"
>      > +#include "migration/vmstate.h"
>      > +#include "qemu/log.h"
>      > +#include "qemu/module.h"
>      > +#include "qemu/guest-random.h"
>      > +#include "qapi/error.h"
>      > +#include "hw/qdev-properties.h"
>      > +#include "hw/misc/allwinner-h3-sid.h"
>      > +#include "trace.h"
>      > +
>      > +/* SID register offsets */
>      > +enum {
>      > +    REG_PRCTL = 0x40,   /* Control */
>      > +    REG_RDKEY = 0x60,   /* Read Key */
>      > +};
>      > +
>      > +/* SID register flags */
>      > +enum {
>      > +    REG_PRCTL_WRITE   = 0x0002, /* Unknown write flag */
>      > +    REG_PRCTL_OP_LOCK = 0xAC00, /* Lock operation */
>      > +};
>      > +
>      > +static uint64_t allwinner_h3_sid_read(void *opaque, hwaddr offset,
>      > +                                      unsigned size)
>      > +{
>      > +    const AwH3SidState *s = (AwH3SidState *)opaque;
>      > +    uint64_t val = 0;
>      > +
>      > +    switch (offset) {
>      > +    case REG_PRCTL:    /* Control */
>      > +        val = s->control;
>      > +        break;
>      > +    case REG_RDKEY:    /* Read Key */
>      > +        val = s->rdkey;
>      > +        break;
>      > +    default:
>      > +        qemu_log_mask(LOG_GUEST_ERROR, "%s: bad read offset
>     0x%04x\n",
>      > +                      __func__, (uint32_t)offset);
>      > +        return 0;
>      > +    }
>      > +
>      > +    trace_allwinner_h3_sid_read(offset, val, size);
>      > +
>      > +    return val;
>      > +}
>      > +
>      > +static void allwinner_h3_sid_write(void *opaque, hwaddr offset,
>      > +                                   uint64_t val, unsigned size)
>      > +{
>      > +    AwH3SidState *s = (AwH3SidState *)opaque;
>      > +
>      > +    trace_allwinner_h3_sid_write(offset, val, size);
>      > +
>      > +    switch (offset) {
>      > +    case REG_PRCTL:    /* Control */
>      > +        s->control = val;
>      > +
>      > +        if ((s->control & REG_PRCTL_OP_LOCK) &&
>      > +            (s->control & REG_PRCTL_WRITE)) {
>      > +            uint32_t id = s->control >> 16;
>      > +
>      > +            if (id < sizeof(QemuUUID)) {
>      > +                s->rdkey = (s->identifier.data[id]) |
>      > +                           (s->identifier.data[id + 1] << 8) |
>      > +                           (s->identifier.data[id + 2] << 16) |
>      > +                           (s->identifier.data[id + 3] << 24);
> 
>     This is:
> 
>                          s->rdkey = ldl_le_p(&s->identifier.data[id]);
> 
>      > +            }
>      > +        }
>      > +        s->control &= ~REG_PRCTL_WRITE;
>      > +        break;
>      > +    case REG_RDKEY:    /* Read Key */
> 
>     Read in a write()?
> 
>     Maybe we can simply /* fall through */ LOG_GUEST_ERROR?
> 
> 
> When writing this module, I looked at how U-Boot is using the SID 
> registers and simply
> named the registers after the names used by U-Boot. You can find this 
> part in arch/arm/mach-sunxi/cpu_info.c:111,
> functions sun8i_efuse_read() and sunxi_get_sid(). U-Boot defines 
> SIDC_RDKEY, so I named the register also rdkey.
> I used the U-Boot source because the Allwinner H3 datasheet does not 
> document the registers. Later I
> found the SID page on the linux-sunxi wiki that I mentioned earlier, and 
> they also describe the same register names:
> 
> https://linux-sunxi.org/SID_Register_Guide

Hmm this page describe this register as RW, odd. I think this is wrong 
because we deal with a fuse, and we program it via the REG_PRKEY 
register. Does Linux/U-Boot do write access to this register?
We can start logging LOG_GUEST_ERROR, and correct it if we notice this 
register is really writable (which I doubt).

> 
> I suspect the information on this page is written based on the source 
> code from the original SDK (which I did not study btw)
[...]



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

* Re: [PATCH v2 00/10] Add Allwinner H3 SoC and Orange Pi PC Machine
  2019-12-30 11:28 ` [PATCH v2 00/10] Add Allwinner H3 SoC and Orange Pi PC Machine Niek Linnenbank
@ 2019-12-30 14:56   ` Philippe Mathieu-Daudé
  2019-12-30 20:10     ` Niek Linnenbank
  0 siblings, 1 reply; 30+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-12-30 14:56 UTC (permalink / raw)
  To: Niek Linnenbank, QEMU Developers; +Cc: Peter Maydell, qemu-arm

On 12/30/19 12:28 PM, Niek Linnenbank wrote:
> Hi,
> 
> Here a short status report of this patch series.

Good idea!

> 
> For V3 update I already prepared the following:
>   - reworked all review comments from Philippe, except:
>     - patch#8: question for the SID, whether command-line override is 
> required (and how is the best way for machine-specific cli arg?) [1]

Answered recently.

> - added BootROM support, allows booting with only specifying -sd <IMG>
> - added SDRAM controller driver, for U-Boot SPL
> - added Allwinner generic RTC driver (for both Cubieboard and OrangePi 
> PC, supports sun4i, sun6i, sun7i)
> - small fixes for EMAC
> 
> My current TODO:
>   - integrate Philips acceptance tests in the series

You can queue them in your series, adding your Signed-off-by tag after 
mine. See:
https://www.kernel.org/doc/html/latest/process/submitting-patches.html#sign-your-work-the-developer-s-certificate-of-origin

   The sign-off is a simple line at the end of the explanation for the 
patch, which certifies that you wrote it or otherwise have the right to 
pass it on as an open-source patch.

See point (c).

>   - integrate Philips work for generalizing the Allwinner timer, and 
> finish it

We can also do that later, and get your work merged first.

>   - test and fix BSD targets (NetBSD, FreeBSD) [2, 3]
>   - further generalize the series to cover very similar SoCs: H2+, H5
> 
> Does anyone have more comments/requests for the V3 update?
> 
> [1] https://lists.gnu.org/archive/html/qemu-devel/2019-12/msg04049.html
> [2] https://wiki.netbsd.org/ports/evbarm/allwinner/
> [3] 
> https://wiki.freebsd.org/action/show/arm/Allwinner?action=show&redirect=FreeBSD%2Farm%2FAllwinner



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

* Re: [PATCH v2 00/10] Add Allwinner H3 SoC and Orange Pi PC Machine
  2019-12-30 14:56   ` Philippe Mathieu-Daudé
@ 2019-12-30 20:10     ` Niek Linnenbank
  2020-01-02 19:52       ` Niek Linnenbank
  0 siblings, 1 reply; 30+ messages in thread
From: Niek Linnenbank @ 2019-12-30 20:10 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé; +Cc: Peter Maydell, qemu-arm, QEMU Developers

[-- Attachment #1: Type: text/plain, Size: 2097 bytes --]

On Mon, Dec 30, 2019 at 3:56 PM Philippe Mathieu-Daudé <philmd@redhat.com>
wrote:

> On 12/30/19 12:28 PM, Niek Linnenbank wrote:
> > Hi,
> >
> > Here a short status report of this patch series.
>
> Good idea!
>
> >
> > For V3 update I already prepared the following:
> >   - reworked all review comments from Philippe, except:
> >     - patch#8: question for the SID, whether command-line override is
> > required (and how is the best way for machine-specific cli arg?) [1]
>
> Answered recently.
>
Thanks!

>
> > - added BootROM support, allows booting with only specifying -sd <IMG>
> > - added SDRAM controller driver, for U-Boot SPL
> > - added Allwinner generic RTC driver (for both Cubieboard and OrangePi
> > PC, supports sun4i, sun6i, sun7i)
> > - small fixes for EMAC
> >
> > My current TODO:
> >   - integrate Philips acceptance tests in the series
>
> You can queue them in your series, adding your Signed-off-by tag after
> mine. See:
>
> https://www.kernel.org/doc/html/latest/process/submitting-patches.html#sign-your-work-the-developer-s-certificate-of-origin
>
>    The sign-off is a simple line at the end of the explanation for the
> patch, which certifies that you wrote it or otherwise have the right to
> pass it on as an open-source patch.
>
> See point (c).
>
> Ah that certainly helps. I'll read that page.


> >   - integrate Philips work for generalizing the Allwinner timer, and
> > finish it
>
> We can also do that later, and get your work merged first.
>

Ok that sounds very good! Agreed, lets do the timer work later.


>
> >   - test and fix BSD targets (NetBSD, FreeBSD) [2, 3]
> >   - further generalize the series to cover very similar SoCs: H2+, H5
> >
> > Does anyone have more comments/requests for the V3 update?
> >
> > [1] https://lists.gnu.org/archive/html/qemu-devel/2019-12/msg04049.html
> > [2] https://wiki.netbsd.org/ports/evbarm/allwinner/
> > [3]
> >
> https://wiki.freebsd.org/action/show/arm/Allwinner?action=show&redirect=FreeBSD%2Farm%2FAllwinner
>
>

-- 
Niek Linnenbank

[-- Attachment #2: Type: text/html, Size: 3716 bytes --]

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

* Re: [PATCH v2 00/10] Add Allwinner H3 SoC and Orange Pi PC Machine
  2019-12-30 20:10     ` Niek Linnenbank
@ 2020-01-02 19:52       ` Niek Linnenbank
  2020-01-02 21:11         ` Philippe Mathieu-Daudé
  0 siblings, 1 reply; 30+ messages in thread
From: Niek Linnenbank @ 2020-01-02 19:52 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé; +Cc: Peter Maydell, qemu-arm, QEMU Developers

[-- Attachment #1: Type: text/plain, Size: 3428 bytes --]

Hi Philippe,

I'm almost ready to send out v3 here.

Now for documentation I'm not sure yet what to do:

1) Where should I place board documentation?
    For example, the information that I wrote on the cover letter with
instructions on how to get the board up and running,
    some description of the design, where to find more inforformation,
datasheet sources, etc. I don't yet see any documentation
   for the other boards in the source. In my opinion, it is important to
keep that information somewhere, such that also in the future
   the boards can still be properly maintained. Can I / shall I place a new
file like ./docs/hw/arm/orangepi.txt for that?

 2) Is is allowed / encouraged to provide Doxygen-style comments in the
header files in include/hw/*?
   I see that some of the API's have that, but the boards and devices
mostly are free of Doxygen-style comments.
   It takes some work, but I think it can really help to give more insight
/ background info on how things are working
   for the devices and boards. But if it's not preferred for QEMU, I'm fine
with that as well.

Regards,
Niek

On Mon, Dec 30, 2019 at 9:10 PM Niek Linnenbank <nieklinnenbank@gmail.com>
wrote:

>
>
> On Mon, Dec 30, 2019 at 3:56 PM Philippe Mathieu-Daudé <philmd@redhat.com>
> wrote:
>
>> On 12/30/19 12:28 PM, Niek Linnenbank wrote:
>> > Hi,
>> >
>> > Here a short status report of this patch series.
>>
>> Good idea!
>>
>> >
>> > For V3 update I already prepared the following:
>> >   - reworked all review comments from Philippe, except:
>> >     - patch#8: question for the SID, whether command-line override is
>> > required (and how is the best way for machine-specific cli arg?) [1]
>>
>> Answered recently.
>>
> Thanks!
>
>>
>> > - added BootROM support, allows booting with only specifying -sd <IMG>
>> > - added SDRAM controller driver, for U-Boot SPL
>> > - added Allwinner generic RTC driver (for both Cubieboard and OrangePi
>> > PC, supports sun4i, sun6i, sun7i)
>> > - small fixes for EMAC
>> >
>> > My current TODO:
>> >   - integrate Philips acceptance tests in the series
>>
>> You can queue them in your series, adding your Signed-off-by tag after
>> mine. See:
>>
>> https://www.kernel.org/doc/html/latest/process/submitting-patches.html#sign-your-work-the-developer-s-certificate-of-origin
>>
>>    The sign-off is a simple line at the end of the explanation for the
>> patch, which certifies that you wrote it or otherwise have the right to
>> pass it on as an open-source patch.
>>
>> See point (c).
>>
>> Ah that certainly helps. I'll read that page.
>
>
>> >   - integrate Philips work for generalizing the Allwinner timer, and
>> > finish it
>>
>> We can also do that later, and get your work merged first.
>>
>
> Ok that sounds very good! Agreed, lets do the timer work later.
>
>
>>
>> >   - test and fix BSD targets (NetBSD, FreeBSD) [2, 3]
>> >   - further generalize the series to cover very similar SoCs: H2+, H5
>> >
>> > Does anyone have more comments/requests for the V3 update?
>> >
>> > [1] https://lists.gnu.org/archive/html/qemu-devel/2019-12/msg04049.html
>> > [2] https://wiki.netbsd.org/ports/evbarm/allwinner/
>> > [3]
>> >
>> https://wiki.freebsd.org/action/show/arm/Allwinner?action=show&redirect=FreeBSD%2Farm%2FAllwinner
>>
>>
>
> --
> Niek Linnenbank
>
>

-- 
Niek Linnenbank

[-- Attachment #2: Type: text/html, Size: 5570 bytes --]

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

* Re: [PATCH v2 00/10] Add Allwinner H3 SoC and Orange Pi PC Machine
  2020-01-02 19:52       ` Niek Linnenbank
@ 2020-01-02 21:11         ` Philippe Mathieu-Daudé
  2020-01-02 22:06           ` Niek Linnenbank
  0 siblings, 1 reply; 30+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-01-02 21:11 UTC (permalink / raw)
  To: Niek Linnenbank; +Cc: Peter Maydell, qemu-arm, QEMU Developers

Hi Niek,

On 1/2/20 8:52 PM, Niek Linnenbank wrote:
> Hi Philippe,
> 
> I'm almost ready to send out v3 here.
> 
> Now for documentation I'm not sure yet what to do:
> 
> 1) Where should I place board documentation?
>      For example, the information that I wrote on the cover letter with 
> instructions on how to get the board up and running,
>      some description of the design, where to find more inforformation, 
> datasheet sources, etc. I don't yet see any documentation

We usually refer the datasheet in the implementation header, see:

$ git grep -F .pdf hw/ | wc -l
62

You can cite the datasheet globally in hw/arm/allwinner-h3.c, and then 
the particular chapters or source files in the other hw/*/allwinner-* files.

>     for the other boards in the source. In my opinion, it is important 
> to keep that information somewhere, such that also in the future
>     the boards can still be properly maintained. Can I / shall I place a 
> new file like ./docs/hw/arm/orangepi.txt for that?

See docs/microvm.rst which is a recent example of machine documentation,
the obvious name is docs/orangepi.rst.

Maybe refer to this file in hw/arm/orangepi.c header for completeness.

>   2) Is is allowed / encouraged to provide Doxygen-style comments in the 
> header files in include/hw/*?
>     I see that some of the API's have that, but the boards and devices 
> mostly are free of Doxygen-style comments.
>     It takes some work, but I think it can really help to give more 
> insight / background info on how things are working
>     for the devices and boards. But if it's not preferred for QEMU, I'm 
> fine with that as well.

Documentation is certainly welcome!

There are 2 different schools over the codebase, one that document the 
declarations, and another that documents the implementation/definition.

I personally prefer to document the headers, which is where I look when 
I want to consume an API.
The implementation school says this can lead to documentation getting 
outdated.

So if you are willing to document, I'd suggest to document your 
include/hw/ files.

Happy new year!

Phil.

> On Mon, Dec 30, 2019 at 9:10 PM Niek Linnenbank 
> <nieklinnenbank@gmail.com <mailto:nieklinnenbank@gmail.com>> wrote:
> 
> 
> 
>     On Mon, Dec 30, 2019 at 3:56 PM Philippe Mathieu-Daudé
>     <philmd@redhat.com <mailto:philmd@redhat.com>> wrote:
> 
>         On 12/30/19 12:28 PM, Niek Linnenbank wrote:
>          > Hi,
>          >
>          > Here a short status report of this patch series.
> 
>         Good idea!
> 
>          >
>          > For V3 update I already prepared the following:
>          >   - reworked all review comments from Philippe, except:
>          >     - patch#8: question for the SID, whether command-line
>         override is
>          > required (and how is the best way for machine-specific cli
>         arg?) [1]
> 
>         Answered recently.
> 
>     Thanks!
> 
> 
>          > - added BootROM support, allows booting with only specifying
>         -sd <IMG>
>          > - added SDRAM controller driver, for U-Boot SPL
>          > - added Allwinner generic RTC driver (for both Cubieboard and
>         OrangePi
>          > PC, supports sun4i, sun6i, sun7i)
>          > - small fixes for EMAC
>          >
>          > My current TODO:
>          >   - integrate Philips acceptance tests in the series
> 
>         You can queue them in your series, adding your Signed-off-by tag
>         after
>         mine. See:
>         https://www.kernel.org/doc/html/latest/process/submitting-patches.html#sign-your-work-the-developer-s-certificate-of-origin
> 
>             The sign-off is a simple line at the end of the explanation
>         for the
>         patch, which certifies that you wrote it or otherwise have the
>         right to
>         pass it on as an open-source patch.
> 
>         See point (c).
> 
>     Ah that certainly helps. I'll read that page.
> 
>          >   - integrate Philips work for generalizing the Allwinner
>         timer, and
>          > finish it
> 
>         We can also do that later, and get your work merged first.
> 
> 
>     Ok that sounds very good! Agreed, lets do the timer work later.
> 
> 
>          >   - test and fix BSD targets (NetBSD, FreeBSD) [2, 3]
>          >   - further generalize the series to cover very similar SoCs:
>         H2+, H5
>          >
>          > Does anyone have more comments/requests for the V3 update?
>          >
>          > [1]
>         https://lists.gnu.org/archive/html/qemu-devel/2019-12/msg04049.html
>          > [2] https://wiki.netbsd.org/ports/evbarm/allwinner/
>          > [3]
>          >
>         https://wiki.freebsd.org/action/show/arm/Allwinner?action=show&redirect=FreeBSD%2Farm%2FAllwinner
> 
> 
> 
>     -- 
>     Niek Linnenbank
> 
> 
> 
> -- 
> Niek Linnenbank
> 



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

* Re: [PATCH v2 00/10] Add Allwinner H3 SoC and Orange Pi PC Machine
  2020-01-02 21:11         ` Philippe Mathieu-Daudé
@ 2020-01-02 22:06           ` Niek Linnenbank
  0 siblings, 0 replies; 30+ messages in thread
From: Niek Linnenbank @ 2020-01-02 22:06 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé; +Cc: Peter Maydell, qemu-arm, QEMU Developers

[-- Attachment #1: Type: text/plain, Size: 5668 bytes --]

Hey Philippe,

On Thu, Jan 2, 2020 at 10:11 PM Philippe Mathieu-Daudé <philmd@redhat.com>
wrote:

> Hi Niek,
>
> On 1/2/20 8:52 PM, Niek Linnenbank wrote:
> > Hi Philippe,
> >
> > I'm almost ready to send out v3 here.
> >
> > Now for documentation I'm not sure yet what to do:
> >
> > 1) Where should I place board documentation?
> >      For example, the information that I wrote on the cover letter with
> > instructions on how to get the board up and running,
> >      some description of the design, where to find more inforformation,
> > datasheet sources, etc. I don't yet see any documentation
>
> We usually refer the datasheet in the implementation header, see:
>
> $ git grep -F .pdf hw/ | wc -l
> 62
>
> You can cite the datasheet globally in hw/arm/allwinner-h3.c, and then
> the particular chapters or source files in the other hw/*/allwinner-*
> files.
>
> >     for the other boards in the source. In my opinion, it is important
> > to keep that information somewhere, such that also in the future
> >     the boards can still be properly maintained. Can I / shall I place a
> > new file like ./docs/hw/arm/orangepi.txt for that?
>
> See docs/microvm.rst which is a recent example of machine documentation,
> the obvious name is docs/orangepi.rst.
>
> Ah great, that is very helpful! I will use the microvm.rst as example and
add a new file docs/orangepi.rst to document the board.


> Maybe refer to this file in hw/arm/orangepi.c header for completeness.
>
> >   2) Is is allowed / encouraged to provide Doxygen-style comments in the
> > header files in include/hw/*?
> >     I see that some of the API's have that, but the boards and devices
> > mostly are free of Doxygen-style comments.
> >     It takes some work, but I think it can really help to give more
> > insight / background info on how things are working
> >     for the devices and boards. But if it's not preferred for QEMU, I'm
> > fine with that as well.
>
> Documentation is certainly welcome!
>
> There are 2 different schools over the codebase, one that document the
> declarations, and another that documents the implementation/definition.
>
> I personally prefer to document the headers, which is where I look when
> I want to consume an API.
> The implementation school says this can lead to documentation getting
> outdated.
>
> So if you are willing to document, I'd suggest to document your
> include/hw/ files.
>

OK, thanks for clarifying! Yes, I also prefer to have it in the header
files, it
makes the most sense indeed.


>
> Happy new year!
>

And happy new year to you as well Philippe!

Regards,
Niek

>
> Phil.
>
> > On Mon, Dec 30, 2019 at 9:10 PM Niek Linnenbank
> > <nieklinnenbank@gmail.com <mailto:nieklinnenbank@gmail.com>> wrote:
> >
> >
> >
> >     On Mon, Dec 30, 2019 at 3:56 PM Philippe Mathieu-Daudé
> >     <philmd@redhat.com <mailto:philmd@redhat.com>> wrote:
> >
> >         On 12/30/19 12:28 PM, Niek Linnenbank wrote:
> >          > Hi,
> >          >
> >          > Here a short status report of this patch series.
> >
> >         Good idea!
> >
> >          >
> >          > For V3 update I already prepared the following:
> >          >   - reworked all review comments from Philippe, except:
> >          >     - patch#8: question for the SID, whether command-line
> >         override is
> >          > required (and how is the best way for machine-specific cli
> >         arg?) [1]
> >
> >         Answered recently.
> >
> >     Thanks!
> >
> >
> >          > - added BootROM support, allows booting with only specifying
> >         -sd <IMG>
> >          > - added SDRAM controller driver, for U-Boot SPL
> >          > - added Allwinner generic RTC driver (for both Cubieboard and
> >         OrangePi
> >          > PC, supports sun4i, sun6i, sun7i)
> >          > - small fixes for EMAC
> >          >
> >          > My current TODO:
> >          >   - integrate Philips acceptance tests in the series
> >
> >         You can queue them in your series, adding your Signed-off-by tag
> >         after
> >         mine. See:
> >
> https://www.kernel.org/doc/html/latest/process/submitting-patches.html#sign-your-work-the-developer-s-certificate-of-origin
> >
> >             The sign-off is a simple line at the end of the explanation
> >         for the
> >         patch, which certifies that you wrote it or otherwise have the
> >         right to
> >         pass it on as an open-source patch.
> >
> >         See point (c).
> >
> >     Ah that certainly helps. I'll read that page.
> >
> >          >   - integrate Philips work for generalizing the Allwinner
> >         timer, and
> >          > finish it
> >
> >         We can also do that later, and get your work merged first.
> >
> >
> >     Ok that sounds very good! Agreed, lets do the timer work later.
> >
> >
> >          >   - test and fix BSD targets (NetBSD, FreeBSD) [2, 3]
> >          >   - further generalize the series to cover very similar SoCs:
> >         H2+, H5
> >          >
> >          > Does anyone have more comments/requests for the V3 update?
> >          >
> >          > [1]
> >
> https://lists.gnu.org/archive/html/qemu-devel/2019-12/msg04049.html
> >          > [2] https://wiki.netbsd.org/ports/evbarm/allwinner/
> >          > [3]
> >          >
> >
> https://wiki.freebsd.org/action/show/arm/Allwinner?action=show&redirect=FreeBSD%2Farm%2FAllwinner
> >
> >
> >
> >     --
> >     Niek Linnenbank
> >
> >
> >
> > --
> > Niek Linnenbank
> >
>
>

-- 
Niek Linnenbank

[-- Attachment #2: Type: text/html, Size: 8493 bytes --]

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

* Re: [PATCH v2 08/10] arm: allwinner-h3: add Security Identifier device
  2019-12-30 14:49       ` Philippe Mathieu-Daudé
@ 2020-01-07 21:53         ` Niek Linnenbank
  0 siblings, 0 replies; 30+ messages in thread
From: Niek Linnenbank @ 2020-01-07 21:53 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé; +Cc: Peter Maydell, qemu-arm, QEMU Developers

[-- Attachment #1: Type: text/plain, Size: 15189 bytes --]

On Mon, Dec 30, 2019 at 3:49 PM Philippe Mathieu-Daudé <philmd@redhat.com>
wrote:

> On 12/18/19 9:49 PM, Niek Linnenbank wrote:
> > Hi Philippe,
> >
> > On Tue, Dec 17, 2019 at 8:45 AM Philippe Mathieu-Daudé
> > <philmd@redhat.com <mailto:philmd@redhat.com>> wrote:
> >
> >     Hi Niek,
> >
> >     On 12/17/19 12:35 AM, Niek Linnenbank wrote:
> >      > The Security Identifier device in Allwinner H3 System on Chip
> >      > gives applications a per-board unique identifier. This commit
> >      > adds support for the Allwinner H3 Security Identifier using
> >      > a 128-bit UUID value as input.
> >      >
> >      > Signed-off-by: Niek Linnenbank <nieklinnenbank@gmail.com
> >     <mailto:nieklinnenbank@gmail.com>>
> >      > ---
> >      >   include/hw/arm/allwinner-h3.h      |   2 +
> >      >   include/hw/misc/allwinner-h3-sid.h |  40 +++++++
> >      >   hw/arm/allwinner-h3.c              |   7 ++
> >      >   hw/arm/orangepi.c                  |   4 +
> >      >   hw/misc/allwinner-h3-sid.c         | 179
> >     +++++++++++++++++++++++++++++
> >      >   hw/misc/Makefile.objs              |   1 +
> >      >   hw/misc/trace-events               |   4 +
> >      >   7 files changed, 237 insertions(+)
> >      >   create mode 100644 include/hw/misc/allwinner-h3-sid.h
> >      >   create mode 100644 hw/misc/allwinner-h3-sid.c
> >      >
> >      > diff --git a/include/hw/arm/allwinner-h3.h
> >     b/include/hw/arm/allwinner-h3.h
> >      > index 8128ae6131..c98c1972a6 100644
> >      > --- a/include/hw/arm/allwinner-h3.h
> >      > +++ b/include/hw/arm/allwinner-h3.h
> >      > @@ -29,6 +29,7 @@
> >      >   #include "hw/misc/allwinner-h3-clk.h"
> >      >   #include "hw/misc/allwinner-h3-cpucfg.h"
> >      >   #include "hw/misc/allwinner-h3-syscon.h"
> >      > +#include "hw/misc/allwinner-h3-sid.h"
> >      >   #include "target/arm/cpu.h"
> >      >
> >      >   enum {
> >      > @@ -77,6 +78,7 @@ typedef struct AwH3State {
> >      >       AwH3ClockState ccu;
> >      >       AwH3CpuCfgState cpucfg;
> >      >       AwH3SysconState syscon;
> >      > +    AwH3SidState sid;
> >      >       GICState gic;
> >      >       MemoryRegion sram_a1;
> >      >       MemoryRegion sram_a2;
> >      > diff --git a/include/hw/misc/allwinner-h3-sid.h
> >     b/include/hw/misc/allwinner-h3-sid.h
> >      > new file mode 100644
> >      > index 0000000000..79c9a24459
> >      > --- /dev/null
> >      > +++ b/include/hw/misc/allwinner-h3-sid.h
> >      > @@ -0,0 +1,40 @@
> >      > +/*
> >      > + * Allwinner H3 Security ID emulation
> >      > + *
> >      > + * Copyright (C) 2019 Niek Linnenbank <nieklinnenbank@gmail.com
> >     <mailto:nieklinnenbank@gmail.com>>
> >      > + *
> >      > + * This program is free software: you can redistribute it and/or
> >     modify
> >      > + * it under the terms of the GNU General Public License as
> >     published by
> >      > + * the Free Software Foundation, either version 2 of the
> License, or
> >      > + * (at your option) any later version.
> >      > + *
> >      > + * This program is distributed in the hope that it will be
> useful,
> >      > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> >      > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> >      > + * GNU General Public License for more details.
> >      > + *
> >      > + * 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_MISC_ALLWINNER_H3_SID_H
> >      > +#define HW_MISC_ALLWINNER_H3_SID_H
> >      > +
> >      > +#include "hw/sysbus.h"
> >      > +#include "qemu/uuid.h"
> >      > +
> >      > +#define TYPE_AW_H3_SID    "allwinner-h3-sid"
> >      > +#define AW_H3_SID(obj)    OBJECT_CHECK(AwH3SidState, (obj),
> >     TYPE_AW_H3_SID)
> >      > +
> >      > +typedef struct AwH3SidState {
> >      > +    /*< private >*/
> >      > +    SysBusDevice parent_obj;
> >      > +    /*< public >*/
> >      > +
> >      > +    MemoryRegion iomem;
> >      > +    uint32_t control;
> >      > +    uint32_t rdkey;
> >      > +    QemuUUID identifier;
> >      > +} AwH3SidState;
> >      > +
> >      > +#endif
> >      > diff --git a/hw/arm/allwinner-h3.c b/hw/arm/allwinner-h3.c
> >      > index 1a9748ab2e..ba34f905cd 100644
> >      > --- a/hw/arm/allwinner-h3.c
> >      > +++ b/hw/arm/allwinner-h3.c
> >      > @@ -196,6 +196,9 @@ static void aw_h3_init(Object *obj)
> >      >
> >      >       sysbus_init_child_obj(obj, "cpucfg", &s->cpucfg,
> >     sizeof(s->cpucfg),
> >      >                             TYPE_AW_H3_CPUCFG);
> >      > +
> >      > +    sysbus_init_child_obj(obj, "sid", &s->sid, sizeof(s->sid),
> >      > +                          TYPE_AW_H3_SID);
> >
> >     Here add a property alias:
> >
> >              object_property_add_alias(obj, "identifier",
> OBJECT(&s->sid),
> >                                        "identifier", &error_abort);
> >
> >      >   }
> >      >
> >      >   static void aw_h3_realize(DeviceState *dev, Error **errp)
> >      > @@ -332,6 +335,10 @@ static void aw_h3_realize(DeviceState *dev,
> >     Error **errp)
> >      >       qdev_init_nofail(DEVICE(&s->cpucfg));
> >      >       sysbus_mmio_map(SYS_BUS_DEVICE(&s->cpucfg), 0,
> >     s->memmap[AW_H3_CPUCFG]);
> >      >
> >      > +    /* Security Identifier */
> >      > +    qdev_init_nofail(DEVICE(&s->sid));
> >      > +    sysbus_mmio_map(SYS_BUS_DEVICE(&s->sid), 0,
> >     s->memmap[AW_H3_SID]);
> >      > +
> >      >       /* Universal Serial Bus */
> >      >       sysbus_create_simple(TYPE_AW_H3_EHCI,
> s->memmap[AW_H3_EHCI0],
> >      >                            qdev_get_gpio_in(DEVICE(&s->gic),
> >      > diff --git a/hw/arm/orangepi.c b/hw/arm/orangepi.c
> >      > index 62cefc8c06..b01c4b4f01 100644
> >      > --- a/hw/arm/orangepi.c
> >      > +++ b/hw/arm/orangepi.c
> >      > @@ -62,6 +62,10 @@ static void orangepi_init(MachineState
> *machine)
> >      >           exit(1);
> >      >       }
> >      >
> >      > +    /* Setup SID properties */
> >      > +    qdev_prop_set_string(DEVICE(&s->h3->sid), "identifier",
> >      > +                         "8100c002-0001-0002-0003-000044556677");
> >
> >     And here use the alias:
> >
> >              qdev_prop_set_string(DEVICE(&s->h3), "identifier",
> >
>  "8100c002-0001-0002-0003-000044556677");
> >
> >
> > Ah OK, I see what you mean. The boards should be using the SoC object
> > only and
> > not directly any of its sub devices, correct?
> >
> >
> >     What means this value? Don't you want to be able to set it from
> command
> >     line?
> >
> > The first word 0x02c00081 is the identifying word for the H3 SoC in the
> > SID data.
> > After that come the per-device unique specific bytes. This is documented
> > at the end of this page in 'Currently known SID's' on the
> > linux-sunxi.org <http://linux-sunxi.org> Wiki:
> > https://linux-sunxi.org/SID_Register_Guide
> >
> > The remaining parts of this value I simply made up without any real
> meaning.
> > And yes, it would in fact make sense to have the user be able to
> > override it from the command line.
> > It is used by U-boot as an input for generating the MAC address. Linux
> > also reads it, but I did not investigate
> > how it us used there. I think I did make a TODO of using a cmdline
> > argument, but later forgot to actually implement it.
> >
> > Do you have a suggestion how to best provide the command line argument?
> > I do see '-device driver[,prop=value]'
> > is there in the --help for qemu-system-arm, but it looks like that
> > should be used by the user for adding PCI / USB devices?
>
> Look for '-global' in the manpage:
>
>
>    -global driver.prop=value
>    -global driver=driver,property=property,value=value
>
>      Set default value of driver's property prop to value.
>
>      In particular, you can use this to set driver properties
>      for devices which are created automatically by the machine
>      model. To create a device which is not created automatically
>      and set properties on it, use -device.
>
>      -global driver.prop=value is shorthand for
>      -global driver=driver,property=prop,value=value.
>
> So this should work for your device:
>
>      -global
> allwinner-h3-sid.identifier=8100c002-0001-0002-0003-000044556677
>

Thanks, I tried this, however currently its not applied when used.
I think its because the orangepi.c file sets the property as well.

Its not a blocking problem if the user can't override the SID value, but it
would be a nice-to-have.
U-Boot uses its value for MAC generation and that can be overridden as well
by U-Boot itself.



> >
> >
> >      >       /* Mark H3 object realized */
> >      >       object_property_set_bool(OBJECT(s->h3), true, "realized",
> >     &error_abort);
> >      >       if (error_abort != NULL) {
> >      > diff --git a/hw/misc/allwinner-h3-sid.c
> b/hw/misc/allwinner-h3-sid.c
> >      > new file mode 100644
> >      > index 0000000000..c472f2bcc6
> >      > --- /dev/null
> >      > +++ b/hw/misc/allwinner-h3-sid.c
> >      > @@ -0,0 +1,179 @@
> >      > +/*
> >      > + * Allwinner H3 Security ID emulation
> >      > + *
> >      > + * Copyright (C) 2019 Niek Linnenbank <nieklinnenbank@gmail.com
> >     <mailto:nieklinnenbank@gmail.com>>
> >      > + *
> >      > + * This program is free software: you can redistribute it and/or
> >     modify
> >      > + * it under the terms of the GNU General Public License as
> >     published by
> >      > + * the Free Software Foundation, either version 2 of the
> License, or
> >      > + * (at your option) any later version.
> >      > + *
> >      > + * This program is distributed in the hope that it will be
> useful,
> >      > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> >      > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> >      > + * GNU General Public License for more details.
> >      > + *
> >      > + * 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/units.h"
> >      > +#include "hw/sysbus.h"
> >      > +#include "migration/vmstate.h"
> >      > +#include "qemu/log.h"
> >      > +#include "qemu/module.h"
> >      > +#include "qemu/guest-random.h"
> >      > +#include "qapi/error.h"
> >      > +#include "hw/qdev-properties.h"
> >      > +#include "hw/misc/allwinner-h3-sid.h"
> >      > +#include "trace.h"
> >      > +
> >      > +/* SID register offsets */
> >      > +enum {
> >      > +    REG_PRCTL = 0x40,   /* Control */
> >      > +    REG_RDKEY = 0x60,   /* Read Key */
> >      > +};
> >      > +
> >      > +/* SID register flags */
> >      > +enum {
> >      > +    REG_PRCTL_WRITE   = 0x0002, /* Unknown write flag */
> >      > +    REG_PRCTL_OP_LOCK = 0xAC00, /* Lock operation */
> >      > +};
> >      > +
> >      > +static uint64_t allwinner_h3_sid_read(void *opaque, hwaddr
> offset,
> >      > +                                      unsigned size)
> >      > +{
> >      > +    const AwH3SidState *s = (AwH3SidState *)opaque;
> >      > +    uint64_t val = 0;
> >      > +
> >      > +    switch (offset) {
> >      > +    case REG_PRCTL:    /* Control */
> >      > +        val = s->control;
> >      > +        break;
> >      > +    case REG_RDKEY:    /* Read Key */
> >      > +        val = s->rdkey;
> >      > +        break;
> >      > +    default:
> >      > +        qemu_log_mask(LOG_GUEST_ERROR, "%s: bad read offset
> >     0x%04x\n",
> >      > +                      __func__, (uint32_t)offset);
> >      > +        return 0;
> >      > +    }
> >      > +
> >      > +    trace_allwinner_h3_sid_read(offset, val, size);
> >      > +
> >      > +    return val;
> >      > +}
> >      > +
> >      > +static void allwinner_h3_sid_write(void *opaque, hwaddr offset,
> >      > +                                   uint64_t val, unsigned size)
> >      > +{
> >      > +    AwH3SidState *s = (AwH3SidState *)opaque;
> >      > +
> >      > +    trace_allwinner_h3_sid_write(offset, val, size);
> >      > +
> >      > +    switch (offset) {
> >      > +    case REG_PRCTL:    /* Control */
> >      > +        s->control = val;
> >      > +
> >      > +        if ((s->control & REG_PRCTL_OP_LOCK) &&
> >      > +            (s->control & REG_PRCTL_WRITE)) {
> >      > +            uint32_t id = s->control >> 16;
> >      > +
> >      > +            if (id < sizeof(QemuUUID)) {
> >      > +                s->rdkey = (s->identifier.data[id]) |
> >      > +                           (s->identifier.data[id + 1] << 8) |
> >      > +                           (s->identifier.data[id + 2] << 16) |
> >      > +                           (s->identifier.data[id + 3] << 24);
> >
> >     This is:
> >
> >                          s->rdkey = ldl_le_p(&s->identifier.data[id]);
> >
> >      > +            }
> >      > +        }
> >      > +        s->control &= ~REG_PRCTL_WRITE;
> >      > +        break;
> >      > +    case REG_RDKEY:    /* Read Key */
> >
> >     Read in a write()?
> >
> >     Maybe we can simply /* fall through */ LOG_GUEST_ERROR?
> >
> >
> > When writing this module, I looked at how U-Boot is using the SID
> > registers and simply
> > named the registers after the names used by U-Boot. You can find this
> > part in arch/arm/mach-sunxi/cpu_info.c:111,
> > functions sun8i_efuse_read() and sunxi_get_sid(). U-Boot defines
> > SIDC_RDKEY, so I named the register also rdkey.
> > I used the U-Boot source because the Allwinner H3 datasheet does not
> > document the registers. Later I
> > found the SID page on the linux-sunxi wiki that I mentioned earlier, and
> > they also describe the same register names:
> >
> > https://linux-sunxi.org/SID_Register_Guide
>
> Hmm this page describe this register as RW, odd. I think this is wrong
> because we deal with a fuse, and we program it via the REG_PRKEY
> register. Does Linux/U-Boot do write access to this register?
> We can start logging LOG_GUEST_ERROR, and correct it if we notice this
> register is really writable (which I doubt).
>
>
Yes it seems so. The PRCTL is the "Control" register (R/W) and the RDKEY
the "Data" register (RO).
You can see the Linux implementation in drivers/nvmem/sunxi_sid.c
For U-Boot the file is in arch/arm/mach-sunxi/cpu_info.c, functions
sunxi_get_sid and sun8i_efuse_read.

Regards,
Niek


> >
> > I suspect the information on this page is written based on the source
> > code from the original SDK (which I did not study btw)
> [...]
>
>

-- 
Niek Linnenbank

[-- Attachment #2: Type: text/html, Size: 21268 bytes --]

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

end of thread, other threads:[~2020-01-07 21:54 UTC | newest]

Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-12-16 23:35 [PATCH v2 00/10] Add Allwinner H3 SoC and Orange Pi PC Machine Niek Linnenbank
2019-12-16 23:35 ` [PATCH v2 01/10] hw: arm: add Allwinner H3 System-on-Chip Niek Linnenbank
2019-12-16 23:35 ` [PATCH v2 02/10] hw: arm: add Xunlong Orange Pi PC machine Niek Linnenbank
2019-12-17  7:31   ` Philippe Mathieu-Daudé
2019-12-18 20:14     ` Niek Linnenbank
2019-12-19 19:06       ` Philippe Mathieu-Daudé
2019-12-16 23:35 ` [PATCH v2 03/10] arm: allwinner-h3: add Clock Control Unit Niek Linnenbank
2019-12-16 23:35 ` [PATCH v2 04/10] arm: allwinner-h3: add USB host controller Niek Linnenbank
2019-12-16 23:35 ` [PATCH v2 05/10] arm: allwinner-h3: add System Control module Niek Linnenbank
2019-12-16 23:35 ` [PATCH v2 06/10] arm/arm-powerctl: rebuild hflags after setting CP15 bits in arm_set_cpu_on() Niek Linnenbank
2019-12-16 23:44   ` Niek Linnenbank
2019-12-17 16:12     ` Peter Maydell
2019-12-17 16:41       ` Richard Henderson
2019-12-17 17:39         ` Peter Maydell
2019-12-18 21:01         ` Niek Linnenbank
2019-12-18 23:25           ` Richard Henderson
2019-12-16 23:35 ` [PATCH v2 07/10] arm: allwinner-h3: add CPU Configuration module Niek Linnenbank
2019-12-16 23:35 ` [PATCH v2 08/10] arm: allwinner-h3: add Security Identifier device Niek Linnenbank
2019-12-17  7:45   ` Philippe Mathieu-Daudé
2019-12-18 20:49     ` Niek Linnenbank
2019-12-30 14:49       ` Philippe Mathieu-Daudé
2020-01-07 21:53         ` Niek Linnenbank
2019-12-16 23:35 ` [PATCH v2 09/10] arm: allwinner-h3: add SD/MMC host controller Niek Linnenbank
2019-12-16 23:35 ` [PATCH v2 10/10] arm: allwinner-h3: add EMAC ethernet device Niek Linnenbank
2019-12-30 11:28 ` [PATCH v2 00/10] Add Allwinner H3 SoC and Orange Pi PC Machine Niek Linnenbank
2019-12-30 14:56   ` Philippe Mathieu-Daudé
2019-12-30 20:10     ` Niek Linnenbank
2020-01-02 19:52       ` Niek Linnenbank
2020-01-02 21:11         ` Philippe Mathieu-Daudé
2020-01-02 22:06           ` Niek Linnenbank

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).