From patchwork Tue Feb 23 11:43:26 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Asherah Connor X-Patchwork-Id: 1443463 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=kivikakk.ee header.i=@kivikakk.ee header.a=rsa-sha256 header.s=fm3 header.b=FSp7y8jO; dkim=pass (2048-bit key; unprotected) header.d=messagingengine.com header.i=@messagingengine.com header.a=rsa-sha256 header.s=fm2 header.b=bhnavBRz; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4DlHJx5Nwtz9sVS for ; Tue, 23 Feb 2021 22:44:33 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 2B030829F6; Tue, 23 Feb 2021 12:44:25 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=kivikakk.ee Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (2048-bit key; unprotected) header.d=kivikakk.ee header.i=@kivikakk.ee header.b="FSp7y8jO"; dkim=pass (2048-bit key; unprotected) header.d=messagingengine.com header.i=@messagingengine.com header.b="bhnavBRz"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 9E9FA82A0F; Tue, 23 Feb 2021 12:44:17 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL, SPF_HELO_PASS autolearn=ham autolearn_force=no version=3.4.2 Received: from new3-smtp.messagingengine.com (new3-smtp.messagingengine.com [66.111.4.229]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 1A373829EF for ; Tue, 23 Feb 2021 12:44:06 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=kivikakk.ee Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=ashe@kivikakk.ee Received: from compute5.internal (compute5.nyi.internal [10.202.2.45]) by mailnew.nyi.internal (Postfix) with ESMTP id 60CC5580406; Tue, 23 Feb 2021 06:44:05 -0500 (EST) Received: from mailfrontend2 ([10.202.2.163]) by compute5.internal (MEProxy); Tue, 23 Feb 2021 06:44:05 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kivikakk.ee; h= from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; s=fm3; bh=9FyIxv3hgvIB3 //rCDdhjdL8mUE3++ulPa99enp47wc=; b=FSp7y8jO7PXrJ9LP61nLN1TnH3Oz+ zSUAqJeuOFr97eKVe/eavtRdmmH9TSyVnxy/aWhJPXK7Jl3jYKjMaYmAJzbRAim6 wosIiobpy3oq6+gDxwbBzusACphhCH9ACoTiNqtv7XJ9he8Fi02vUd4lLlvmYTHI C3agw1ylFtLOE4oIStX0NSeAFAk8rBESIz0scWhLDWalb2PPtM2yNyv2/PxC7f+g opwXCiqKqY4kHIVcHcxdiS/PWvtAWV4HOnf92L7iJgRUI3Do2hvb+y0vdDSzqvUT v78zTLONOUxaWaKBBIi44XZFbPP6xhhSzj3pnlQ5bFvrfEXa30hZT4mTQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:date:from :in-reply-to:message-id:mime-version:references:subject:to :x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm2; bh=9FyIxv3hgvIB3//rCDdhjdL8mUE3++ulPa99enp47wc=; b=bhnavBRz YwZFvKbQerOJuUfIrBxkKPJJrWCso85cFePHYxjA1y8xloBdkCcKOSNjEUA5f5u7 Gf/XN2jr58QeUCcw2yAqyvwtqGPabwH5LbOo1a9tGx9+gMmaONwmhB9aDALBGSH+ A/4VrPyLDisAaW/f+rZNmW3Vgi5OaSBhcUd6pE+cxNSKkDPWo0Kha0fb7M6D43MA UHcbNo0y0uzUTm+X/lrK4agSq6RCc/WZmEebzIz0wFpqRTpNHkx8BRSxtDEvgR+1 ibsFhc9zopHMF8Rx6zPtCTCk2so7a2MJYj1V7LsAsxvt+4tIqfitY9KshmtSt/Lz AJ1FCuq6vVoH/A== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeduledrkeehgdefudcutefuodetggdotefrodftvf curfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfghnecu uegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenuc fjughrpefhvffufffkofgjfhgggfestdekredtredttdenucfhrhhomheptehshhgvrhgr hhcuvehonhhnohhruceorghshhgvsehkihhvihhkrghkkhdrvggvqeenucggtffrrghtth gvrhhnpeduffekffefveetfeefjeegudeghffgteeiteeltddtkedvgeffudeifeegkeet feenucfkphepudduledrudekrdefuddrudefheenucevlhhushhtvghrufhiiigvpedtne curfgrrhgrmhepmhgrihhlfhhrohhmpegrshhhvgeskhhivhhikhgrkhhkrdgvvg X-ME-Proxy: Received: from ravenlin.tomodachi (119-18-31-135.77121f.mel.static.aussiebb.net [119.18.31.135]) by mail.messagingengine.com (Postfix) with ESMTPA id 117FE1080067; Tue, 23 Feb 2021 06:44:00 -0500 (EST) From: Asherah Connor To: u-boot@lists.denx.de Cc: Simon Glass , Asherah Connor , Bharat Gooty , Bin Meng , Heinrich Schuchardt , Jagan Teki , Michal Simek , Pragnesh Patel , Rayagonda Kokatanur , Tero Kristo , Tom Rini , Trevor Woerner , Wolfgang Wallner Subject: [PATCH v3 1/4] arm: x86: qemu: move qfw to DM, include Arm support Date: Tue, 23 Feb 2021 22:43:26 +1100 Message-Id: <20210223114329.16729-2-ashe@kivikakk.ee> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20210223114329.16729-1-ashe@kivikakk.ee> References: <20210223114329.16729-1-ashe@kivikakk.ee> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.34 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.102.3 at phobos.denx.de X-Virus-Status: Clean Updates the QFW driver to use the driver model, and adds support for QFW on Arm platforms by configuring from the device tree and using MMIO accordingly. A sandbox driver for QFW is also included, and a simple DM unit test for it. Signed-off-by: Asherah Connor --- Changes in v3: - ARCH_QEMU now implies CMD_QFW, not QFW - rename qemu_fwcfg_read_entry_pio to ..._io arch/arm/Kconfig | 1 + arch/x86/cpu/qemu/cpu.c | 7 +- arch/x86/cpu/qemu/qemu.c | 54 ++------ arch/x86/cpu/qfw_cpu.c | 11 +- cmd/qfw.c | 44 +++--- drivers/misc/Kconfig | 1 + drivers/misc/qfw.c | 289 +++++++++++++++++++++++++++------------ include/qfw.h | 63 +++++---- 8 files changed, 292 insertions(+), 178 deletions(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index d51abbeaf0..cd01dc458a 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 CMD_QFW config ARCH_RMOBILE bool "Renesas ARM SoCs" diff --git a/arch/x86/cpu/qemu/cpu.c b/arch/x86/cpu/qemu/cpu.c index 9ce86b379c..ab1b797f9a 100644 --- a/arch/x86/cpu/qemu/cpu.c +++ b/arch/x86/cpu/qemu/cpu.c @@ -22,7 +22,12 @@ int cpu_qemu_get_desc(const struct udevice *dev, char *buf, int size) static int cpu_qemu_get_count(const struct udevice *dev) { - return qemu_fwcfg_online_cpus(); + struct udevice *qfw_dev = qemu_fwcfg_dev(); + + if (!qfw_dev) + return -ENODEV; + + return qemu_fwcfg_online_cpus(qfw_dev); } static const struct cpu_ops cpu_qemu_ops = { diff --git a/arch/x86/cpu/qemu/qemu.c b/arch/x86/cpu/qemu/qemu.c index 044a429c13..e255af9a4a 100644 --- a/arch/x86/cpu/qemu/qemu.c +++ b/arch/x86/cpu/qemu/qemu.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -19,45 +20,20 @@ static bool i440fx; #ifdef CONFIG_QFW /* on x86, the qfw registers are all IO ports */ -#define FW_CONTROL_PORT 0x510 -#define FW_DATA_PORT 0x511 -#define FW_DMA_PORT_LOW 0x514 -#define FW_DMA_PORT_HIGH 0x518 - -static void qemu_x86_fwcfg_read_entry_pio(uint16_t entry, - uint32_t size, void *address) -{ - uint32_t i = 0; - uint8_t *data = address; - - /* - * writting FW_CFG_INVALID will cause read operation to resume at - * last offset, otherwise read will start at offset 0 - * - * Note: on platform where the control register is IO port, the - * endianness is little endian. - */ - if (entry != FW_CFG_INVALID) - outw(cpu_to_le16(entry), FW_CONTROL_PORT); - - /* the endianness of data register is string-preserving */ - while (size--) - data[i++] = inb(FW_DATA_PORT); -} - -static void qemu_x86_fwcfg_read_entry_dma(struct fw_cfg_dma_access *dma) -{ - /* the DMA address register is big endian */ - outl(cpu_to_be32((uintptr_t)dma), FW_DMA_PORT_HIGH); - - while (be32_to_cpu(dma->control) & ~FW_CFG_DMA_ERROR) - __asm__ __volatile__ ("pause"); -} +static const struct qfw_plat x86_qfw_plat = { + .io = { + .control_port = 0x510, + .data_port = 0x511, + .dma_port_low = 0x514, + .dma_port_high = 0x518, + }, +}; -static struct fw_cfg_arch_ops fwcfg_x86_ops = { - .arch_read_pio = qemu_x86_fwcfg_read_entry_pio, - .arch_read_dma = qemu_x86_fwcfg_read_entry_dma +U_BOOT_DRVINFO(x86_qfw) = { + .name = "qfw", + .plat = &x86_qfw_plat, }; + #endif static void enable_pm_piix(void) @@ -132,10 +108,6 @@ static void qemu_chipset_init(void) enable_pm_ich9(); } - -#ifdef CONFIG_QFW - qemu_fwcfg_init(&fwcfg_x86_ops); -#endif } #if !CONFIG_IS_ENABLED(SPL_X86_32BIT_INIT) diff --git a/arch/x86/cpu/qfw_cpu.c b/arch/x86/cpu/qfw_cpu.c index b959eaddde..c8fb918494 100644 --- a/arch/x86/cpu/qfw_cpu.c +++ b/arch/x86/cpu/qfw_cpu.c @@ -18,7 +18,7 @@ int qemu_cpu_fixup(void) int cpu_num; int cpu_online; struct uclass *uc; - struct udevice *dev, *pdev; + struct udevice *dev, *pdev, *qfwdev; struct cpu_plat *plat; char *cpu; @@ -39,6 +39,13 @@ int qemu_cpu_fixup(void) return -ENODEV; } + /* get qfw dev */ + qfwdev = qemu_fwcfg_dev(); + if (!qfwdev) { + printf("unable to find qfw device\n"); + return -ENODEV; + } + /* calculate cpus that are already bound */ cpu_num = 0; for (uclass_find_first_device(UCLASS_CPU, &dev); @@ -48,7 +55,7 @@ int qemu_cpu_fixup(void) } /* get actual cpu number */ - cpu_online = qemu_fwcfg_online_cpus(); + cpu_online = qemu_fwcfg_online_cpus(qfwdev); if (cpu_online < 0) { printf("unable to get online cpu number: %d\n", cpu_online); return cpu_online; diff --git a/cmd/qfw.c b/cmd/qfw.c index bb571487f0..ec80a9a3b5 100644 --- a/cmd/qfw.c +++ b/cmd/qfw.c @@ -8,19 +8,22 @@ #include #include #include +#include + +static struct udevice *qfw_dev; /* * This function prepares kernel for zboot. It loads kernel data * to 'load_addr', initrd to 'initrd_addr' and kernel command * line using qemu fw_cfg interface. */ -static int qemu_fwcfg_setup_kernel(void *load_addr, void *initrd_addr) +static int qemu_fwcfg_cmd_setup_kernel(void *load_addr, void *initrd_addr) { char *data_addr; uint32_t setup_size, kernel_size, cmdline_size, initrd_size; - qemu_fwcfg_read_entry(FW_CFG_SETUP_SIZE, 4, &setup_size); - qemu_fwcfg_read_entry(FW_CFG_KERNEL_SIZE, 4, &kernel_size); + qemu_fwcfg_read_entry(qfw_dev, FW_CFG_SETUP_SIZE, 4, &setup_size); + qemu_fwcfg_read_entry(qfw_dev, FW_CFG_KERNEL_SIZE, 4, &kernel_size); if (setup_size == 0 || kernel_size == 0) { printf("warning: no kernel available\n"); @@ -28,27 +31,27 @@ static int qemu_fwcfg_setup_kernel(void *load_addr, void *initrd_addr) } data_addr = load_addr; - qemu_fwcfg_read_entry(FW_CFG_SETUP_DATA, + qemu_fwcfg_read_entry(qfw_dev, FW_CFG_SETUP_DATA, le32_to_cpu(setup_size), data_addr); data_addr += le32_to_cpu(setup_size); - qemu_fwcfg_read_entry(FW_CFG_KERNEL_DATA, + qemu_fwcfg_read_entry(qfw_dev, FW_CFG_KERNEL_DATA, le32_to_cpu(kernel_size), data_addr); data_addr += le32_to_cpu(kernel_size); data_addr = initrd_addr; - qemu_fwcfg_read_entry(FW_CFG_INITRD_SIZE, 4, &initrd_size); + qemu_fwcfg_read_entry(qfw_dev, FW_CFG_INITRD_SIZE, 4, &initrd_size); if (initrd_size == 0) { printf("warning: no initrd available\n"); } else { - qemu_fwcfg_read_entry(FW_CFG_INITRD_DATA, + qemu_fwcfg_read_entry(qfw_dev, FW_CFG_INITRD_DATA, le32_to_cpu(initrd_size), data_addr); data_addr += le32_to_cpu(initrd_size); } - qemu_fwcfg_read_entry(FW_CFG_CMDLINE_SIZE, 4, &cmdline_size); + qemu_fwcfg_read_entry(qfw_dev, FW_CFG_CMDLINE_SIZE, 4, &cmdline_size); if (cmdline_size) { - qemu_fwcfg_read_entry(FW_CFG_CMDLINE_DATA, + qemu_fwcfg_read_entry(qfw_dev, FW_CFG_CMDLINE_DATA, le32_to_cpu(cmdline_size), data_addr); /* * if kernel cmdline only contains '\0', (e.g. no -append @@ -72,19 +75,18 @@ static int qemu_fwcfg_setup_kernel(void *load_addr, void *initrd_addr) return 0; } -static int qemu_fwcfg_list_firmware(void) +static int qemu_fwcfg_cmd_list_firmware(void) { int ret; struct fw_cfg_file_iter iter; struct fw_file *file; /* make sure fw_list is loaded */ - ret = qemu_fwcfg_read_firmware_list(); + ret = qemu_fwcfg_read_firmware_list(qfw_dev); if (ret) return ret; - - for (file = qemu_fwcfg_file_iter_init(&iter); + for (file = qemu_fwcfg_file_iter_init(qfw_dev, &iter); !qemu_fwcfg_file_iter_end(&iter); file = qemu_fwcfg_file_iter_next(&iter)) { printf("%-56s\n", file->cfg.name); @@ -96,7 +98,7 @@ static int qemu_fwcfg_list_firmware(void) static int qemu_fwcfg_do_list(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { - if (qemu_fwcfg_list_firmware() < 0) + if (qemu_fwcfg_cmd_list_firmware() < 0) return CMD_RET_FAILURE; return 0; @@ -105,14 +107,7 @@ static int qemu_fwcfg_do_list(struct cmd_tbl *cmdtp, int flag, static int qemu_fwcfg_do_cpus(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { - int ret = qemu_fwcfg_online_cpus(); - if (ret < 0) { - printf("QEMU fw_cfg interface not found\n"); - return CMD_RET_FAILURE; - } - - printf("%d cpu(s) online\n", qemu_fwcfg_online_cpus()); - + printf("%d cpu(s) online\n", qemu_fwcfg_online_cpus(qfw_dev)); return 0; } @@ -153,7 +148,7 @@ static int qemu_fwcfg_do_load(struct cmd_tbl *cmdtp, int flag, return CMD_RET_FAILURE; } - return qemu_fwcfg_setup_kernel(load_addr, initrd_addr); + return qemu_fwcfg_cmd_setup_kernel(load_addr, initrd_addr); } static struct cmd_tbl fwcfg_commands[] = { @@ -168,7 +163,8 @@ static int do_qemu_fw(struct cmd_tbl *cmdtp, int flag, int argc, int ret; struct cmd_tbl *fwcfg_cmd; - if (!qemu_fwcfg_present()) { + qfw_dev = qemu_fwcfg_dev(); + if (!qfw_dev) { printf("QEMU fw_cfg interface not found\n"); return CMD_RET_USAGE; } diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 7d2a299779..0a65f29acd 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -367,6 +367,7 @@ config WINBOND_W83627 config QFW bool + depends on MISC help Hidden option to enable QEMU fw_cfg interface. This will be selected by either CONFIG_CMD_QFW or CONFIG_GENERATE_ACPI_TABLE. diff --git a/drivers/misc/qfw.c b/drivers/misc/qfw.c index f6eb6583ed..eae3afd23b 100644 --- a/drivers/misc/qfw.c +++ b/drivers/misc/qfw.c @@ -9,17 +9,18 @@ #include #include #include +#include #include +#include #ifdef CONFIG_GENERATE_ACPI_TABLE #include #endif -#include -static bool fwcfg_present; -static bool fwcfg_dma_present; -static struct fw_cfg_arch_ops *fwcfg_arch_ops; - -static LIST_HEAD(fw_list); +/* Determined at runtime. */ +struct qfw_priv { + bool dma_present; + struct list_head fw_list; +}; #ifdef CONFIG_GENERATE_ACPI_TABLE /* @@ -32,7 +33,8 @@ static LIST_HEAD(fw_list); * be ignored. * @return: 0 on success, or negative value on failure */ -static int bios_linker_allocate(struct bios_linker_entry *entry, ulong *addr) +static int bios_linker_allocate(struct udevice *dev, + struct bios_linker_entry *entry, ulong *addr) { uint32_t size, align; struct fw_file *file; @@ -45,7 +47,7 @@ static int bios_linker_allocate(struct bios_linker_entry *entry, ulong *addr) return -EINVAL; } - file = qemu_fwcfg_find_file(entry->alloc.file); + file = qemu_fwcfg_find_file(dev, entry->alloc.file); if (!file) { printf("error: can't find file %s\n", entry->alloc.file); return -ENOENT; @@ -75,7 +77,7 @@ static int bios_linker_allocate(struct bios_linker_entry *entry, ulong *addr) debug("bios_linker_allocate: allocate file %s, size %u, zone %d, align %u, addr 0x%lx\n", file->cfg.name, size, entry->alloc.zone, align, aligned_addr); - qemu_fwcfg_read_entry(be16_to_cpu(file->cfg.select), + qemu_fwcfg_read_entry(dev, be16_to_cpu(file->cfg.select), size, (void *)aligned_addr); file->addr = aligned_addr; @@ -94,16 +96,17 @@ static int bios_linker_allocate(struct bios_linker_entry *entry, ulong *addr) * ACPI tables * @return: 0 on success, or negative value on failure */ -static int bios_linker_add_pointer(struct bios_linker_entry *entry) +static int bios_linker_add_pointer(struct udevice *dev, + struct bios_linker_entry *entry) { struct fw_file *dest, *src; uint32_t offset = le32_to_cpu(entry->pointer.offset); uint64_t pointer = 0; - dest = qemu_fwcfg_find_file(entry->pointer.dest_file); + dest = qemu_fwcfg_find_file(dev, entry->pointer.dest_file); if (!dest || !dest->addr) return -ENOENT; - src = qemu_fwcfg_find_file(entry->pointer.src_file); + src = qemu_fwcfg_find_file(dev, entry->pointer.src_file); if (!src || !src->addr) return -ENOENT; @@ -127,13 +130,14 @@ static int bios_linker_add_pointer(struct bios_linker_entry *entry) * checksums * @return: 0 on success, or negative value on failure */ -static int bios_linker_add_checksum(struct bios_linker_entry *entry) +static int bios_linker_add_checksum(struct udevice *dev, + struct bios_linker_entry *entry) { struct fw_file *file; uint8_t *data, cksum = 0; uint8_t *cksum_start; - file = qemu_fwcfg_find_file(entry->cksum.file); + file = qemu_fwcfg_find_file(dev, entry->cksum.file); if (!file || !file->addr) return -ENOENT; @@ -154,15 +158,22 @@ ulong write_acpi_tables(ulong addr) struct bios_linker_entry *table_loader; struct bios_linker_entry *entry; uint32_t size; + struct udevice *dev; + + dev = qemu_fwcfg_dev(); + if (!dev) { + printf("error: no qfw\n"); + return addr; + } /* make sure fw_list is loaded */ - ret = qemu_fwcfg_read_firmware_list(); + ret = qemu_fwcfg_read_firmware_list(dev); if (ret) { printf("error: can't read firmware file list\n"); return addr; } - file = qemu_fwcfg_find_file("etc/table-loader"); + file = qemu_fwcfg_find_file(dev, "etc/table-loader"); if (!file) { printf("error: can't find etc/table-loader\n"); return addr; @@ -180,24 +191,24 @@ ulong write_acpi_tables(ulong addr) return addr; } - qemu_fwcfg_read_entry(be16_to_cpu(file->cfg.select), + qemu_fwcfg_read_entry(dev, be16_to_cpu(file->cfg.select), size, table_loader); for (i = 0; i < (size / sizeof(*entry)); i++) { entry = table_loader + i; switch (le32_to_cpu(entry->command)) { case BIOS_LINKER_LOADER_COMMAND_ALLOCATE: - ret = bios_linker_allocate(entry, &addr); + ret = bios_linker_allocate(dev, entry, &addr); if (ret) goto out; break; case BIOS_LINKER_LOADER_COMMAND_ADD_POINTER: - ret = bios_linker_add_pointer(entry); + ret = bios_linker_add_pointer(dev, entry); if (ret) goto out; break; case BIOS_LINKER_LOADER_COMMAND_ADD_CHECKSUM: - ret = bios_linker_add_checksum(entry); + ret = bios_linker_add_checksum(dev, entry); if (ret) goto out; break; @@ -209,7 +220,7 @@ ulong write_acpi_tables(ulong addr) out: if (ret) { struct fw_cfg_file_iter iter; - for (file = qemu_fwcfg_file_iter_init(&iter); + for (file = qemu_fwcfg_file_iter_init(dev, &iter); !qemu_fwcfg_file_iter_end(&iter); file = qemu_fwcfg_file_iter_next(&iter)) { if (file->addr) { @@ -226,31 +237,91 @@ out: ulong acpi_get_rsdp_addr(void) { struct fw_file *file; + struct udevice *dev; - file = qemu_fwcfg_find_file("etc/acpi/rsdp"); + dev = qemu_fwcfg_dev(); + if (!dev) { + printf("error: no qfw\n"); + return 0; + } + + file = qemu_fwcfg_find_file(dev, "etc/acpi/rsdp"); return file->addr; } #endif -/* Read configuration item using fw_cfg PIO interface */ -static void qemu_fwcfg_read_entry_pio(uint16_t entry, - uint32_t size, void *address) +/* Read configuration item using fw_cfg PIO/MMIO interface */ +static void qemu_fwcfg_read_entry_io(struct qfw_plat *plat, u16 entry, + u32 size, void *address) { - debug("qemu_fwcfg_read_entry_pio: entry 0x%x, size %u address %p\n", + debug("qemu_fwcfg_read_entry_io: entry 0x%x, size %u address %p\n", entry, size, address); - return fwcfg_arch_ops->arch_read_pio(entry, size, address); + /* + * writing FW_CFG_INVALID will cause read operation to resume at last + * offset, otherwise read will start at offset 0 + * + * Note: on platform where the control register is IO port, the + * endianness is little endian. Where it is on MMIO, the register is + * big endian. + */ + if (entry != FW_CFG_INVALID) { + if (plat->mmio) + plat->mmio->selector = cpu_to_be16(entry); +#ifdef CONFIG_X86 + else + outw(cpu_to_le16(entry), plat->io.control_port); +#endif + } + + /* the endianness of data register is string-preserving */ + + if (plat->mmio) { + while (size >= 8) { + *(u64 *)address = plat->mmio->data64; + address += 8; + size -= 8; + } + while (size >= 4) { + *(u32 *)address = plat->mmio->data32; + address += 4; + size -= 4; + } + while (size >= 2) { + *(u16 *)address = plat->mmio->data16; + address += 2; + size -= 2; + } + while (size >= 1) { + *(u8 *)address = plat->mmio->data8; + address += 1; + size -= 1; + } + } +#ifdef CONFIG_X86 + else { + u32 i = 0; + u8 *data = address; + + while (size--) + data[i++] = inb(plat->io.data_port); + } +#endif } /* Read configuration item using fw_cfg DMA interface */ -static void qemu_fwcfg_read_entry_dma(uint16_t entry, - uint32_t size, void *address) +static void qemu_fwcfg_read_entry_dma(struct qfw_plat *plat, u16 entry, + u32 size, void *address) { - struct fw_cfg_dma_access dma; - - dma.length = cpu_to_be32(size); - dma.address = cpu_to_be64((uintptr_t)address); - dma.control = cpu_to_be32(FW_CFG_DMA_READ); + struct { + __be32 control; + __be32 length; + __be64 address; + } dma = { + .length = cpu_to_be32(size), + .address = cpu_to_be64((uintptr_t)address), + .control = cpu_to_be32(FW_CFG_DMA_READ), + }; /* * writting FW_CFG_INVALID will cause read operation to resume at @@ -264,51 +335,58 @@ static void qemu_fwcfg_read_entry_dma(uint16_t entry, debug("qemu_fwcfg_read_entry_dma: entry 0x%x, size %u address %p, control 0x%x\n", entry, size, address, be32_to_cpu(dma.control)); - fwcfg_arch_ops->arch_read_dma(&dma); -} + /* the DMA address register is big-endian */ + if (plat->mmio) + plat->mmio->dma = cpu_to_be64((uintptr_t)&dma); +#ifdef CONFIG_X86 + else + outl(cpu_to_be32((uintptr_t)&dma), plat->io.dma_port_high); +#endif -bool qemu_fwcfg_present(void) -{ - return fwcfg_present; -} -bool qemu_fwcfg_dma_present(void) -{ - return fwcfg_dma_present; + while (be32_to_cpu(dma.control) & ~FW_CFG_DMA_ERROR) +#ifdef CONFIG_X86 + __asm__ __volatile__ ("pause"); +#else + __asm__ __volatile__ ("yield"); +#endif } -void qemu_fwcfg_read_entry(uint16_t entry, uint32_t length, void *address) +void qemu_fwcfg_read_entry(struct udevice *dev, u16 entry, u32 length, + void *address) { - if (fwcfg_dma_present) - qemu_fwcfg_read_entry_dma(entry, length, address); + struct qfw_plat *plat = dev_get_plat(dev); + struct qfw_priv *priv = dev_get_priv(dev); + + if (priv->dma_present) + qemu_fwcfg_read_entry_dma(plat, entry, length, address); else - qemu_fwcfg_read_entry_pio(entry, length, address); + qemu_fwcfg_read_entry_io(plat, entry, length, address); } -int qemu_fwcfg_online_cpus(void) +int qemu_fwcfg_online_cpus(struct udevice *dev) { - uint16_t nb_cpus; - - if (!fwcfg_present) - return -ENODEV; + u16 nb_cpus; - qemu_fwcfg_read_entry(FW_CFG_NB_CPUS, 2, &nb_cpus); + qemu_fwcfg_read_entry(dev, FW_CFG_NB_CPUS, 2, &nb_cpus); return le16_to_cpu(nb_cpus); } -int qemu_fwcfg_read_firmware_list(void) +int qemu_fwcfg_read_firmware_list(struct udevice *dev) { int i; - uint32_t count; + u32 count; struct fw_file *file; struct list_head *entry; + struct qfw_priv *priv = dev_get_priv(dev); + /* don't read it twice */ - if (!list_empty(&fw_list)) + if (!list_empty(&priv->fw_list)) return 0; - qemu_fwcfg_read_entry(FW_CFG_FILE_DIR, 4, &count); + qemu_fwcfg_read_entry(dev, FW_CFG_FILE_DIR, 4, &count); if (!count) return 0; @@ -319,16 +397,16 @@ int qemu_fwcfg_read_firmware_list(void) printf("error: allocating resource\n"); goto err; } - qemu_fwcfg_read_entry(FW_CFG_INVALID, + qemu_fwcfg_read_entry(dev, FW_CFG_INVALID, sizeof(struct fw_cfg_file), &file->cfg); file->addr = 0; - list_add_tail(&file->list, &fw_list); + list_add_tail(&file->list, &priv->fw_list); } return 0; err: - list_for_each(entry, &fw_list) { + list_for_each(entry, &priv->fw_list) { file = list_entry(entry, struct fw_file, list); free(file); } @@ -336,12 +414,14 @@ err: return -ENOMEM; } -struct fw_file *qemu_fwcfg_find_file(const char *name) +struct fw_file *qemu_fwcfg_find_file(struct udevice *dev, const char *name) { struct list_head *entry; struct fw_file *file; - list_for_each(entry, &fw_list) { + struct qfw_priv *priv = dev_get_priv(dev); + + list_for_each(entry, &priv->fw_list) { file = list_entry(entry, struct fw_file, list); if (!strcmp(file->cfg.name, name)) return file; @@ -350,9 +430,13 @@ struct fw_file *qemu_fwcfg_find_file(const char *name) return NULL; } -struct fw_file *qemu_fwcfg_file_iter_init(struct fw_cfg_file_iter *iter) +struct fw_file *qemu_fwcfg_file_iter_init(struct udevice *dev, + struct fw_cfg_file_iter *iter) { - iter->entry = fw_list.next; + struct qfw_priv *priv = dev_get_priv(dev); + + iter->entry = priv->fw_list.next; + iter->end = &priv->fw_list; return list_entry((struct list_head *)iter->entry, struct fw_file, list); } @@ -366,29 +450,62 @@ struct fw_file *qemu_fwcfg_file_iter_next(struct fw_cfg_file_iter *iter) bool qemu_fwcfg_file_iter_end(struct fw_cfg_file_iter *iter) { - return iter->entry == &fw_list; + return iter->entry == iter->end; } -void qemu_fwcfg_init(struct fw_cfg_arch_ops *ops) +static int qfw_of_to_plat(struct udevice *dev) { - uint32_t qemu; - uint32_t dma_enabled; - - fwcfg_present = false; - fwcfg_dma_present = false; - fwcfg_arch_ops = NULL; - - if (!ops || !ops->arch_read_pio || !ops->arch_read_dma) - return; - fwcfg_arch_ops = ops; - - qemu_fwcfg_read_entry_pio(FW_CFG_SIGNATURE, 4, &qemu); - if (be32_to_cpu(qemu) == QEMU_FW_CFG_SIGNATURE) - fwcfg_present = true; - - if (fwcfg_present) { - qemu_fwcfg_read_entry_pio(FW_CFG_ID, 1, &dma_enabled); - if (dma_enabled & FW_CFG_DMA_ENABLED) - fwcfg_dma_present = true; - } + struct qfw_plat *plat = dev_get_plat(dev); + + plat->mmio = map_physmem(dev_read_addr(dev), + sizeof(struct qfw_mmio), + MAP_NOCACHE); + + return 0; +} + +static int qfw_probe(struct udevice *dev) +{ + u32 qemu, dma_enabled; + struct qfw_plat *plat = dev_get_plat(dev); + struct qfw_priv *priv = dev_get_priv(dev); + + INIT_LIST_HEAD(&priv->fw_list); + + qemu_fwcfg_read_entry_io(plat, FW_CFG_SIGNATURE, 4, &qemu); + if (be32_to_cpu(qemu) != QEMU_FW_CFG_SIGNATURE) + return -ENODEV; + + qemu_fwcfg_read_entry_io(plat, FW_CFG_ID, 1, &dma_enabled); + if (dma_enabled & FW_CFG_DMA_ENABLED) + priv->dma_present = true; + + return 0; +} + +static const struct udevice_id qfw_ids[] = { + { .compatible = "qemu,fw-cfg-mmio" }, + {} +}; + +U_BOOT_DRIVER(qfw) = { + .name = "qfw", + .id = UCLASS_MISC, + .of_match = qfw_ids, + .of_to_plat = qfw_of_to_plat, + .plat_auto = sizeof(struct qfw_plat), + .priv_auto = sizeof(struct qfw_priv), + .probe = qfw_probe, +}; + +struct udevice *qemu_fwcfg_dev(void) +{ + struct udevice *dev; + int ret; + + /* XXX: decide what to do here */ + ret = uclass_first_device(UCLASS_MISC, &dev); + if (ret) + return NULL; + return dev; } diff --git a/include/qfw.h b/include/qfw.h index cea8e11d44..f9c6828841 100644 --- a/include/qfw.h +++ b/include/qfw.h @@ -82,19 +82,7 @@ struct fw_file { }; struct fw_cfg_file_iter { - struct list_head *entry; /* structure to iterate file list */ -}; - -struct fw_cfg_dma_access { - __be32 control; - __be32 length; - __be64 address; -}; - -struct fw_cfg_arch_ops { - void (*arch_read_pio)(uint16_t selector, uint32_t size, - void *address); - void (*arch_read_dma)(struct fw_cfg_dma_access *dma); + struct list_head *entry, *end; /* structures to iterate file list */ }; struct bios_linker_entry { @@ -146,32 +134,59 @@ struct bios_linker_entry { }; } __packed; +struct qfw_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; +}; + +struct qfw_plat { + /* MMIO used on Arm. */ + volatile struct qfw_mmio *mmio; + /* IO used on x86. */ + struct { + u16 control_port; + u16 data_port; + u16 dma_port_low; + u16 dma_port_high; + } io; +}; + +struct udevice; /** - * Initialize QEMU fw_cfg interface + * Get QEMU firmware config device * - * @ops: arch specific read operations + * @return struct udevice * if present, NULL otherwise */ -void qemu_fwcfg_init(struct fw_cfg_arch_ops *ops); +struct udevice *qemu_fwcfg_dev(void); -void qemu_fwcfg_read_entry(uint16_t entry, uint32_t length, void *address); -int qemu_fwcfg_read_firmware_list(void); -struct fw_file *qemu_fwcfg_find_file(const char *name); +void qemu_fwcfg_read_entry(struct udevice *dev, u16 entry, u32 length, + void *address); +int qemu_fwcfg_read_firmware_list(struct udevice *dev); +struct fw_file *qemu_fwcfg_find_file(struct udevice *dev, const char *name); /** * Get system cpu number * * @return: cpu number in system */ -int qemu_fwcfg_online_cpus(void); +int qemu_fwcfg_online_cpus(struct udevice *dev); /* helper functions to iterate firmware file list */ -struct fw_file *qemu_fwcfg_file_iter_init(struct fw_cfg_file_iter *iter); +struct fw_file *qemu_fwcfg_file_iter_init(struct udevice *dev, + struct fw_cfg_file_iter *iter); struct fw_file *qemu_fwcfg_file_iter_next(struct fw_cfg_file_iter *iter); bool qemu_fwcfg_file_iter_end(struct fw_cfg_file_iter *iter); -bool qemu_fwcfg_present(void); -bool qemu_fwcfg_dma_present(void); - /** * qemu_cpu_fixup() - Fix up the CPUs for QEMU * From patchwork Tue Feb 23 11:43:27 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Asherah Connor X-Patchwork-Id: 1443465 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=kivikakk.ee header.i=@kivikakk.ee header.a=rsa-sha256 header.s=fm3 header.b=v8x08f2Y; dkim=pass (2048-bit key; unprotected) header.d=messagingengine.com header.i=@messagingengine.com header.a=rsa-sha256 header.s=fm2 header.b=i1jSjLIt; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4DlHK65DJ2z9sVF for ; Tue, 23 Feb 2021 22:44:41 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id BFD4782A0C; Tue, 23 Feb 2021 12:44:37 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=kivikakk.ee Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (2048-bit key; unprotected) header.d=kivikakk.ee header.i=@kivikakk.ee header.b="v8x08f2Y"; dkim=pass (2048-bit key; unprotected) header.d=messagingengine.com header.i=@messagingengine.com header.b="i1jSjLIt"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id EB3D682A13; Tue, 23 Feb 2021 12:44:21 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL, SPF_HELO_PASS autolearn=ham autolearn_force=no version=3.4.2 Received: from new3-smtp.messagingengine.com (new3-smtp.messagingengine.com [66.111.4.229]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 1DBC482A09 for ; Tue, 23 Feb 2021 12:44:11 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=kivikakk.ee Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=ashe@kivikakk.ee Received: from compute5.internal (compute5.nyi.internal [10.202.2.45]) by mailnew.nyi.internal (Postfix) with ESMTP id 5EC06580406; Tue, 23 Feb 2021 06:44:10 -0500 (EST) Received: from mailfrontend2 ([10.202.2.163]) by compute5.internal (MEProxy); Tue, 23 Feb 2021 06:44:10 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kivikakk.ee; h= from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; s=fm3; bh=OMx+sjBGLXi+z 7NMZRM0JNBotONkUPLgeAzg39TSGsI=; b=v8x08f2YWanMFDQ3n0qtpXkHF8Lzb qSxDqetz+1auO6r8JOML5svMJuMaGw4h7DhFvtVKSUubZwMxS7fhGItVn4MSf25E mlO5DKNfETOPQWZt6XEamdp+KB+v2pUZFGeKFVbXIiphxHSZSkCrd2tWp7TWVPXy D5E3lZH5X5JWKooushXxkxJpfxbA6X+oAmwSqprXju9zu7M6nee1Z7FmQABZsogP 8oFe9bW/7JSBbpz8giZ3x6f6+k3c5qr4O/3FIkao6xofHg3RiPHWokWjySPApHhk X5j5dAUXpvTSNN8ZyyR6P8SDNwawttiojoX3lbKE2Ikz8DaQbFwmKI39g== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:date:from :in-reply-to:message-id:mime-version:references:subject:to :x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm2; bh=OMx+sjBGLXi+z7NMZRM0JNBotONkUPLgeAzg39TSGsI=; b=i1jSjLIt uZXpdrC9hVDPGLo+E5PDTEOsKT+tcI0lFax+YuMvKx3ADzwyTn1UIcbVcFGXpodj KkRfFDPn+N5exslJFJtIcWGaSGXifGOIkmfchuJ/0ZYtE8U2blpo7zMnCE6PwLnB KeYBsTC5AQ3xz4XxTlcizZISeu4fhzM4ENb4Ic1uxvGq7suQ1vaAznab+WN0GHV2 DIde8Yp6GvfMYkBHi2ZpT9ml0ju7V4/LTFNUDr2d+1/EktwAWpHdRqFiMFAd1q1y eWzLyXfNDsLVe/QzazTio6W6pIhWRYgXgtIzaC7C7xCmAeBRitAwBIRF+nKQoP4v aHIBS6++mYQMKw== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeduledrkeehgdefudcutefuodetggdotefrodftvf curfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfghnecu uegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenuc fjughrpefhvffufffkofgjfhgggfestdekredtredttdenucfhrhhomheptehshhgvrhgr hhcuvehonhhnohhruceorghshhgvsehkihhvihhkrghkkhdrvggvqeenucggtffrrghtth gvrhhnpeduffekffefveetfeefjeegudeghffgteeiteeltddtkedvgeffudeifeegkeet feenucfkphepudduledrudekrdefuddrudefheenucevlhhushhtvghrufhiiigvpedune curfgrrhgrmhepmhgrihhlfhhrohhmpegrshhhvgeskhhivhhikhgrkhhkrdgvvg X-ME-Proxy: Received: from ravenlin.tomodachi (119-18-31-135.77121f.mel.static.aussiebb.net [119.18.31.135]) by mail.messagingengine.com (Postfix) with ESMTPA id 8DC5B1080057; Tue, 23 Feb 2021 06:44:05 -0500 (EST) From: Asherah Connor To: u-boot@lists.denx.de Cc: Simon Glass , Asherah Connor , AKASHI Takahiro , Bharat Gooty , Bin Meng , Heinrich Schuchardt , Jagan Teki , Masahiro Yamada , Michal Simek , Peng Fan , Pragnesh Patel , Tero Kristo , Tom Rini , Trevor Woerner , Wolfgang Wallner Subject: [PATCH v3 2/4] arm: x86: qemu: add UCLASS_QFW, split driver into _pio and _mmio Date: Tue, 23 Feb 2021 22:43:27 +1100 Message-Id: <20210223114329.16729-3-ashe@kivikakk.ee> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20210223114329.16729-1-ashe@kivikakk.ee> References: <20210223114329.16729-1-ashe@kivikakk.ee> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.34 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.102.3 at phobos.denx.de X-Virus-Status: Clean Split the qfw driver into qfw_pio and qfw_mmio, under their own uclass. Each driver does arch/platform-specific I/O. Signed-off-by: Asherah Connor --- Changes in v3: - Add new UCLASS_QFW, split qfw driver into PIO and MMIO variants. - QFW no longer depends on or selects MISC. arch/x86/cpu/qemu/cpu.c | 2 +- arch/x86/cpu/qemu/qemu.c | 18 ++- arch/x86/cpu/qfw_cpu.c | 2 +- cmd/qfw.c | 26 ++-- common/Makefile | 2 + common/qfw.c | 111 ++++++++++++++++ drivers/misc/Kconfig | 1 - drivers/misc/Makefile | 6 + drivers/misc/qfw.c | 270 ++++++--------------------------------- drivers/misc/qfw_mmio.c | 101 +++++++++++++++ drivers/misc/qfw_pio.c | 66 ++++++++++ include/dm/uclass-id.h | 1 + include/qfw.h | 45 +++++-- 13 files changed, 382 insertions(+), 269 deletions(-) create mode 100644 common/qfw.c create mode 100644 drivers/misc/qfw_mmio.c create mode 100644 drivers/misc/qfw_pio.c diff --git a/arch/x86/cpu/qemu/cpu.c b/arch/x86/cpu/qemu/cpu.c index ab1b797f9a..09499aad78 100644 --- a/arch/x86/cpu/qemu/cpu.c +++ b/arch/x86/cpu/qemu/cpu.c @@ -22,7 +22,7 @@ int cpu_qemu_get_desc(const struct udevice *dev, char *buf, int size) static int cpu_qemu_get_count(const struct udevice *dev) { - struct udevice *qfw_dev = qemu_fwcfg_dev(); + struct udevice *qfw_dev = qfw_get_dev(); if (!qfw_dev) return -ENODEV; diff --git a/arch/x86/cpu/qemu/qemu.c b/arch/x86/cpu/qemu/qemu.c index e255af9a4a..5a61cc3bb4 100644 --- a/arch/x86/cpu/qemu/qemu.c +++ b/arch/x86/cpu/qemu/qemu.c @@ -20,18 +20,16 @@ static bool i440fx; #ifdef CONFIG_QFW /* on x86, the qfw registers are all IO ports */ -static const struct qfw_plat x86_qfw_plat = { - .io = { - .control_port = 0x510, - .data_port = 0x511, - .dma_port_low = 0x514, - .dma_port_high = 0x518, - }, +static const struct qfw_pio_plat x86_qfw_pio_plat = { + .control_port = 0x510, + .data_port = 0x511, + .dma_port_low = 0x514, + .dma_port_high = 0x518, }; -U_BOOT_DRVINFO(x86_qfw) = { - .name = "qfw", - .plat = &x86_qfw_plat, +U_BOOT_DRVINFO(x86_qfw_pio) = { + .name = "qfw_pio", + .plat = &x86_qfw_pio_plat, }; #endif diff --git a/arch/x86/cpu/qfw_cpu.c b/arch/x86/cpu/qfw_cpu.c index c8fb918494..e80cec0ca4 100644 --- a/arch/x86/cpu/qfw_cpu.c +++ b/arch/x86/cpu/qfw_cpu.c @@ -40,7 +40,7 @@ int qemu_cpu_fixup(void) } /* get qfw dev */ - qfwdev = qemu_fwcfg_dev(); + qfwdev = qfw_get_dev(); if (!qfwdev) { printf("unable to find qfw device\n"); return -ENODEV; diff --git a/cmd/qfw.c b/cmd/qfw.c index ec80a9a3b5..a983a45380 100644 --- a/cmd/qfw.c +++ b/cmd/qfw.c @@ -22,8 +22,8 @@ static int qemu_fwcfg_cmd_setup_kernel(void *load_addr, void *initrd_addr) char *data_addr; uint32_t setup_size, kernel_size, cmdline_size, initrd_size; - qemu_fwcfg_read_entry(qfw_dev, FW_CFG_SETUP_SIZE, 4, &setup_size); - qemu_fwcfg_read_entry(qfw_dev, FW_CFG_KERNEL_SIZE, 4, &kernel_size); + qfw_read_entry(qfw_dev, FW_CFG_SETUP_SIZE, 4, &setup_size); + qfw_read_entry(qfw_dev, FW_CFG_KERNEL_SIZE, 4, &kernel_size); if (setup_size == 0 || kernel_size == 0) { printf("warning: no kernel available\n"); @@ -31,28 +31,28 @@ static int qemu_fwcfg_cmd_setup_kernel(void *load_addr, void *initrd_addr) } data_addr = load_addr; - qemu_fwcfg_read_entry(qfw_dev, FW_CFG_SETUP_DATA, - le32_to_cpu(setup_size), data_addr); + qfw_read_entry(qfw_dev, FW_CFG_SETUP_DATA, + le32_to_cpu(setup_size), data_addr); data_addr += le32_to_cpu(setup_size); - qemu_fwcfg_read_entry(qfw_dev, FW_CFG_KERNEL_DATA, - le32_to_cpu(kernel_size), data_addr); + qfw_read_entry(qfw_dev, FW_CFG_KERNEL_DATA, + le32_to_cpu(kernel_size), data_addr); data_addr += le32_to_cpu(kernel_size); data_addr = initrd_addr; - qemu_fwcfg_read_entry(qfw_dev, FW_CFG_INITRD_SIZE, 4, &initrd_size); + qfw_read_entry(qfw_dev, FW_CFG_INITRD_SIZE, 4, &initrd_size); if (initrd_size == 0) { printf("warning: no initrd available\n"); } else { - qemu_fwcfg_read_entry(qfw_dev, FW_CFG_INITRD_DATA, - le32_to_cpu(initrd_size), data_addr); + qfw_read_entry(qfw_dev, FW_CFG_INITRD_DATA, + le32_to_cpu(initrd_size), data_addr); data_addr += le32_to_cpu(initrd_size); } - qemu_fwcfg_read_entry(qfw_dev, FW_CFG_CMDLINE_SIZE, 4, &cmdline_size); + qfw_read_entry(qfw_dev, FW_CFG_CMDLINE_SIZE, 4, &cmdline_size); if (cmdline_size) { - qemu_fwcfg_read_entry(qfw_dev, FW_CFG_CMDLINE_DATA, - le32_to_cpu(cmdline_size), data_addr); + qfw_read_entry(qfw_dev, FW_CFG_CMDLINE_DATA, + le32_to_cpu(cmdline_size), data_addr); /* * if kernel cmdline only contains '\0', (e.g. no -append * when invoking qemu), do not update bootargs @@ -163,7 +163,7 @@ static int do_qemu_fw(struct cmd_tbl *cmdtp, int flag, int argc, int ret; struct cmd_tbl *fwcfg_cmd; - qfw_dev = qemu_fwcfg_dev(); + qfw_dev = qfw_get_dev(); if (!qfw_dev) { printf("QEMU fw_cfg interface not found\n"); return CMD_RET_USAGE; diff --git a/common/Makefile b/common/Makefile index daeea67cf2..f174a06c33 100644 --- a/common/Makefile +++ b/common/Makefile @@ -137,3 +137,5 @@ obj-$(CONFIG_CMD_LOADB) += xyzModem.o obj-$(CONFIG_$(SPL_TPL_)YMODEM_SUPPORT) += xyzModem.o obj-$(CONFIG_AVB_VERIFY) += avb_verify.o + +obj-$(CONFIG_QFW) += qfw.o diff --git a/common/qfw.c b/common/qfw.c new file mode 100644 index 0000000000..b4c9e4483c --- /dev/null +++ b/common/qfw.c @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2015 Miao Yan + * (C) Copyright 2021 Asherah Connor + */ + +#include +#include +#include +#include + +struct udevice *qfw_get_dev(void) +{ + struct udevice *dev; + int ret; + + ret = uclass_first_device(UCLASS_QFW, &dev); + if (ret) + return NULL; + return dev; +} + +int qemu_fwcfg_online_cpus(struct udevice *dev) +{ + u16 nb_cpus; + + qfw_read_entry(dev, FW_CFG_NB_CPUS, 2, &nb_cpus); + + return le16_to_cpu(nb_cpus); +} + +int qemu_fwcfg_read_firmware_list(struct udevice *dev) +{ + int i; + u32 count; + struct fw_file *file; + struct list_head *entry; + + struct qfw_dev *qdev = dev_get_uclass_priv(dev); + + /* don't read it twice */ + if (!list_empty(&qdev->fw_list)) + return 0; + + qfw_read_entry(dev, FW_CFG_FILE_DIR, 4, &count); + if (!count) + return 0; + + count = be32_to_cpu(count); + for (i = 0; i < count; i++) { + file = malloc(sizeof(*file)); + if (!file) { + printf("error: allocating resource\n"); + goto err; + } + qfw_read_entry(dev, FW_CFG_INVALID, + sizeof(struct fw_cfg_file), &file->cfg); + file->addr = 0; + list_add_tail(&file->list, &qdev->fw_list); + } + + return 0; + +err: + list_for_each(entry, &qdev->fw_list) { + file = list_entry(entry, struct fw_file, list); + free(file); + } + + return -ENOMEM; +} + +struct fw_file *qemu_fwcfg_find_file(struct udevice *dev, const char *name) +{ + struct list_head *entry; + struct fw_file *file; + + struct qfw_dev *qdev = dev_get_uclass_priv(dev); + + list_for_each(entry, &qdev->fw_list) { + file = list_entry(entry, struct fw_file, list); + if (!strcmp(file->cfg.name, name)) + return file; + } + + return NULL; +} + +struct fw_file *qemu_fwcfg_file_iter_init(struct udevice *dev, + struct fw_cfg_file_iter *iter) +{ + struct qfw_dev *qdev = dev_get_uclass_priv(dev); + + iter->entry = qdev->fw_list.next; + iter->end = &qdev->fw_list; + return list_entry((struct list_head *)iter->entry, + struct fw_file, list); +} + +struct fw_file *qemu_fwcfg_file_iter_next(struct fw_cfg_file_iter *iter) +{ + iter->entry = ((struct list_head *)iter->entry)->next; + return list_entry((struct list_head *)iter->entry, + struct fw_file, list); +} + +bool qemu_fwcfg_file_iter_end(struct fw_cfg_file_iter *iter) +{ + return iter->entry == iter->end; +} + diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 0a65f29acd..7d2a299779 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -367,7 +367,6 @@ config WINBOND_W83627 config QFW bool - depends on MISC help Hidden option to enable QEMU fw_cfg interface. This will be selected by either CONFIG_CMD_QFW or CONFIG_GENERATE_ACPI_TABLE. diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index d737203704..e6e1dfea95 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -56,6 +56,12 @@ obj-$(CONFIG_P2SB) += p2sb-uclass.o obj-$(CONFIG_PCA9551_LED) += pca9551_led.o obj-$(CONFIG_$(SPL_)PWRSEQ) += pwrseq-uclass.o obj-$(CONFIG_QFW) += qfw.o +ifdef CONFIG_X86 +obj-$(CONFIG_QFW) += qfw_pio.o +endif +ifdef CONFIG_ARM +obj-$(CONFIG_QFW) += qfw_mmio.o +endif obj-$(CONFIG_ROCKCHIP_EFUSE) += rockchip-efuse.o obj-$(CONFIG_ROCKCHIP_OTP) += rockchip-otp.o obj-$(CONFIG_SANDBOX) += syscon_sandbox.o misc_sandbox.o diff --git a/drivers/misc/qfw.c b/drivers/misc/qfw.c index eae3afd23b..25b203375b 100644 --- a/drivers/misc/qfw.c +++ b/drivers/misc/qfw.c @@ -1,8 +1,11 @@ // SPDX-License-Identifier: GPL-2.0+ /* * (C) Copyright 2015 Miao Yan + * (C) Copyright 2021 Asherah Connor */ +#define LOG_CATEGORY UCLASS_QFW + #include #include #include @@ -10,18 +13,11 @@ #include #include #include -#include #include #ifdef CONFIG_GENERATE_ACPI_TABLE #include #endif -/* Determined at runtime. */ -struct qfw_priv { - bool dma_present; - struct list_head fw_list; -}; - #ifdef CONFIG_GENERATE_ACPI_TABLE /* * This function allocates memory for ACPI tables @@ -77,8 +73,8 @@ static int bios_linker_allocate(struct udevice *dev, debug("bios_linker_allocate: allocate file %s, size %u, zone %d, align %u, addr 0x%lx\n", file->cfg.name, size, entry->alloc.zone, align, aligned_addr); - qemu_fwcfg_read_entry(dev, be16_to_cpu(file->cfg.select), - size, (void *)aligned_addr); + qfw_read_entry(dev, be16_to_cpu(file->cfg.select), size, + (void *)aligned_addr); file->addr = aligned_addr; /* adjust address for low memory allocation */ @@ -160,7 +156,7 @@ ulong write_acpi_tables(ulong addr) uint32_t size; struct udevice *dev; - dev = qemu_fwcfg_dev(); + dev = qfw_get_dev(); if (!dev) { printf("error: no qfw\n"); return addr; @@ -191,8 +187,7 @@ ulong write_acpi_tables(ulong addr) return addr; } - qemu_fwcfg_read_entry(dev, be16_to_cpu(file->cfg.select), - size, table_loader); + qfw_read_entry(dev, be16_to_cpu(file->cfg.select), size, table_loader); for (i = 0; i < (size / sizeof(*entry)); i++) { entry = table_loader + i; @@ -239,7 +234,7 @@ ulong acpi_get_rsdp_addr(void) struct fw_file *file; struct udevice *dev; - dev = qemu_fwcfg_dev(); + dev = qfw_get_dev(); if (!dev) { printf("error: no qfw\n"); return 0; @@ -250,262 +245,75 @@ ulong acpi_get_rsdp_addr(void) } #endif -/* Read configuration item using fw_cfg PIO/MMIO interface */ -static void qemu_fwcfg_read_entry_io(struct qfw_plat *plat, u16 entry, - u32 size, void *address) +static void qfw_read_entry_io(struct qfw_dev *qdev, u16 entry, u32 size, + void *address) { - debug("qemu_fwcfg_read_entry_io: entry 0x%x, size %u address %p\n", - entry, size, address); + struct dm_qfw_ops *ops = dm_qfw_get_ops(qdev->dev); - /* - * writing FW_CFG_INVALID will cause read operation to resume at last - * offset, otherwise read will start at offset 0 - * - * Note: on platform where the control register is IO port, the - * endianness is little endian. Where it is on MMIO, the register is - * big endian. - */ - if (entry != FW_CFG_INVALID) { - if (plat->mmio) - plat->mmio->selector = cpu_to_be16(entry); -#ifdef CONFIG_X86 - else - outw(cpu_to_le16(entry), plat->io.control_port); -#endif - } + debug("%s: entry 0x%x, size %u address %p\n", __func__, entry, size, + address); - /* the endianness of data register is string-preserving */ - - if (plat->mmio) { - while (size >= 8) { - *(u64 *)address = plat->mmio->data64; - address += 8; - size -= 8; - } - while (size >= 4) { - *(u32 *)address = plat->mmio->data32; - address += 4; - size -= 4; - } - while (size >= 2) { - *(u16 *)address = plat->mmio->data16; - address += 2; - size -= 2; - } - while (size >= 1) { - *(u8 *)address = plat->mmio->data8; - address += 1; - size -= 1; - } - } -#ifdef CONFIG_X86 - else { - u32 i = 0; - u8 *data = address; - - while (size--) - data[i++] = inb(plat->io.data_port); - } -#endif + ops->read_entry_io(qdev->dev, entry, size, address); } -/* Read configuration item using fw_cfg DMA interface */ -static void qemu_fwcfg_read_entry_dma(struct qfw_plat *plat, u16 entry, - u32 size, void *address) +static void qfw_read_entry_dma(struct qfw_dev *qdev, u16 entry, u32 size, + void *address) { - struct { - __be32 control; - __be32 length; - __be64 address; - } dma = { + struct dm_qfw_ops *ops = dm_qfw_get_ops(qdev->dev); + + struct qfw_dma dma = { .length = cpu_to_be32(size), .address = cpu_to_be64((uintptr_t)address), .control = cpu_to_be32(FW_CFG_DMA_READ), }; /* - * writting FW_CFG_INVALID will cause read operation to resume at - * last offset, otherwise read will start at offset 0 + * writing FW_CFG_INVALID will cause read operation to resume at last + * offset, otherwise read will start at offset 0 */ if (entry != FW_CFG_INVALID) dma.control |= cpu_to_be32(FW_CFG_DMA_SELECT | (entry << 16)); - barrier(); - - debug("qemu_fwcfg_read_entry_dma: entry 0x%x, size %u address %p, control 0x%x\n", + debug("%s: entry 0x%x, size %u address %p, control 0x%x\n", __func__, entry, size, address, be32_to_cpu(dma.control)); - /* the DMA address register is big-endian */ - if (plat->mmio) - plat->mmio->dma = cpu_to_be64((uintptr_t)&dma); -#ifdef CONFIG_X86 - else - outl(cpu_to_be32((uintptr_t)&dma), plat->io.dma_port_high); -#endif - + barrier(); - while (be32_to_cpu(dma.control) & ~FW_CFG_DMA_ERROR) -#ifdef CONFIG_X86 - __asm__ __volatile__ ("pause"); -#else - __asm__ __volatile__ ("yield"); -#endif + ops->read_entry_dma(qdev->dev, &dma); } -void qemu_fwcfg_read_entry(struct udevice *dev, u16 entry, u32 length, - void *address) +void qfw_read_entry(struct udevice *dev, u16 entry, u32 length, void *address) { - struct qfw_plat *plat = dev_get_plat(dev); - struct qfw_priv *priv = dev_get_priv(dev); + struct qfw_dev *qdev = dev_get_uclass_priv(dev); - if (priv->dma_present) - qemu_fwcfg_read_entry_dma(plat, entry, length, address); + if (qdev->dma_present) + qfw_read_entry_dma(qdev, entry, length, address); else - qemu_fwcfg_read_entry_io(plat, entry, length, address); -} - -int qemu_fwcfg_online_cpus(struct udevice *dev) -{ - u16 nb_cpus; - - qemu_fwcfg_read_entry(dev, FW_CFG_NB_CPUS, 2, &nb_cpus); - - return le16_to_cpu(nb_cpus); -} - -int qemu_fwcfg_read_firmware_list(struct udevice *dev) -{ - int i; - u32 count; - struct fw_file *file; - struct list_head *entry; - - struct qfw_priv *priv = dev_get_priv(dev); - - /* don't read it twice */ - if (!list_empty(&priv->fw_list)) - return 0; - - qemu_fwcfg_read_entry(dev, FW_CFG_FILE_DIR, 4, &count); - if (!count) - return 0; - - count = be32_to_cpu(count); - for (i = 0; i < count; i++) { - file = malloc(sizeof(*file)); - if (!file) { - printf("error: allocating resource\n"); - goto err; - } - qemu_fwcfg_read_entry(dev, FW_CFG_INVALID, - sizeof(struct fw_cfg_file), &file->cfg); - file->addr = 0; - list_add_tail(&file->list, &priv->fw_list); - } - - return 0; - -err: - list_for_each(entry, &priv->fw_list) { - file = list_entry(entry, struct fw_file, list); - free(file); - } - - return -ENOMEM; -} - -struct fw_file *qemu_fwcfg_find_file(struct udevice *dev, const char *name) -{ - struct list_head *entry; - struct fw_file *file; - - struct qfw_priv *priv = dev_get_priv(dev); - - list_for_each(entry, &priv->fw_list) { - file = list_entry(entry, struct fw_file, list); - if (!strcmp(file->cfg.name, name)) - return file; - } - - return NULL; -} - -struct fw_file *qemu_fwcfg_file_iter_init(struct udevice *dev, - struct fw_cfg_file_iter *iter) -{ - struct qfw_priv *priv = dev_get_priv(dev); - - iter->entry = priv->fw_list.next; - iter->end = &priv->fw_list; - return list_entry((struct list_head *)iter->entry, - struct fw_file, list); -} - -struct fw_file *qemu_fwcfg_file_iter_next(struct fw_cfg_file_iter *iter) -{ - iter->entry = ((struct list_head *)iter->entry)->next; - return list_entry((struct list_head *)iter->entry, - struct fw_file, list); -} - -bool qemu_fwcfg_file_iter_end(struct fw_cfg_file_iter *iter) -{ - return iter->entry == iter->end; -} - -static int qfw_of_to_plat(struct udevice *dev) -{ - struct qfw_plat *plat = dev_get_plat(dev); - - plat->mmio = map_physmem(dev_read_addr(dev), - sizeof(struct qfw_mmio), - MAP_NOCACHE); - - return 0; + qfw_read_entry_io(qdev, entry, length, address); } -static int qfw_probe(struct udevice *dev) +int qfw_register(struct udevice *dev) { + struct qfw_dev *qdev = dev_get_uclass_priv(dev); u32 qemu, dma_enabled; - struct qfw_plat *plat = dev_get_plat(dev); - struct qfw_priv *priv = dev_get_priv(dev); - INIT_LIST_HEAD(&priv->fw_list); + qdev->dev = dev; + INIT_LIST_HEAD(&qdev->fw_list); - qemu_fwcfg_read_entry_io(plat, FW_CFG_SIGNATURE, 4, &qemu); + qfw_read_entry_io(qdev, FW_CFG_SIGNATURE, 4, &qemu); if (be32_to_cpu(qemu) != QEMU_FW_CFG_SIGNATURE) return -ENODEV; - qemu_fwcfg_read_entry_io(plat, FW_CFG_ID, 1, &dma_enabled); + qfw_read_entry_io(qdev, FW_CFG_ID, 1, &dma_enabled); if (dma_enabled & FW_CFG_DMA_ENABLED) - priv->dma_present = true; + qdev->dma_present = true; return 0; } -static const struct udevice_id qfw_ids[] = { - { .compatible = "qemu,fw-cfg-mmio" }, - {} -}; - -U_BOOT_DRIVER(qfw) = { +UCLASS_DRIVER(qfw) = { + .id = UCLASS_QFW, .name = "qfw", - .id = UCLASS_MISC, - .of_match = qfw_ids, - .of_to_plat = qfw_of_to_plat, - .plat_auto = sizeof(struct qfw_plat), - .priv_auto = sizeof(struct qfw_priv), - .probe = qfw_probe, + .per_device_auto = sizeof(struct qfw_dev), }; -struct udevice *qemu_fwcfg_dev(void) -{ - struct udevice *dev; - int ret; - - /* XXX: decide what to do here */ - ret = uclass_first_device(UCLASS_MISC, &dev); - if (ret) - return NULL; - return dev; -} diff --git a/drivers/misc/qfw_mmio.c b/drivers/misc/qfw_mmio.c new file mode 100644 index 0000000000..aa903cb51c --- /dev/null +++ b/drivers/misc/qfw_mmio.c @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * MMIO interface for QFW + * + * (C) Copyright 2015 Miao Yan + * (C) Copyright 2021 Asherah Connor + */ + +#define LOG_CATEGORY UCLASS_QFW + +#include +#include +#include +#include +#include + +static void qfw_mmio_read_entry_io(struct udevice *dev, u16 entry, u32 size, + void *address) +{ + struct qfw_mmio_plat *plat = dev_get_plat(dev); + + /* + * writing FW_CFG_INVALID will cause read operation to resume at last + * offset, otherwise read will start at offset 0 + * + * Note: on platform where the control register is MMIO, the register + * is big endian. + */ + if (entry != FW_CFG_INVALID) + plat->mmio->selector = cpu_to_be16(entry); + + /* the endianness of data register is string-preserving */ + while (size >= 8) { + *(u64 *)address = plat->mmio->data64; + address += 8; + size -= 8; + } + while (size >= 4) { + *(u32 *)address = plat->mmio->data32; + address += 4; + size -= 4; + } + while (size >= 2) { + *(u16 *)address = plat->mmio->data16; + address += 2; + size -= 2; + } + while (size >= 1) { + *(u8 *)address = plat->mmio->data8; + address += 1; + size -= 1; + } +} + +/* Read configuration item using fw_cfg DMA interface */ +static void qfw_mmio_read_entry_dma(struct udevice *dev, struct qfw_dma *dma) +{ + struct qfw_mmio_plat *plat = dev_get_plat(dev); + + /* the DMA address register is big-endian */ + plat->mmio->dma = cpu_to_be64((uintptr_t)dma); + + while (be32_to_cpu(dma->control) & ~FW_CFG_DMA_ERROR) + __asm__ __volatile__ ("yield"); +} + +static int qfw_mmio_of_to_plat(struct udevice *dev) +{ + struct qfw_mmio_plat *plat = dev_get_plat(dev); + + plat->mmio = map_physmem(dev_read_addr(dev), + sizeof(struct qfw_mmio), + MAP_NOCACHE); + + return 0; +} + +static int qfw_mmio_probe(struct udevice *dev) +{ + return qfw_register(dev); +} + +static struct dm_qfw_ops qfw_mmio_ops = { + .read_entry_io = qfw_mmio_read_entry_io, + .read_entry_dma = qfw_mmio_read_entry_dma, +}; + +static const struct udevice_id qfw_mmio_ids[] = { + { .compatible = "qemu,fw-cfg-mmio" }, + {} +}; + +U_BOOT_DRIVER(qfw_mmio) = { + .name = "qfw_mmio", + .id = UCLASS_QFW, + .of_match = qfw_mmio_ids, + .plat_auto = sizeof(struct qfw_mmio_plat), + .of_to_plat = qfw_mmio_of_to_plat, + .probe = qfw_mmio_probe, + .ops = &qfw_mmio_ops, +}; diff --git a/drivers/misc/qfw_pio.c b/drivers/misc/qfw_pio.c new file mode 100644 index 0000000000..beb722ad22 --- /dev/null +++ b/drivers/misc/qfw_pio.c @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * PIO interface for QFW + * + * (C) Copyright 2015 Miao Yan + * (C) Copyright 2021 Asherah Connor + */ + +#define LOG_CATEGORY UCLASS_QFW + +#include +#include +#include + +static void qfw_pio_read_entry_io(struct udevice *dev, u16 entry, u32 size, + void *address) +{ + struct qfw_pio_plat *plat = dev_get_plat(dev); + + /* + * writing FW_CFG_INVALID will cause read operation to resume at last + * offset, otherwise read will start at offset 0 + * + * Note: on platform where the control register is IO port, the + * endianness is little endian. + */ + if (entry != FW_CFG_INVALID) + outw(cpu_to_le16(entry), plat->control_port); + + /* the endianness of data register is string-preserving */ + u32 i = 0; + u8 *data = address; + + while (size--) + data[i++] = inb(plat->data_port); +} + +/* Read configuration item using fw_cfg DMA interface */ +static void qfw_pio_read_entry_dma(struct udevice *dev, struct qfw_dma *dma) +{ + struct qfw_pio_plat *plat = dev_get_plat(dev); + + /* the DMA address register is big-endian */ + outl(cpu_to_be32((uintptr_t)dma), plat->dma_port_high); + + while (be32_to_cpu(dma->control) & ~FW_CFG_DMA_ERROR) + __asm__ __volatile__ ("pause"); +} + +static int qfw_pio_probe(struct udevice *dev) +{ + return qfw_register(dev); +} + +static struct dm_qfw_ops qfw_pio_ops = { + .read_entry_io = qfw_pio_read_entry_io, + .read_entry_dma = qfw_pio_read_entry_dma, +}; + +U_BOOT_DRIVER(qfw_pio) = { + .name = "qfw_pio", + .id = UCLASS_QFW, + .plat_auto = sizeof(struct qfw_pio_plat), + .probe = qfw_pio_probe, + .ops = &qfw_pio_ops, +}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index d75de368c5..d800f679d5 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -90,6 +90,7 @@ enum uclass_id { UCLASS_POWER_DOMAIN, /* (SoC) Power domains */ UCLASS_PWM, /* Pulse-width modulator */ UCLASS_PWRSEQ, /* Power sequence device */ + UCLASS_QFW, /* QEMU firmware config device */ UCLASS_RAM, /* RAM controller */ UCLASS_REGULATOR, /* Regulator device */ UCLASS_REMOTEPROC, /* Remote Processor device */ diff --git a/include/qfw.h b/include/qfw.h index f9c6828841..d7e16651a2 100644 --- a/include/qfw.h +++ b/include/qfw.h @@ -149,28 +149,49 @@ struct qfw_mmio { u64 dma; }; -struct qfw_plat { - /* MMIO used on Arm. */ +struct qfw_pio_plat { + u16 control_port; + u16 data_port; + u16 dma_port_low; + u16 dma_port_high; +}; + +struct qfw_mmio_plat { volatile struct qfw_mmio *mmio; - /* IO used on x86. */ - struct { - u16 control_port; - u16 data_port; - u16 dma_port_low; - u16 dma_port_high; - } io; }; +struct qfw_dma { + __be32 control; + __be32 length; + __be64 address; +}; + +struct qfw_dev { + struct udevice *dev; + bool dma_present; + struct list_head fw_list; +}; + +struct dm_qfw_ops { + void (*read_entry_io)(struct udevice *dev, u16 entry, u32 size, + void *address); + void (*read_entry_dma)(struct udevice *dev, struct qfw_dma *dma); +}; + +#define dm_qfw_get_ops(dev) \ + ((struct dm_qfw_ops *)(dev)->driver->ops) + +int qfw_register(struct udevice *dev); + struct udevice; /** * Get QEMU firmware config device * * @return struct udevice * if present, NULL otherwise */ -struct udevice *qemu_fwcfg_dev(void); +struct udevice *qfw_get_dev(void); -void qemu_fwcfg_read_entry(struct udevice *dev, u16 entry, u32 length, - void *address); +void qfw_read_entry(struct udevice *dev, u16 entry, u32 length, void *address); int qemu_fwcfg_read_firmware_list(struct udevice *dev); struct fw_file *qemu_fwcfg_find_file(struct udevice *dev, const char *name); From patchwork Tue Feb 23 11:43:28 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Asherah Connor X-Patchwork-Id: 1443466 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=kivikakk.ee header.i=@kivikakk.ee header.a=rsa-sha256 header.s=fm3 header.b=otE1XKi3; dkim=pass (2048-bit key; unprotected) header.d=messagingengine.com header.i=@messagingengine.com header.a=rsa-sha256 header.s=fm2 header.b=n49jDUIt; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4DlHKL5r70z9sVF for ; Tue, 23 Feb 2021 22:44:54 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id E830382A15; Tue, 23 Feb 2021 12:44:43 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=kivikakk.ee Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (2048-bit key; unprotected) header.d=kivikakk.ee header.i=@kivikakk.ee header.b="otE1XKi3"; dkim=pass (2048-bit key; unprotected) header.d=messagingengine.com header.i=@messagingengine.com header.b="n49jDUIt"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 45B3A82A10; Tue, 23 Feb 2021 12:44:26 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL, SPF_HELO_PASS autolearn=ham autolearn_force=no version=3.4.2 Received: from out5-smtp.messagingengine.com (out5-smtp.messagingengine.com [66.111.4.29]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 331BD82A0C for ; Tue, 23 Feb 2021 12:44:14 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=kivikakk.ee Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=ashe@kivikakk.ee Received: from compute5.internal (compute5.nyi.internal [10.202.2.45]) by mailout.nyi.internal (Postfix) with ESMTP id E90155C0198; Tue, 23 Feb 2021 06:44:12 -0500 (EST) Received: from mailfrontend2 ([10.202.2.163]) by compute5.internal (MEProxy); Tue, 23 Feb 2021 06:44:12 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kivikakk.ee; h= from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; s=fm3; bh=yLsUKNCSjFyLJ 2E1sPu0RkqxBNmg84PswjXjdpkVdKI=; b=otE1XKi3m65RGZ26WV2slg7OoHJ4N pdvXkau8QFgvrNQfAcSzdLMC5ik2rxgtd4Qag58i34OCTckbZAa1o/UtnmP2EunZ Q6Lu+GuiSkPU834RhlDYVfK+pyZD27oLbBwyG0bQqjikiM8P0WRffGpVUFrQGWtn vPdr5p5J+XuloWQtPSjOVyPrRgx+yGRXvszZg51N83D1g/ZPRC2MDP7QRC8rij+X SH5sz7YFDpAd2SEIbE49Vtj5ewBZqpdO5zj3WHt5hvqXcJEfanwy022SKdxhVj6C waso2NCTQ5LM8KTmoWSHguv4Lwie529DLt0alCMDD28t7ladCs2MT9FIA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:date:from :in-reply-to:message-id:mime-version:references:subject:to :x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm2; bh=yLsUKNCSjFyLJ2E1sPu0RkqxBNmg84PswjXjdpkVdKI=; b=n49jDUIt RQdSB97OLGSXE5cOSabBFwOhXSsFIWaqlX2yO3znH559lHttmZiln7AVf0r+ZjZf rHM/qj6c//6Eu5MQsBh4mjoUEouXCndqYSgHy61/rH9advOOKhNvQYeFIvxZYCqC CQZc4EKUHQeO5oRpXx0oJYU96txt3QCmt+0GmHDuiVuqVD8y3iMUGILQmHvfvqZw DqwHptvfZUjvE2Ulce5xLNMGaG5plK5LNjAIhBacm3NJzO7L88M3IsabqAElykpk NHmuhu7caUhFO2mvOhdVfmYYb9s+IkD61vxlqTLvIU8G5crt28v8Q2Sv8Bx29A0+ 2TzxY1U9Qdtn3A== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeduledrkeehgdefudcutefuodetggdotefrodftvf curfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfghnecu uegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenuc fjughrpefhvffufffkofgjfhgggfestdekredtredttdenucfhrhhomheptehshhgvrhgr hhcuvehonhhnohhruceorghshhgvsehkihhvihhkrghkkhdrvggvqeenucggtffrrghtth gvrhhnpeduffekffefveetfeefjeegudeghffgteeiteeltddtkedvgeffudeifeegkeet feenucfkphepudduledrudekrdefuddrudefheenucevlhhushhtvghrufhiiigvpedune curfgrrhgrmhepmhgrihhlfhhrohhmpegrshhhvgeskhhivhhikhgrkhhkrdgvvg X-ME-Proxy: Received: from ravenlin.tomodachi (119-18-31-135.77121f.mel.static.aussiebb.net [119.18.31.135]) by mail.messagingengine.com (Postfix) with ESMTPA id 7B8941080057; Tue, 23 Feb 2021 06:44:10 -0500 (EST) From: Asherah Connor To: u-boot@lists.denx.de Cc: Simon Glass , Asherah Connor , Bharat Gooty , Bin Meng , Heinrich Schuchardt , Tom Rini Subject: [PATCH v3 3/4] arm: x86: qemu: unify qfw driver functions as qfw_ Date: Tue, 23 Feb 2021 22:43:28 +1100 Message-Id: <20210223114329.16729-4-ashe@kivikakk.ee> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20210223114329.16729-1-ashe@kivikakk.ee> References: <20210223114329.16729-1-ashe@kivikakk.ee> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.34 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.102.3 at phobos.denx.de X-Virus-Status: Clean There's a mixture of "qemu_fwcfg_"-prefixed functions and "qfw_"-prefixed ones. Now that the qfw name is applied in multiple places (i.e. the uclass itself, and each of its drivers), let's consistently use the prefix "qfw_" for anything relating to the drivers. Signed-off-by: Asherah Connor --- (no changes since v1) arch/x86/cpu/qemu/cpu.c | 2 +- arch/x86/cpu/qfw_cpu.c | 2 +- cmd/qfw.c | 10 +++++----- common/qfw.c | 14 +++++++------- drivers/misc/qfw.c | 20 ++++++++++---------- include/qfw.h | 16 ++++++++-------- 6 files changed, 32 insertions(+), 32 deletions(-) diff --git a/arch/x86/cpu/qemu/cpu.c b/arch/x86/cpu/qemu/cpu.c index 09499aad78..0a3962df41 100644 --- a/arch/x86/cpu/qemu/cpu.c +++ b/arch/x86/cpu/qemu/cpu.c @@ -27,7 +27,7 @@ static int cpu_qemu_get_count(const struct udevice *dev) if (!qfw_dev) return -ENODEV; - return qemu_fwcfg_online_cpus(qfw_dev); + return qfw_online_cpus(qfw_dev); } static const struct cpu_ops cpu_qemu_ops = { diff --git a/arch/x86/cpu/qfw_cpu.c b/arch/x86/cpu/qfw_cpu.c index e80cec0ca4..3b94686193 100644 --- a/arch/x86/cpu/qfw_cpu.c +++ b/arch/x86/cpu/qfw_cpu.c @@ -55,7 +55,7 @@ int qemu_cpu_fixup(void) } /* get actual cpu number */ - cpu_online = qemu_fwcfg_online_cpus(qfwdev); + cpu_online = qfw_online_cpus(qfwdev); if (cpu_online < 0) { printf("unable to get online cpu number: %d\n", cpu_online); return cpu_online; diff --git a/cmd/qfw.c b/cmd/qfw.c index a983a45380..e972b26d1e 100644 --- a/cmd/qfw.c +++ b/cmd/qfw.c @@ -82,13 +82,13 @@ static int qemu_fwcfg_cmd_list_firmware(void) struct fw_file *file; /* make sure fw_list is loaded */ - ret = qemu_fwcfg_read_firmware_list(qfw_dev); + ret = qfw_read_firmware_list(qfw_dev); if (ret) return ret; - for (file = qemu_fwcfg_file_iter_init(qfw_dev, &iter); - !qemu_fwcfg_file_iter_end(&iter); - file = qemu_fwcfg_file_iter_next(&iter)) { + for (file = qfw_file_iter_init(qfw_dev, &iter); + !qfw_file_iter_end(&iter); + file = qfw_file_iter_next(&iter)) { printf("%-56s\n", file->cfg.name); } @@ -107,7 +107,7 @@ static int qemu_fwcfg_do_list(struct cmd_tbl *cmdtp, int flag, static int qemu_fwcfg_do_cpus(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { - printf("%d cpu(s) online\n", qemu_fwcfg_online_cpus(qfw_dev)); + printf("%d cpu(s) online\n", qfw_online_cpus(qfw_dev)); return 0; } diff --git a/common/qfw.c b/common/qfw.c index b4c9e4483c..36b19bdc9b 100644 --- a/common/qfw.c +++ b/common/qfw.c @@ -20,7 +20,7 @@ struct udevice *qfw_get_dev(void) return dev; } -int qemu_fwcfg_online_cpus(struct udevice *dev) +int qfw_online_cpus(struct udevice *dev) { u16 nb_cpus; @@ -29,7 +29,7 @@ int qemu_fwcfg_online_cpus(struct udevice *dev) return le16_to_cpu(nb_cpus); } -int qemu_fwcfg_read_firmware_list(struct udevice *dev) +int qfw_read_firmware_list(struct udevice *dev) { int i; u32 count; @@ -70,7 +70,7 @@ err: return -ENOMEM; } -struct fw_file *qemu_fwcfg_find_file(struct udevice *dev, const char *name) +struct fw_file *qfw_find_file(struct udevice *dev, const char *name) { struct list_head *entry; struct fw_file *file; @@ -86,8 +86,8 @@ struct fw_file *qemu_fwcfg_find_file(struct udevice *dev, const char *name) return NULL; } -struct fw_file *qemu_fwcfg_file_iter_init(struct udevice *dev, - struct fw_cfg_file_iter *iter) +struct fw_file *qfw_file_iter_init(struct udevice *dev, + struct fw_cfg_file_iter *iter) { struct qfw_dev *qdev = dev_get_uclass_priv(dev); @@ -97,14 +97,14 @@ struct fw_file *qemu_fwcfg_file_iter_init(struct udevice *dev, struct fw_file, list); } -struct fw_file *qemu_fwcfg_file_iter_next(struct fw_cfg_file_iter *iter) +struct fw_file *qfw_file_iter_next(struct fw_cfg_file_iter *iter) { iter->entry = ((struct list_head *)iter->entry)->next; return list_entry((struct list_head *)iter->entry, struct fw_file, list); } -bool qemu_fwcfg_file_iter_end(struct fw_cfg_file_iter *iter) +bool qfw_file_iter_end(struct fw_cfg_file_iter *iter) { return iter->entry == iter->end; } diff --git a/drivers/misc/qfw.c b/drivers/misc/qfw.c index 25b203375b..4569f1886b 100644 --- a/drivers/misc/qfw.c +++ b/drivers/misc/qfw.c @@ -43,7 +43,7 @@ static int bios_linker_allocate(struct udevice *dev, return -EINVAL; } - file = qemu_fwcfg_find_file(dev, entry->alloc.file); + file = qfw_find_file(dev, entry->alloc.file); if (!file) { printf("error: can't find file %s\n", entry->alloc.file); return -ENOENT; @@ -99,10 +99,10 @@ static int bios_linker_add_pointer(struct udevice *dev, uint32_t offset = le32_to_cpu(entry->pointer.offset); uint64_t pointer = 0; - dest = qemu_fwcfg_find_file(dev, entry->pointer.dest_file); + dest = qfw_find_file(dev, entry->pointer.dest_file); if (!dest || !dest->addr) return -ENOENT; - src = qemu_fwcfg_find_file(dev, entry->pointer.src_file); + src = qfw_find_file(dev, entry->pointer.src_file); if (!src || !src->addr) return -ENOENT; @@ -133,7 +133,7 @@ static int bios_linker_add_checksum(struct udevice *dev, uint8_t *data, cksum = 0; uint8_t *cksum_start; - file = qemu_fwcfg_find_file(dev, entry->cksum.file); + file = qfw_find_file(dev, entry->cksum.file); if (!file || !file->addr) return -ENOENT; @@ -163,13 +163,13 @@ ulong write_acpi_tables(ulong addr) } /* make sure fw_list is loaded */ - ret = qemu_fwcfg_read_firmware_list(dev); + ret = qfw_read_firmware_list(dev); if (ret) { printf("error: can't read firmware file list\n"); return addr; } - file = qemu_fwcfg_find_file(dev, "etc/table-loader"); + file = qfw_find_file(dev, "etc/table-loader"); if (!file) { printf("error: can't find etc/table-loader\n"); return addr; @@ -215,9 +215,9 @@ ulong write_acpi_tables(ulong addr) out: if (ret) { struct fw_cfg_file_iter iter; - for (file = qemu_fwcfg_file_iter_init(dev, &iter); - !qemu_fwcfg_file_iter_end(&iter); - file = qemu_fwcfg_file_iter_next(&iter)) { + for (file = qfw_file_iter_init(dev, &iter); + !qfw_file_iter_end(&iter); + file = qfw_file_iter_next(&iter)) { if (file->addr) { free((void *)file->addr); file->addr = 0; @@ -240,7 +240,7 @@ ulong acpi_get_rsdp_addr(void) return 0; } - file = qemu_fwcfg_find_file(dev, "etc/acpi/rsdp"); + file = qfw_find_file(dev, "etc/acpi/rsdp"); return file->addr; } #endif diff --git a/include/qfw.h b/include/qfw.h index d7e16651a2..52ca1533f5 100644 --- a/include/qfw.h +++ b/include/qfw.h @@ -8,7 +8,7 @@ #include -enum qemu_fwcfg_items { +enum { FW_CFG_SIGNATURE = 0x00, FW_CFG_ID = 0x01, FW_CFG_UUID = 0x02, @@ -192,21 +192,21 @@ struct udevice; struct udevice *qfw_get_dev(void); void qfw_read_entry(struct udevice *dev, u16 entry, u32 length, void *address); -int qemu_fwcfg_read_firmware_list(struct udevice *dev); -struct fw_file *qemu_fwcfg_find_file(struct udevice *dev, const char *name); +int qfw_read_firmware_list(struct udevice *dev); +struct fw_file *qfw_find_file(struct udevice *dev, const char *name); /** * Get system cpu number * * @return: cpu number in system */ -int qemu_fwcfg_online_cpus(struct udevice *dev); +int qfw_online_cpus(struct udevice *dev); /* helper functions to iterate firmware file list */ -struct fw_file *qemu_fwcfg_file_iter_init(struct udevice *dev, - struct fw_cfg_file_iter *iter); -struct fw_file *qemu_fwcfg_file_iter_next(struct fw_cfg_file_iter *iter); -bool qemu_fwcfg_file_iter_end(struct fw_cfg_file_iter *iter); +struct fw_file *qfw_file_iter_init(struct udevice *dev, + struct fw_cfg_file_iter *iter); +struct fw_file *qfw_file_iter_next(struct fw_cfg_file_iter *iter); +bool qfw_file_iter_end(struct fw_cfg_file_iter *iter); /** * qemu_cpu_fixup() - Fix up the CPUs for QEMU From patchwork Tue Feb 23 11:43:29 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Asherah Connor X-Patchwork-Id: 1443467 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=kivikakk.ee header.i=@kivikakk.ee header.a=rsa-sha256 header.s=fm3 header.b=llefywOj; dkim=pass (2048-bit key; unprotected) header.d=messagingengine.com header.i=@messagingengine.com header.a=rsa-sha256 header.s=fm2 header.b=l35pvwsK; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4DlHKd0PVDz9sVF for ; Tue, 23 Feb 2021 22:45:08 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 7C62382971; Tue, 23 Feb 2021 12:44:54 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=kivikakk.ee Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (2048-bit key; unprotected) header.d=kivikakk.ee header.i=@kivikakk.ee header.b="llefywOj"; dkim=pass (2048-bit key; unprotected) header.d=messagingengine.com header.i=@messagingengine.com header.b="l35pvwsK"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 7787082A0F; Tue, 23 Feb 2021 12:44:29 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL, SPF_HELO_PASS autolearn=ham autolearn_force=no version=3.4.2 Received: from new3-smtp.messagingengine.com (new3-smtp.messagingengine.com [66.111.4.229]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 89E8382A11 for ; Tue, 23 Feb 2021 12:44:18 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=kivikakk.ee Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=ashe@kivikakk.ee Received: from compute5.internal (compute5.nyi.internal [10.202.2.45]) by mailnew.nyi.internal (Postfix) with ESMTP id C96FB580406; Tue, 23 Feb 2021 06:44:17 -0500 (EST) Received: from mailfrontend2 ([10.202.2.163]) by compute5.internal (MEProxy); Tue, 23 Feb 2021 06:44:17 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kivikakk.ee; h= from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; s=fm3; bh=I6xTOrdCFVDfV K5jItpKnh/T0g+XA1MWu+oyWR6NWl8=; b=llefywOjFQ3VqD5Uqsb/+i14xsrTp fHbo1aHU9reA1w26hFxLU5of5opNT1RE9WSoDv29K7i6Wb7MMtcPKFr5+KMcFh6N 3rxHpKgXqP9dvDdSuR0RQK6recIu5xAbJlzcctOIZiLnjQocGGGMYRNEOyC3GyIE YIle6wYADWCdMUbNQVHze6KxdlC8GN/oLftA8IUGSiXV8+lTArMtY3Z1803S4srn 9KTo+yoFXpjBtbjzUUJcy/hL89qHhhUvG9msGFG+ai7q0SWo910Tiis4yWTnR9y7 Jl1QL3aQGXhgqUg6kF0tXw4DbAPfbxnsTDmgRrO+Q8xob+f/s6o+/x0+A== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:date:from :in-reply-to:message-id:mime-version:references:subject:to :x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm2; bh=I6xTOrdCFVDfVK5jItpKnh/T0g+XA1MWu+oyWR6NWl8=; b=l35pvwsK P+ow+l9WI/VMbfj5+arjiNndxsWbn4kmJtsJrJ+XnOhDRbELT4cPKOTGEFwnccv3 POUMQ1rIKAhuZHDRbIhr99S2gYtwH/mgMrg7Tp5/RPnPzpW2u+X/i0wLeF938WqV gaFw5tITR6SQf0Kvu9srLiYyplgNYwxAkSK2euOfJmrU7v3dBvLCQahH9CcnpZsV OaLDmXG1cS79yyu2cLWD0Xn5zSHi4FgI6n2ipjAdfFhuG4BQuQQ/iiPM8WOMWoN2 5gF/KTJ1c5W3h6A+PVFwBjJUT6DBxGv7/Qsi1uXX2Nd/ITWOIPBtVysOHHRsZu9p XbNFQqIUbwGfpg== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeduledrkeehgdefudcutefuodetggdotefrodftvf curfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfghnecu uegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenuc fjughrpefhvffufffkofgjfhgggfestdekredtredttdenucfhrhhomheptehshhgvrhgr hhcuvehonhhnohhruceorghshhgvsehkihhvihhkrghkkhdrvggvqeenucggtffrrghtth gvrhhnpeduffekffefveetfeefjeegudeghffgteeiteeltddtkedvgeffudeifeegkeet feenucfkphepudduledrudekrdefuddrudefheenucevlhhushhtvghrufhiiigvpeefne curfgrrhgrmhepmhgrihhlfhhrohhmpegrshhhvgeskhhivhhikhgrkhhkrdgvvg X-ME-Proxy: Received: from ravenlin.tomodachi (119-18-31-135.77121f.mel.static.aussiebb.net [119.18.31.135]) by mail.messagingengine.com (Postfix) with ESMTPA id 1AC6C108005B; Tue, 23 Feb 2021 06:44:12 -0500 (EST) From: Asherah Connor To: u-boot@lists.denx.de Cc: Simon Glass , Asherah Connor , Bharat Gooty , Bin Meng , Dario Binacchi , Etienne Carriere , Heiko Schocher , Heinrich Schuchardt , Jagan Teki , Jean-Jacques Hiblot , Patrick Delaunay , Philippe Reynes , Pragnesh Patel , Sean Anderson , Tero Kristo , Wolfgang Wallner Subject: [PATCH v3 4/4] qemu: add sandbox driver and tests Date: Tue, 23 Feb 2021 22:43:29 +1100 Message-Id: <20210223114329.16729-5-ashe@kivikakk.ee> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20210223114329.16729-1-ashe@kivikakk.ee> References: <20210223114329.16729-1-ashe@kivikakk.ee> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.34 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.102.3 at phobos.denx.de X-Virus-Status: Clean We minimally exercise the sandbox driver. Signed-off-by: Asherah Connor Signed-off-by: Asherah Connor Reviewed-by: Simon Glass --- (no changes since v1) arch/sandbox/dts/sandbox.dtsi | 4 ++ arch/sandbox/dts/test.dts | 4 ++ drivers/misc/Makefile | 11 ++- drivers/misc/qfw_sandbox.c | 129 ++++++++++++++++++++++++++++++++++ test/dm/Makefile | 1 + test/dm/qfw.c | 42 +++++++++++ 6 files changed, 185 insertions(+), 6 deletions(-) create mode 100644 drivers/misc/qfw_sandbox.c create mode 100644 test/dm/qfw.c diff --git a/arch/sandbox/dts/sandbox.dtsi b/arch/sandbox/dts/sandbox.dtsi index dc933f3bfc..7ce05b9662 100644 --- a/arch/sandbox/dts/sandbox.dtsi +++ b/arch/sandbox/dts/sandbox.dtsi @@ -390,6 +390,10 @@ sandbox_tee { compatible = "sandbox,tee"; }; + + qfw { + compatible = "sandbox,qemu-fw-cfg-mmio"; + }; }; &cros_ec { diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index d4195b45bb..4b3f8831d5 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -112,6 +112,10 @@ compatible = "sandbox,dsi-host"; }; + qfw { + compatible = "sandbox,qemu-fw-cfg-mmio"; + }; + a-test { reg = <0 1>; compatible = "denx,u-boot-fdt-test"; diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index e6e1dfea95..ea04abd6c5 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -55,12 +55,11 @@ obj-$(CONFIG_NUVOTON_NCT6102D) += nuvoton_nct6102d.o obj-$(CONFIG_P2SB) += p2sb-uclass.o obj-$(CONFIG_PCA9551_LED) += pca9551_led.o obj-$(CONFIG_$(SPL_)PWRSEQ) += pwrseq-uclass.o -obj-$(CONFIG_QFW) += qfw.o -ifdef CONFIG_X86 -obj-$(CONFIG_QFW) += qfw_pio.o -endif -ifdef CONFIG_ARM -obj-$(CONFIG_QFW) += qfw_mmio.o +ifdef CONFIG_QFW +obj-y += qfw.o +obj-$(CONFIG_X86) += qfw_pio.o +obj-$(CONFIG_ARM) += qfw_mmio.o +obj-$(CONFIG_SANDBOX) += qfw_sandbox.o endif obj-$(CONFIG_ROCKCHIP_EFUSE) += rockchip-efuse.o obj-$(CONFIG_ROCKCHIP_OTP) += rockchip-otp.o diff --git a/drivers/misc/qfw_sandbox.c b/drivers/misc/qfw_sandbox.c new file mode 100644 index 0000000000..fc7006ae19 --- /dev/null +++ b/drivers/misc/qfw_sandbox.c @@ -0,0 +1,129 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Sandbox interface for QFW + * + * (C) Copyright 2015 Miao Yan + * (C) Copyright 2021 Asherah Connor + */ + +#define LOG_CATEGORY UCLASS_QFW + +#include +#include +#include +#include +#include + +struct qfw_sandbox_plat { + u8 file_dir_offset; +}; + +static void qfw_sandbox_read_entry_io(struct udevice *dev, u16 entry, u32 size, + void *address) +{ + debug("%s: entry 0x%x size %u address %p\n", __func__, entry, size, + address); + + switch (entry) { + case FW_CFG_SIGNATURE: + if (size == 4) + *((u32 *)address) = cpu_to_be32(QEMU_FW_CFG_SIGNATURE); + break; + case FW_CFG_ID: + /* Advertise DMA support */ + if (size == 1) + *((u8 *)address) = FW_CFG_DMA_ENABLED; + break; + default: + debug("%s got unsupported entry 0x%x\n", __func__, entry); + /* + * Sandbox driver doesn't support other entries here, assume we use DMA + * to read them -- the uclass driver will exclusively use it when + * advertised. + */ + } +} + +static void qfw_sandbox_read_entry_dma(struct udevice *dev, struct qfw_dma *dma) +{ + u16 entry; + u32 control = be32_to_cpu(dma->control); + void *address = (void *)be64_to_cpu(dma->address); + u32 length = be32_to_cpu(dma->length); + struct qfw_sandbox_plat *plat = dev_get_plat(dev); + struct fw_cfg_file *file; + + debug("%s\n", __func__); + + if (!(control & FW_CFG_DMA_READ)) + return; + + if (control & FW_CFG_DMA_SELECT) { + /* Start new read. */ + entry = control >> 16; + + /* Arbitrary values to be used by tests. */ + switch (entry) { + case FW_CFG_NB_CPUS: + if (length == 2) + *((u16 *)address) = cpu_to_le16(5); + break; + case FW_CFG_FILE_DIR: + if (length == 4) { + *((u32 *)address) = cpu_to_be32(2); + plat->file_dir_offset = 1; + } + break; + default: + debug("%s got unsupported entry 0x%x\n", __func__, + entry); + } + } else if (plat->file_dir_offset && length == 64) { + file = address; + switch (plat->file_dir_offset) { + case 1: + file->size = cpu_to_be32(8); + file->select = cpu_to_be16(FW_CFG_FILE_FIRST); + strcpy(file->name, "test-one"); + plat->file_dir_offset++; + break; + case 2: + file->size = cpu_to_be32(8); + file->select = cpu_to_be16(FW_CFG_FILE_FIRST + 1); + strcpy(file->name, "test-two"); + plat->file_dir_offset++; + break; + } + } + + /* + * Signal that we are finished. No-one checks this in sandbox -- + * normally the platform-specific driver looks for it -- but let's + * replicate the behaviour in case someone relies on it later. + */ + dma->control = 0; +} + +static int qfw_sandbox_probe(struct udevice *dev) +{ + return qfw_register(dev); +} + +static struct dm_qfw_ops qfw_sandbox_ops = { + .read_entry_io = qfw_sandbox_read_entry_io, + .read_entry_dma = qfw_sandbox_read_entry_dma, +}; + +static const struct udevice_id qfw_sandbox_ids[] = { + { .compatible = "sandbox,qemu-fw-cfg-mmio" }, + {} +}; + +U_BOOT_DRIVER(qfw_sandbox) = { + .name = "qfw_sandbox", + .id = UCLASS_QFW, + .of_match = qfw_sandbox_ids, + .plat_auto = sizeof(struct qfw_sandbox_plat), + .probe = qfw_sandbox_probe, + .ops = &qfw_sandbox_ops, +}; diff --git a/test/dm/Makefile b/test/dm/Makefile index 6275ec56ea..bdca7ae613 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -95,5 +95,6 @@ obj-$(CONFIG_SCMI_FIRMWARE) += scmi.o ifneq ($(CONFIG_PINMUX),) obj-$(CONFIG_PINCONF) += pinmux.o endif +obj-$(CONFIG_QFW) += qfw.o endif endif # !SPL diff --git a/test/dm/qfw.c b/test/dm/qfw.c new file mode 100644 index 0000000000..51b1c42dda --- /dev/null +++ b/test/dm/qfw.c @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2021 Asherah Connor + */ + +#include +#include +#include +#include +#include +#include + +/* + * Exercise the device enough to be satisfied the initialisation and DMA + * interfaces work. + */ + +static int dm_test_qfw_cpus(struct unit_test_state *uts) +{ + struct udevice *dev; + + ut_assertok(uclass_first_device_err(UCLASS_QFW, &dev)); + ut_asserteq(5, qfw_online_cpus(dev)); + + return 0; +} + +DM_TEST(dm_test_qfw_cpus, UT_TESTF_SCAN_FDT); + +static int dm_test_qfw_firmware_list(struct unit_test_state *uts) +{ + struct udevice *dev; + struct fw_file *file; + + ut_assertok(uclass_first_device_err(UCLASS_QFW, &dev)); + ut_assertok(qfw_read_firmware_list(dev)); + ut_assertok_ptr((file = qfw_find_file(dev, "test-one"))); + + return 0; +} + +DM_TEST(dm_test_qfw_firmware_list, UT_TESTF_SCAN_FDT);