Merge patch series "Add virtio-mmio support to m68k virt machine"

Daniel Palmer <daniel@thingy.jp> says:

Lets start making the m68k virt machine support useful.

First we need to fix some m68k endian issues.

Then allow virtio mmio driver instances to be created with
platform data and fix a minor endian issue.

Finally, add the code for the board to create the instances.

Link: https://lore.kernel.org/r/20260516074016.885146-1-daniel@thingy.jp
This commit is contained in:
Tom Rini
2026-05-22 16:46:42 -06:00
11 changed files with 121 additions and 42 deletions

View File

@@ -196,12 +196,14 @@ config TARGET_STMARK2
select M54418
config TARGET_QEMU_M68K
bool "Support QEMU m68k virt"
select M68040
imply CMD_DM
help
This target supports the QEMU m68k virtual machine (-M virt).
It simulates a Motorola 68040 CPU with Goldfish peripherals.
bool "Support QEMU m68k virt"
select M68040
select BOARD_EARLY_INIT_R
select VIRTIO_MMIO
imply CMD_DM
help
This target supports the QEMU m68k virtual machine (-M virt).
It simulates a Motorola 68040 CPU with Goldfish peripherals.
endchoice

View File

@@ -23,18 +23,27 @@
#define __raw_writew(w,addr) ((*(volatile u16 *) (addr)) = (w))
#define __raw_writel(l,addr) ((*(volatile u32 *) (addr)) = (l))
#define readb(addr) in_8((volatile u8 *)(addr))
#define writeb(b,addr) out_8((volatile u8 *)(addr), (b))
#if !defined(__BIG_ENDIAN)
#define readw(addr) (*(volatile u16 *) (addr))
#define readl(addr) (*(volatile u32 *) (addr))
#define writew(b,addr) ((*(volatile u16 *) (addr)) = (b))
#define writel(b,addr) ((*(volatile u32 *) (addr)) = (b))
#define readb(addr) in_8((volatile u8 *)(addr))
#define writeb(b, addr) out_8((volatile u8 *)(addr), (b))
#ifdef CONFIG_M680x0
/*
* For classic m68k these work the same way as Linux:
* Read a little endian value, swap to the CPU endian.
*/
#define readw(addr) in_le16((volatile u16 *)(addr))
#define readl(addr) in_le32((volatile u32 *)(addr))
#define writew(b, addr) out_le16((volatile u16 *)(addr), (b))
#define writel(b, addr) out_le32((volatile u32 *)(addr), (b))
#else
#define readw(addr) in_be16((volatile u16 *)(addr))
#define readl(addr) in_be32((volatile u32 *)(addr))
#define writew(b,addr) out_be16((volatile u16 *)(addr),(b))
#define writel(b,addr) out_be32((volatile u32 *)(addr),(b))
/*
* For coldfire these read a big endian value and use it
* as-is. This means that for little endian devices on the
* bus like PCI device these won't work as expected currently.
*/
#define readw(addr) in_be16((volatile u16 *)(addr))
#define readl(addr) in_be32((volatile u32 *)(addr))
#define writew(b, addr) out_be16((volatile u16 *)(addr), (b))
#define writel(b, addr) out_be32((volatile u32 *)(addr), (b))
#endif
/*

View File

@@ -14,9 +14,14 @@
#include <asm/bootinfo.h>
#include <asm/global_data.h>
#include <asm/io.h>
#include <dm.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
#include <dm/platdata.h>
#include <dm/root.h>
#include <linux/errno.h>
#include <linux/sizes.h>
#include <virtio_mmio.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -25,6 +30,38 @@ static struct goldfish_rtc_plat rtc_plat;
static struct goldfish_timer_plat timer_plat;
static struct qemu_virt_ctrl_plat reset_plat;
#define VIRTIO_MMIO_NUM 128
#define VIRTIO_MMIO_SZ 0x200
static struct virtio_mmio_plat virtio_mmio_plat[VIRTIO_MMIO_NUM];
static char virtio_mmio_names[VIRTIO_MMIO_NUM][11];
static phys_addr_t virtio_mmio_base;
static int create_virtio_mmios(void)
{
struct driver *drv;
int i, ret;
if (!virtio_mmio_base)
return -ENODEV;
drv = lists_driver_lookup_name("virtio-mmio");
if (!drv)
return -ENOENT;
for (i = 0; i < VIRTIO_MMIO_NUM; i++) {
virtio_mmio_plat[i].base = virtio_mmio_base + (VIRTIO_MMIO_SZ * i);
sprintf(virtio_mmio_names[i], "virtio-%d", i);
ret = device_bind(dm_root(), drv, virtio_mmio_names[i],
&virtio_mmio_plat[i], ofnode_null(), NULL);
if (ret)
return ret;
}
return 0;
}
/*
* Theoretical limit derivation:
* Max Bootinfo Size (Standard Page) = 4096 bytes
@@ -65,6 +102,9 @@ static void parse_bootinfo(void)
case BI_VIRT_CTRL_BASE:
reset_plat.reg = base;
break;
case BI_VIRT_VIRTIO_BASE:
virtio_mmio_base = base;
break;
case BI_MEMCHUNK:
gd->ram_size = record->data[1];
break;
@@ -80,6 +120,11 @@ int board_early_init_f(void)
return 0;
}
int board_early_init_r(void)
{
return create_virtio_mmios();
}
int checkboard(void)
{
puts("Board: QEMU m68k virt\n");

View File

@@ -1871,8 +1871,8 @@ config CMD_PVBLOCK
config CMD_VIRTIO
bool "virtio"
depends on VIRTIO
default y if VIRTIO
depends on VIRTIO_BLK
default y if VIRTIO_BLK
help
VirtIO block device support

View File

@@ -40,8 +40,8 @@ static int goldfish_rtc_get(struct udevice *dev, struct rtc_time *time)
u64 time_low;
u64 now;
time_low = ioread32(base + GOLDFISH_TIME_LOW);
time_high = ioread32(base + GOLDFISH_TIME_HIGH);
time_low = __raw_readl(base + GOLDFISH_TIME_LOW);
time_high = __raw_readl(base + GOLDFISH_TIME_HIGH);
now = (time_high << 32) | time_low;
do_div(now, 1000000000U);
@@ -62,8 +62,8 @@ static int goldfish_rtc_set(struct udevice *dev, const struct rtc_time *time)
return -EINVAL;
now = rtc_mktime(time) * 1000000000ULL;
iowrite32(now >> 32, base + GOLDFISH_TIME_HIGH);
iowrite32(now, base + GOLDFISH_TIME_LOW);
__raw_writel(now >> 32, base + GOLDFISH_TIME_HIGH);
__raw_writel(now, base + GOLDFISH_TIME_LOW);
if (time->tm_isdst > 0)
priv->isdst = 1;

View File

@@ -8,6 +8,7 @@
#include <dm.h>
#include <qemu_virt_ctrl.h>
#include <sysreset.h>
#include <mapmem.h>
#include <asm/io.h>
#include <linux/err.h>
@@ -24,6 +25,7 @@
static int qemu_virt_ctrl_request(struct udevice *dev, enum sysreset_t type)
{
struct qemu_virt_ctrl_plat *plat = dev_get_plat(dev);
void __iomem *reg = map_sysmem(plat->reg + VIRT_CTRL_REG_CMD, 0x4);
u32 val;
switch (type) {
@@ -38,7 +40,7 @@ static int qemu_virt_ctrl_request(struct udevice *dev, enum sysreset_t type)
return -EPROTONOSUPPORT;
}
writel(val, plat->reg + VIRT_CTRL_REG_CMD);
__raw_writel(val, reg);
return -EINPROGRESS;
}

View File

@@ -31,8 +31,8 @@ static u64 goldfish_timer_get_count(struct udevice *dev)
* We must read LOW before HIGH to latch the high 32-bit value
* and ensure a consistent 64-bit timestamp.
*/
low = readl(priv->base + TIMER_TIME_LOW);
high = readl(priv->base + TIMER_TIME_HIGH);
low = __raw_readl(priv->base + TIMER_TIME_LOW);
high = __raw_readl(priv->base + TIMER_TIME_HIGH);
time = ((u64)high << 32) | low;

View File

@@ -231,14 +231,11 @@ static int virtio_blk_bind(struct udevice *dev)
return devnum;
desc->devnum = devnum;
desc->part_type = PART_TYPE_UNKNOWN;
/*
* virtio mmio transport supplies string identification for us,
* while pci trnasport uses a 2-byte subvendor value.
*/
if (uc_priv->vendor >> 16)
sprintf(desc->vendor, "%s", (char *)&uc_priv->vendor);
if (uc_priv->vendor == VIRTIO_VENDOR_QEMU)
strcpy(desc->vendor, "QEMU");
else
sprintf(desc->vendor, "%04x", uc_priv->vendor);
sprintf(desc->vendor, "%08x", uc_priv->vendor);
desc->bdev = dev;
/* Indicate what driver features we support */

View File

@@ -12,6 +12,7 @@
#include <virtio_types.h>
#include <virtio.h>
#include <virtio_ring.h>
#include <virtio_mmio.h>
#include <linux/bug.h>
#include <linux/compat.h>
#include <linux/err.h>
@@ -335,21 +336,28 @@ static int virtio_mmio_notify(struct udevice *udev, struct virtqueue *vq)
static int virtio_mmio_of_to_plat(struct udevice *udev)
{
struct virtio_mmio_priv *priv = dev_get_priv(udev);
struct virtio_mmio_plat *plat = dev_get_plat(udev);
fdt_addr_t addr;
priv->base = (void __iomem *)(ulong)dev_read_addr(udev);
if (priv->base == (void __iomem *)FDT_ADDR_T_NONE)
addr = dev_read_addr(udev);
if (addr == FDT_ADDR_T_NONE)
return -EINVAL;
plat->base = addr;
return 0;
}
static int virtio_mmio_probe(struct udevice *udev)
{
struct virtio_mmio_plat *plat = dev_get_plat(udev);
struct virtio_mmio_priv *priv = dev_get_priv(udev);
struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(udev);
u32 magic;
priv->base = (void __iomem *)(uintptr_t)plat->base;
/* Check magic value */
magic = readl(priv->base + VIRTIO_MMIO_MAGIC_VALUE);
if (magic != ('v' | 'i' << 8 | 'r' << 16 | 't' << 24)) {
@@ -405,11 +413,12 @@ static const struct udevice_id virtio_mmio_ids[] = {
};
U_BOOT_DRIVER(virtio_mmio) = {
.name = "virtio-mmio",
.id = UCLASS_VIRTIO,
.of_match = virtio_mmio_ids,
.ops = &virtio_mmio_ops,
.probe = virtio_mmio_probe,
.name = "virtio-mmio",
.id = UCLASS_VIRTIO,
.of_match = virtio_mmio_ids,
.ops = &virtio_mmio_ops,
.probe = virtio_mmio_probe,
.of_to_plat = virtio_mmio_of_to_plat,
.priv_auto = sizeof(struct virtio_mmio_priv),
.priv_auto = sizeof(struct virtio_mmio_priv),
.plat_auto = sizeof(struct virtio_mmio_plat),
};

View File

@@ -25,6 +25,9 @@
#include <linux/bitops.h>
#include <linux/bug.h>
#include <linux/typecheck.h>
#define VIRTIO_VENDOR_QEMU 0x554d4551
#define VIRTIO_ID_NET 1 /* virtio net */
#define VIRTIO_ID_BLOCK 2 /* virtio block */
#define VIRTIO_ID_RNG 4 /* virtio rng */

12
include/virtio_mmio.h Normal file
View File

@@ -0,0 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0+ */
#ifndef __VIRTIO_MMIO_H__
#define __VIRTIO_MMIO_H__
#include <linux/types.h>
struct virtio_mmio_plat {
phys_addr_t base;
};
#endif /* __VIRTIO_MMIO_H__ */