1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24#include "qemu/osdep.h"
25#include "hw/sysbus.h"
26#include "qemu/log.h"
27#include "qapi/error.h"
28#include "hw/qdev-properties.h"
29
30#define TYPE_GPIO_MR_MUX "gpio-mr-mux"
31
32#define GPIO_MR_MUX(obj) \
33 OBJECT_CHECK(GpioMrMux, (obj), TYPE_GPIO_MR_MUX)
34
35#ifndef MR_MUX_DEBUG
36#define MR_MUX_DEBUG 0
37#endif
38
39#define MAX_NR_GPIOS (4)
40#define MAX_REGIONS (1 << MAX_NR_GPIOS)
41
42typedef struct GpioMrMux {
43 SysBusDevice parent_obj;
44 MemoryRegion iomem;
45
46 MemoryRegion *mr[MAX_REGIONS];
47 MemoryRegion mr_alias[MAX_REGIONS];
48
49 struct {
50 uint64_t mr_size;
51 } cfg;
52
53 uint32_t state;
54} GpioMrMux;
55
56static void update_regions(GpioMrMux *s)
57{
58 int i;
59
60 for (i = 0; i < MAX_REGIONS; i++) {
61 bool enabled = s->state == i;
62 memory_region_set_enabled(&s->mr_alias[i], enabled);
63 }
64}
65
66static void input_handler(void *opaque, int nr, int level)
67{
68 GpioMrMux *s = GPIO_MR_MUX(opaque);
69
70 s->state = deposit32(s->state, nr, 1, level);
71 update_regions(s);
72}
73
74static void gpio_mr_mux_realize(DeviceState *dev, Error **errp)
75{
76 GpioMrMux *s = GPIO_MR_MUX(dev);
77 SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
78 int i;
79
80 memory_region_init(&s->iomem, OBJECT(dev),
81 TYPE_GPIO_MR_MUX, s->cfg.mr_size);
82 sysbus_init_mmio(sbd, &s->iomem);
83
84 for (i = 0; i < MAX_REGIONS; i++) {
85 if (s->mr[i]) {
86 char *name = g_strdup_printf("mr-alias%d", i);
87
88
89 memory_region_init_alias(&s->mr_alias[i], OBJECT(s),
90 name, s->mr[i], 0, memory_region_size(s->mr[i]));
91 memory_region_add_subregion_overlap(&s->iomem, 0,
92 &s->mr_alias[i], 0);
93 g_free(name);
94 }
95 }
96}
97
98static void gpio_mr_mux_init(Object *obj)
99{
100 GpioMrMux *s = GPIO_MR_MUX(obj);
101 int i;
102
103 qdev_init_gpio_in(DEVICE(obj), input_handler, MAX_NR_GPIOS);
104
105 for (i = 0; i < MAX_REGIONS; i++) {
106 char *name = g_strdup_printf("mr%d", i);
107
108 object_property_add_link(obj, name, TYPE_MEMORY_REGION,
109 (Object **)&s->mr[i],
110 qdev_prop_allow_set_link_before_realize,
111 OBJ_PROP_LINK_STRONG);
112 g_free(name);
113 }
114}
115
116static Property gpio_mr_mux_properties[] = {
117 DEFINE_PROP_UINT64("mr-size", GpioMrMux, cfg.mr_size, UINT64_MAX),
118 DEFINE_PROP_END_OF_LIST(),
119};
120
121static void gpio_mr_mux_class_init(ObjectClass *klass, void *data)
122{
123 DeviceClass *dc = DEVICE_CLASS(klass);
124
125 dc->realize = gpio_mr_mux_realize;
126 device_class_set_props(dc, gpio_mr_mux_properties);
127}
128
129static const TypeInfo gpio_mr_mux_info = {
130 .name = TYPE_GPIO_MR_MUX,
131 .parent = TYPE_SYS_BUS_DEVICE,
132 .instance_size = sizeof(GpioMrMux),
133 .class_init = gpio_mr_mux_class_init,
134 .instance_init = gpio_mr_mux_init,
135};
136
137static void gpio_mr_mux_register_types(void)
138{
139 type_register_static(&gpio_mr_mux_info);
140}
141
142type_init(gpio_mr_mux_register_types)
143