[PATCH 1/1] arm: qemu: support qfw

Heinrich Schuchardt xypron.glpk at gmx.de
Fri Feb 19 06:58:21 CET 2021


On 2/19/21 1:52 AM, Asherah Connor wrote:
> Adds support for QFW on Arm platforms by checking the device tree for a
> "qemu,fw-cfg-mmio"-compatible node in arch_early_init_r and initialising
> the driver if found.  Both MMIO and DMA are supported on this
> architecture.

The device shows up as:

fw-cfg at 9020000 {
     dma-coherent;
     reg = <0x00000000 0x09020000 0x00000000 0x00000018>;
     compatible = "qemu,fw-cfg-mmio";
};

drivers/misc/qfw.c should be converted to the driver model instead of
initializing the driver in arch_early_init_r() on qemu-arm and
qemu_chipset_init() on qemu-x86.

Cf. https://u-boot.readthedocs.io/en/latest/driver-model/index.html

Please, coordinate the change with Simon.

Should cmd/qfw.c be enhanced to show if the ramfb device is present?

Best regards

Heinrich

>
> Signed-off-by: Asherah Connor <ashe at kivikakk.ee>
> ---
>
>   arch/arm/Kconfig            |   1 +
>   arch/arm/Makefile           |   1 +
>   arch/arm/mach-qemu/Kconfig  |   2 +
>   arch/arm/mach-qemu/Makefile |   1 +
>   arch/arm/mach-qemu/qemu.c   | 109 ++++++++++++++++++++++++++++++++++++
>   5 files changed, 114 insertions(+)
>   create mode 100644 arch/arm/mach-qemu/Makefile
>   create mode 100644 arch/arm/mach-qemu/qemu.c
>
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index d51abbeaf0..3841ae3ba2 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -937,6 +937,7 @@ config ARCH_QEMU
>   	imply DM_RNG
>   	imply DM_RTC
>   	imply RTC_PL031
> +	imply QFW
>
>   config ARCH_RMOBILE
>   	bool "Renesas ARM SoCs"
> diff --git a/arch/arm/Makefile b/arch/arm/Makefile
> index 28b523b37c..90fc3d2d1a 100644
> --- a/arch/arm/Makefile
> +++ b/arch/arm/Makefile
> @@ -70,6 +70,7 @@ machine-$(CONFIG_ARCH_NEXELL)		+= nexell
>   machine-$(CONFIG_ARCH_OMAP2PLUS)	+= omap2
>   machine-$(CONFIG_ARCH_ORION5X)		+= orion5x
>   machine-$(CONFIG_ARCH_OWL)		+= owl
> +machine-$(CONFIG_ARCH_QEMU)		+= qemu
>   machine-$(CONFIG_ARCH_RMOBILE)		+= rmobile
>   machine-$(CONFIG_ARCH_ROCKCHIP)		+= rockchip
>   machine-$(CONFIG_ARCH_S5PC1XX)		+= s5pc1xx
> diff --git a/arch/arm/mach-qemu/Kconfig b/arch/arm/mach-qemu/Kconfig
> index 186c3582eb..50cbfc5efe 100644
> --- a/arch/arm/mach-qemu/Kconfig
> +++ b/arch/arm/mach-qemu/Kconfig
> @@ -19,11 +19,13 @@ config TARGET_QEMU_ARM_32BIT
>   	select BOARD_LATE_INIT
>   	select CPU_V7A
>   	select SYS_ARCH_TIMER
> +	select ARCH_EARLY_INIT_R if QFW
>
>   config TARGET_QEMU_ARM_64BIT
>   	bool "ARMv8, 64bit"
>   	select ARM64
>   	select BOARD_LATE_INIT
> +	select ARCH_EARLY_INIT_R if QFW
>
>   endchoice
>
> diff --git a/arch/arm/mach-qemu/Makefile b/arch/arm/mach-qemu/Makefile
> new file mode 100644
> index 0000000000..5f5915fb6e
> --- /dev/null
> +++ b/arch/arm/mach-qemu/Makefile
> @@ -0,0 +1 @@
> +obj-$(CONFIG_QFW) += qemu.o
> diff --git a/arch/arm/mach-qemu/qemu.c b/arch/arm/mach-qemu/qemu.c
> new file mode 100644
> index 0000000000..742cf81d6e
> --- /dev/null
> +++ b/arch/arm/mach-qemu/qemu.c
> @@ -0,0 +1,109 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2021, Asherah Connor <ashe at kivikakk.ee>
> + */
> +#include <dm.h>
> +#include <fdt_support.h>
> +#include <qfw.h>
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +/*
> + * on Arm, qfw registers are MMIO at offsets; see
> + * https://github.com/qemu/qemu/blob/1af56296/docs/specs/fw_cfg.txt
> + */
> +struct qemu_arm_fwcfg_mmio {
> +	/*
> +	 * Each access to the 64-bit data register can be 8/16/32/64 bits wide.
> +	 */
> +	union {
> +		u8 data8;
> +		u16 data16;
> +		u32 data32;
> +		u64 data64;
> +	};
> +	u16 selector;
> +	u8 padding[6];
> +	u64 dma;
> +};
> +
> +static volatile struct qemu_arm_fwcfg_mmio *mmio;
> +
> +static void qemu_arm_fwcfg_read_entry_pio(uint16_t entry, uint32_t size,
> +					  void *address)
> +{
> +	/*
> +	 * using FW_CFG_INVALID selector will resume a previous read at its last
> +	 * offset, otherwise read will start at 0 for new selector
> +	 *
> +	 * MMIO selector register is big-endian
> +	 */
> +	if (entry != FW_CFG_INVALID)
> +		mmio->selector = cpu_to_be16(entry);
> +
> +	/* data register is string-preserving */
> +	while (size >= 8) {
> +		*(u64 *)address = mmio->data64;
> +		address += 8;
> +		size -= 8;
> +	}
> +	while (size >= 4) {
> +		*(u32 *)address = mmio->data32;
> +		address += 4;
> +		size -= 4;
> +	}
> +	while (size >= 2) {
> +		*(u16 *)address = mmio->data16;
> +		address += 2;
> +		size -= 2;
> +	}
> +	while (size >= 1) {
> +		*(u8 *)address = mmio->data8;
> +		address += 1;
> +		size -= 1;
> +	}
> +}
> +
> +static void qemu_arm_fwcfg_read_entry_dma(struct fw_cfg_dma_access *dma)
> +{
> +	/* the DMA address register is big-endian */
> +	mmio->dma = cpu_to_be64((uintptr_t)dma);
> +
> +	while (be32_to_cpu(dma->control) & ~FW_CFG_DMA_ERROR)
> +		__asm__ __volatile__ ("yield");
> +}
> +
> +static struct fw_cfg_arch_ops fwcfg_arm_ops = {
> +	.arch_read_pio = qemu_arm_fwcfg_read_entry_pio,
> +	.arch_read_dma = qemu_arm_fwcfg_read_entry_dma
> +};
> +
> +int arch_early_init_r(void)
> +{
> +	/* Try to init QFW from device tree. */
> +	int offset;
> +	fdt32_t *reg;
> +	u64 mmio_offset, mmio_size;
> +	int addr_cells = fdt_address_cells(gd->fdt_blob, 0);
> +	int size_cells = fdt_size_cells(gd->fdt_blob, 0);
> +
> +	offset = fdt_node_offset_by_compatible(gd->fdt_blob, -1,
> +					       "qemu,fw-cfg-mmio");
> +	if (offset >= 0) {
> +		reg = (fdt32_t *)fdt_getprop(gd->fdt_blob, offset, "reg", 0);
> +		if (reg) {
> +			mmio_offset = fdt_read_number(reg, addr_cells);
> +			reg += addr_cells;
> +			mmio_size = fdt_read_number(reg, size_cells);
> +
> +			/* Sanity check: at least data+selector wide. */
> +			if (mmio_size >= 10) {
> +				mmio = (struct qemu_arm_fwcfg_mmio
> +						*)mmio_offset;
> +				qemu_fwcfg_init(&fwcfg_arm_ops);
> +			}
> +		}
> +	}
> +
> +	return 0;
> +}
>



More information about the U-Boot mailing list