| // 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 *)(uintptr_t)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", | |
| }; |