mirror of
https://source.denx.de/u-boot/u-boot.git
synced 2026-06-02 09:46:37 +03:00
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:
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
/*
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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),
|
||||
};
|
||||
|
||||
@@ -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
12
include/virtio_mmio.h
Normal 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__ */
|
||||
Reference in New Issue
Block a user