@samitouri / QOSamiQemu / commits / 6ed05d5e65

hw/ufs: Add a generic SysBus frontend

Add TYPE_SYSBUS_UFS as a reusable frontend for the transport-independent UFS controller core. Use the system memory address space for DMA, expose the controller MMIO region and IRQ through SysBus, and provide the same properties and migration policy as the PCI frontend. Platform-specific controllers can derive from this type and keep only their hardware-specific behavior. Signed-off-by: Jeuk Kim <jeuk20.kim@samsung.com>

Jeuk Kim committed Aug 7, 2026 at 19:36 UTC 6ed05d5e65208a5ee23a02667d5df0dc6491c156
4 files changed +107
hw/ufs/Kconfig
+4
@@ -7,3 +7,7 @@ config UFS_PCI
7 default y if PCI_DEVICES
8 depends on PCI
9 select UFS
10 +
11 +config UFS_SYSBUS
12 + bool
13 + select UFS
hw/ufs/meson.build
+1
@@ -1,2 +1,3 @@
1 system_ss.add(when: 'CONFIG_UFS', if_true: files('ufs.c', 'lu.c'))
2 system_ss.add(when: 'CONFIG_UFS_PCI', if_true: files('ufs-pci.c'))
3 +system_ss.add(when: 'CONFIG_UFS_SYSBUS', if_true: files('ufs-sysbus.c'))
hw/ufs/ufs-sysbus.c new
+80
@@ -0,0 +1,80 @@
1 +/*
2 + * QEMU Universal Flash Storage (UFS) sysbus controller
3 + *
4 + * SPDX-License-Identifier: GPL-2.0-or-later
5 + */
6 +
7 +#include "qemu/osdep.h"
8 +#include "hw/core/qdev-properties.h"
9 +#include "ufs-sysbus.h"
10 +#include "migration/vmstate.h"
11 +#include "system/address-spaces.h"
12 +
13 +static void ufs_sysbus_realize(DeviceState *dev, Error **errp)
14 +{
15 + SysbusUfsState *s = SYSBUS_UFS(dev);
16 +
17 + if (!ufs_realize(&s->ufs, dev, &address_space_memory, errp)) {
18 + return;
19 + }
20 +
21 + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->ufs.iomem);
22 +}
23 +
24 +static void ufs_sysbus_unrealize(DeviceState *dev)
25 +{
26 + SysbusUfsState *s = SYSBUS_UFS(dev);
27 +
28 + ufs_unrealize(&s->ufs);
29 +}
30 +
31 +static void ufs_sysbus_init(Object *obj)
32 +{
33 + SysbusUfsState *s = SYSBUS_UFS(obj);
34 +
35 + sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->ufs.irq);
36 +}
37 +
38 +static const Property ufs_sysbus_props[] = {
39 + DEFINE_PROP_STRING("serial", SysbusUfsState, ufs.params.serial),
40 + DEFINE_PROP_UINT8("nutrs", SysbusUfsState, ufs.params.nutrs, 32),
41 + DEFINE_PROP_UINT8("nutmrs", SysbusUfsState, ufs.params.nutmrs, 8),
42 + DEFINE_PROP_BOOL("mcq", SysbusUfsState, ufs.params.mcq, false),
43 + DEFINE_PROP_UINT8("mcq-maxq", SysbusUfsState, ufs.params.mcq_maxq, 2),
44 + DEFINE_PROP_UINT32("wb-max-size", SysbusUfsState, ufs.params.wb_max_size,
45 + 0x400),
46 + DEFINE_PROP_UINT32("wb-min-size", SysbusUfsState, ufs.params.wb_min_size,
47 + 0x100),
48 +};
49 +
50 +static const VMStateDescription ufs_sysbus_vmstate = {
51 + .name = TYPE_SYSBUS_UFS,
52 + .unmigratable = 1,
53 +};
54 +
55 +static void ufs_sysbus_class_init(ObjectClass *oc, const void *data)
56 +{
57 + DeviceClass *dc = DEVICE_CLASS(oc);
58 +
59 + dc->realize = ufs_sysbus_realize;
60 + dc->unrealize = ufs_sysbus_unrealize;
61 + dc->vmsd = &ufs_sysbus_vmstate;
62 + dc->desc = "Universal Flash Storage";
63 + device_class_set_props(dc, ufs_sysbus_props);
64 + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
65 +}
66 +
67 +static const TypeInfo ufs_sysbus_info = {
68 + .name = TYPE_SYSBUS_UFS,
69 + .parent = TYPE_SYS_BUS_DEVICE,
70 + .instance_size = sizeof(SysbusUfsState),
71 + .instance_init = ufs_sysbus_init,
72 + .class_init = ufs_sysbus_class_init,
73 +};
74 +
75 +static void ufs_sysbus_register_types(void)
76 +{
77 + type_register_static(&ufs_sysbus_info);
78 +}
79 +
80 +type_init(ufs_sysbus_register_types)
hw/ufs/ufs-sysbus.h new
+22
@@ -0,0 +1,22 @@
1 +/*
2 + * QEMU Universal Flash Storage (UFS) sysbus controller
3 + *
4 + * SPDX-License-Identifier: GPL-2.0-or-later
5 + */
6 +
7 +#ifndef HW_UFS_UFS_SYSBUS_H
8 +#define HW_UFS_UFS_SYSBUS_H
9 +
10 +#include "hw/core/sysbus.h"
11 +#include "ufs.h"
12 +
13 +#define TYPE_SYSBUS_UFS "sysbus-ufs"
14 +OBJECT_DECLARE_SIMPLE_TYPE(SysbusUfsState, SYSBUS_UFS)
15 +
16 +struct SysbusUfsState {
17 + SysBusDevice parent_obj;
18 +
19 + UfsHc ufs;
20 +};
21 +
22 +#endif /* HW_UFS_UFS_SYSBUS_H */