1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Sandbox interface for QFW 4 * 5 * (C) Copyright 2015 Miao Yan <yanmiaobest@gmail.com> 6 * (C) Copyright 2021 Asherah Connor <ashe@kivikakk.ee> 7 */ 8 9#define LOG_CATEGORY UCLASS_QFW 10 11#include <asm/types.h> 12#include <asm/io.h> 13#include <dm.h> 14#include <dm/device.h> 15#include <qfw.h> 16 17struct qfw_sandbox_plat { 18 u8 file_dir_offset; 19}; 20 21static void qfw_sandbox_read_entry_io(struct udevice *dev, u16 entry, u32 size, 22 void *address) 23{ 24 debug("%s: entry 0x%x size %u address %p\n", __func__, entry, size, 25 address); 26 27 switch (entry) { 28 case FW_CFG_SIGNATURE: 29 if (size == 4) 30 *((u32 *)address) = cpu_to_be32(QEMU_FW_CFG_SIGNATURE); 31 break; 32 case FW_CFG_ID: 33 /* Advertise DMA support */ 34 if (size == 1) 35 *((u8 *)address) = FW_CFG_DMA_ENABLED; 36 break; 37 default: 38 debug("%s got unsupported entry 0x%x\n", __func__, entry); 39 /* 40 * Sandbox driver doesn't support other entries here, assume we use DMA 41 * to read them -- the uclass driver will exclusively use it when 42 * advertised. 43 */ 44 } 45} 46 47static void qfw_sandbox_read_entry_dma(struct udevice *dev, struct qfw_dma *dma) 48{ 49 u16 entry; 50 u32 control = be32_to_cpu(dma->control); 51 void *address = (void *)(uintptr_t)be64_to_cpu(dma->address); 52 u32 length = be32_to_cpu(dma->length); 53 struct qfw_sandbox_plat *plat = dev_get_plat(dev); 54 struct fw_cfg_file *file; 55 56 debug("%s\n", __func__); 57 58 if (!(control & FW_CFG_DMA_READ)) 59 return; 60 61 if (control & FW_CFG_DMA_SELECT) { 62 /* Start new read. */ 63 entry = control >> 16; 64 65 /* Arbitrary values to be used by tests. */ 66 switch (entry) { 67 case FW_CFG_NB_CPUS: 68 if (length == 2) 69 *((u16 *)address) = cpu_to_le16(5); 70 break; 71 case FW_CFG_FILE_DIR: 72 if (length == 4) { 73 *((u32 *)address) = cpu_to_be32(2); 74 plat->file_dir_offset = 1; 75 } 76 break; 77 default: 78 debug("%s got unsupported entry 0x%x\n", __func__, 79 entry); 80 } 81 } else if (plat->file_dir_offset && length == 64) { 82 file = address; 83 switch (plat->file_dir_offset) { 84 case 1: 85 file->size = cpu_to_be32(8); 86 file->select = cpu_to_be16(FW_CFG_FILE_FIRST); 87 strcpy(file->name, "test-one"); 88 plat->file_dir_offset++; 89 break; 90 case 2: 91 file->size = cpu_to_be32(8); 92 file->select = cpu_to_be16(FW_CFG_FILE_FIRST + 1); 93 strcpy(file->name, "test-two"); 94 plat->file_dir_offset++; 95 break; 96 } 97 } 98 99 /* 100 * Signal that we are finished. No-one checks this in sandbox -- 101 * normally the platform-specific driver looks for it -- but let's 102 * replicate the behaviour in case someone relies on it later. 103 */ 104 dma->control = 0; 105} 106 107static int qfw_sandbox_probe(struct udevice *dev) 108{ 109 return qfw_register(dev); 110} 111 112static struct dm_qfw_ops qfw_sandbox_ops = { 113 .read_entry_io = qfw_sandbox_read_entry_io, 114 .read_entry_dma = qfw_sandbox_read_entry_dma, 115}; 116 117U_BOOT_DRIVER(qfw_sandbox) = { 118 .name = "qfw_sandbox", 119 .id = UCLASS_QFW, 120 .plat_auto = sizeof(struct qfw_sandbox_plat), 121 .probe = qfw_sandbox_probe, 122 .ops = &qfw_sandbox_ops, 123}; 124 125U_BOOT_DRVINFO(qfw_sandbox) = { 126 .name = "qfw_sandbox", 127}; 128