test: qemu: add qfw sandbox driver, dm tests, qemu tests
A sandbox driver and test are added for the qfw uclass, and a test in QEMU added for qfw functionality to confirm it doesn't break in real world use. Signed-off-by: Asherah Connor <ashe@kivikakk.ee> Reviewed-by: Simon Glass <sjg@chromium.org> Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
This commit is contained in:
		
							parent
							
								
									5b0b43e0e2
								
							
						
					
					
						commit
						69512551aa
					
				|  | @ -73,7 +73,6 @@ CONFIG_CMD_EFIDEBUG=y | ||||||
| CONFIG_CMD_TIME=y | CONFIG_CMD_TIME=y | ||||||
| CONFIG_CMD_TIMER=y | CONFIG_CMD_TIMER=y | ||||||
| CONFIG_CMD_SOUND=y | CONFIG_CMD_SOUND=y | ||||||
| CONFIG_CMD_QFW=y |  | ||||||
| CONFIG_CMD_BOOTSTAGE=y | CONFIG_CMD_BOOTSTAGE=y | ||||||
| CONFIG_CMD_PMIC=y | CONFIG_CMD_PMIC=y | ||||||
| CONFIG_CMD_REGULATOR=y | CONFIG_CMD_REGULATOR=y | ||||||
|  |  | ||||||
|  | @ -75,7 +75,6 @@ CONFIG_CMD_EFIDEBUG=y | ||||||
| CONFIG_CMD_TIME=y | CONFIG_CMD_TIME=y | ||||||
| CONFIG_CMD_TIMER=y | CONFIG_CMD_TIMER=y | ||||||
| CONFIG_CMD_SOUND=y | CONFIG_CMD_SOUND=y | ||||||
| CONFIG_CMD_QFW=y |  | ||||||
| CONFIG_CMD_BOOTSTAGE=y | CONFIG_CMD_BOOTSTAGE=y | ||||||
| CONFIG_CMD_PMIC=y | CONFIG_CMD_PMIC=y | ||||||
| CONFIG_CMD_REGULATOR=y | CONFIG_CMD_REGULATOR=y | ||||||
|  |  | ||||||
|  | @ -58,6 +58,7 @@ obj-$(CONFIG_$(SPL_)PWRSEQ) += pwrseq-uclass.o | ||||||
| ifdef CONFIG_QFW | ifdef CONFIG_QFW | ||||||
| obj-y += qfw.o | obj-y += qfw.o | ||||||
| obj-$(CONFIG_QFW_PIO) += qfw_pio.o | obj-$(CONFIG_QFW_PIO) += qfw_pio.o | ||||||
|  | obj-$(CONFIG_SANDBOX) += qfw_sandbox.o | ||||||
| endif | endif | ||||||
| obj-$(CONFIG_ROCKCHIP_EFUSE) += rockchip-efuse.o | obj-$(CONFIG_ROCKCHIP_EFUSE) += rockchip-efuse.o | ||||||
| obj-$(CONFIG_ROCKCHIP_OTP) += rockchip-otp.o | obj-$(CONFIG_ROCKCHIP_OTP) += rockchip-otp.o | ||||||
|  |  | ||||||
|  | @ -0,0 +1,127 @@ | ||||||
|  | // SPDX-License-Identifier: GPL-2.0+
 | ||||||
|  | /*
 | ||||||
|  |  * Sandbox interface for QFW | ||||||
|  |  * | ||||||
|  |  * (C) Copyright 2015 Miao Yan <yanmiaobest@gmail.com> | ||||||
|  |  * (C) Copyright 2021 Asherah Connor <ashe@kivikakk.ee> | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #define LOG_CATEGORY UCLASS_QFW | ||||||
|  | 
 | ||||||
|  | #include <asm/types.h> | ||||||
|  | #include <asm/io.h> | ||||||
|  | #include <dm.h> | ||||||
|  | #include <dm/device.h> | ||||||
|  | #include <qfw.h> | ||||||
|  | 
 | ||||||
|  | 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, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | U_BOOT_DRIVER(qfw_sandbox) = { | ||||||
|  | 	.name	= "qfw_sandbox", | ||||||
|  | 	.id	= UCLASS_QFW, | ||||||
|  | 	.plat_auto	= sizeof(struct qfw_sandbox_plat), | ||||||
|  | 	.probe	= qfw_sandbox_probe, | ||||||
|  | 	.ops	= &qfw_sandbox_ops, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | U_BOOT_DRVINFO(qfw_sandbox) = { | ||||||
|  | 	.name = "qfw_sandbox", | ||||||
|  | }; | ||||||
|  | @ -98,5 +98,6 @@ endif | ||||||
| ifneq ($(CONFIG_EFI_PARTITION),) | ifneq ($(CONFIG_EFI_PARTITION),) | ||||||
| obj-$(CONFIG_FASTBOOT_FLASH_MMC) += fastboot.o | obj-$(CONFIG_FASTBOOT_FLASH_MMC) += fastboot.o | ||||||
| endif | endif | ||||||
|  | obj-$(CONFIG_QFW) += qfw.o | ||||||
| endif | endif | ||||||
| endif # !SPL
 | endif # !SPL
 | ||||||
|  |  | ||||||
|  | @ -0,0 +1,42 @@ | ||||||
|  | // SPDX-License-Identifier: GPL-2.0+
 | ||||||
|  | /*
 | ||||||
|  |  * Copyright 2021 Asherah Connor <ashe@kivikakk.ee> | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #include <common.h> | ||||||
|  | #include <qfw.h> | ||||||
|  | #include <dm.h> | ||||||
|  | #include <asm/test.h> | ||||||
|  | #include <dm/test.h> | ||||||
|  | #include <test/ut.h> | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * 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_PDATA); | ||||||
|  | 
 | ||||||
|  | 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_PDATA); | ||||||
|  | @ -0,0 +1,26 @@ | ||||||
|  | # SPDX-License-Identifier: GPL-2.0+ | ||||||
|  | # Copyright (c) 2021, Asherah Connor <ashe@kivikakk.ee> | ||||||
|  | 
 | ||||||
|  | # Test qfw command implementation | ||||||
|  | 
 | ||||||
|  | import pytest | ||||||
|  | 
 | ||||||
|  | @pytest.mark.buildconfigspec('cmd_qfw') | ||||||
|  | def test_qfw_cpus(u_boot_console): | ||||||
|  |     "Test QEMU firmware config reports the CPU count." | ||||||
|  | 
 | ||||||
|  |     output = u_boot_console.run_command('qfw cpus') | ||||||
|  |     # The actual number varies depending on the board under test, so only | ||||||
|  |     # assert a non-zero output. | ||||||
|  |     assert 'cpu(s) online' in output | ||||||
|  |     assert '0 cpu(s) online' not in output | ||||||
|  | 
 | ||||||
|  | @pytest.mark.buildconfigspec('cmd_qfw') | ||||||
|  | def test_qfw_list(u_boot_console): | ||||||
|  |     "Test QEMU firmware config lists devices." | ||||||
|  | 
 | ||||||
|  |     output = u_boot_console.run_command('qfw list') | ||||||
|  |     # Assert either: | ||||||
|  |     # 1) 'test-one', from the sandbox driver, or | ||||||
|  |     # 2) 'bootorder', found in every real QEMU implementation. | ||||||
|  |     assert ("bootorder" in output) or ("test-one" in output) | ||||||
		Loading…
	
		Reference in New Issue