qfw_sandbox.c 3.0 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 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",
};