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#include "qemu/osdep.h"
27#include "hw/sysbus.h"
28#include "qemu/log.h"
29
30#include "qemu/bitops.h"
31#include "qapi/qmp/qerror.h"
32#include "hw/register.h"
33#include "hw/fdt_generic_util.h"
34
35#ifndef ZYNQMP_IOU_SLCR_ERR_DEBUG
36#define ZYNQMP_IOU_SLCR_ERR_DEBUG 0
37#endif
38
39#define TYPE_ZYNQMP_IOU_SLCR "xilinx.zynqmp-iou-slcr"
40
41#define ZYNQMP_IOU_SLCR(obj) \
42 OBJECT_CHECK(ZynqMPIOUSLCR, (obj), TYPE_ZYNQMP_IOU_SLCR)
43
44REG32(MIO, 0x0)
45 #define R_MIO_RSVD 0xffffff01
46
47REG32(SD_SLOTTYPE, 0x310)
48 #define R_SD_SLOTTYPE_RSVD 0xffffff9c
49
50#define R_MAX ((R_SD_SLOTTYPE) + 1)
51
52typedef struct ZynqMPIOUSLCR ZynqMPIOUSLCR;
53
54struct ZynqMPIOUSLCR {
55 SysBusDevice busdev;
56 MemoryRegion iomem;
57
58 uint32_t regs[R_MAX];
59 RegisterInfo regs_info[R_MAX];
60};
61
62static const RegisterAccessInfo zynqmp_iou_slcr_regs_info[] = {
63#define M(x) \
64 { .name = "MIO" #x, .decode.addr = A_MIO + 4 * x, \
65 .rsvd = R_MIO_RSVD, \
66 },
67 M( 0) M( 1) M( 2) M( 3) M( 4) M( 5) M( 6) M( 7) M( 8) M( 9)
68 M(10) M(11) M(12) M(13) M(14) M(15) M(16) M(17) M(18) M(19)
69 M(20) M(21) M(22) M(23) M(24) M(25) M(26) M(27) M(28) M(29)
70 M(30) M(31) M(32) M(33) M(34) M(35) M(36) M(37) M(38) M(39)
71 M(40) M(41) M(42) M(43) M(44) M(45) M(46) M(47) M(48) M(49)
72 M(50) M(51) M(52) M(53) M(54) M(55) M(56) M(57) M(58) M(59)
73 M(60) M(61) M(62) M(63) M(64) M(65) M(66) M(67) M(78) M(69)
74 M(70) M(71) M(72) M(73) M(74) M(75) M(76) M(77)
75#undef M
76 { .name = "SD Slot TYPE", .decode.addr = A_SD_SLOTTYPE,
77 .rsvd = R_SD_SLOTTYPE_RSVD,
78 .gpios = (RegisterGPIOMapping []) {
79 { .name = "SD0_SLOTTYPE", .bit_pos = 0, .width = 2 },
80 { .name = "SD1_SLOTTYPE", .bit_pos = 15, .width = 2 },
81 {},
82 }
83 }
84};
85
86static void zynqmp_iou_slcr_reset(DeviceState *dev)
87{
88 ZynqMPIOUSLCR *s = ZYNQMP_IOU_SLCR(dev);
89 int i;
90
91 for (i = 0; i < R_MAX; ++i) {
92 register_reset(&s->regs_info[i]);
93 }
94}
95
96static const MemoryRegionOps zynqmp_iou_slcr_ops = {
97 .read = register_read_memory_le,
98 .write = register_write_memory_le,
99 .endianness = DEVICE_LITTLE_ENDIAN,
100 .valid = {
101 .min_access_size = 4,
102 .max_access_size = 4,
103 }
104};
105
106static void zynqmp_iou_slcr_realize(DeviceState *dev, Error **errp)
107{
108 ZynqMPIOUSLCR *s = ZYNQMP_IOU_SLCR(dev);
109 const char *prefix = object_get_canonical_path(OBJECT(dev));
110 int i;
111
112 for (i = 0; i < ARRAY_SIZE(zynqmp_iou_slcr_regs_info); ++i) {
113 RegisterInfo *r = &s->regs_info[i];
114
115 *r = (RegisterInfo) {
116 .data = (uint8_t *)&s->regs[
117 zynqmp_iou_slcr_regs_info[i].decode.addr/4],
118 .data_size = sizeof(uint32_t),
119 .access = &zynqmp_iou_slcr_regs_info[i],
120 .debug = ZYNQMP_IOU_SLCR_ERR_DEBUG,
121 .prefix = prefix,
122 .opaque = s,
123 };
124 register_init(r);
125 qdev_pass_all_gpios(DEVICE(r), dev);
126
127 memory_region_init_io(&r->mem, OBJECT(dev), &zynqmp_iou_slcr_ops, r,
128 r->access->name, 4);
129 memory_region_add_subregion(&s->iomem, r->access->decode.addr, &r->mem);
130 }
131 return;
132}
133
134static void zynqmp_iou_slcr_init(Object *obj)
135{
136 ZynqMPIOUSLCR *s = ZYNQMP_IOU_SLCR(obj);
137
138 memory_region_init(&s->iomem, obj, "MMIO", R_MAX * 4);
139 sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);
140}
141
142static const VMStateDescription vmstate_zynqmp_iou_slcr = {
143 .name = "zynqmp_iou_slcr",
144 .version_id = 1,
145 .minimum_version_id = 1,
146 .minimum_version_id_old = 1,
147 .fields = (VMStateField[]) {
148 VMSTATE_UINT32_ARRAY(regs, ZynqMPIOUSLCR, R_MAX),
149 VMSTATE_END_OF_LIST(),
150 }
151};
152
153static const FDTGenericGPIOSet zynqmp_iou_slcr_controller_gpios [] = {
154 {
155
156 .names = &fdt_generic_gpio_name_set_gpio,
157 .gpios = (FDTGenericGPIOConnection []) {
158 { .name = "SD0_SLOTTYPE", .fdt_index = 0 },
159 { .name = "SD1_SLOTTYPE", .fdt_index = 1 },
160 { },
161 },
162 },
163 { },
164};
165
166static void zynqmp_iou_slcr_class_init(ObjectClass *klass, void *data)
167{
168 DeviceClass *dc = DEVICE_CLASS(klass);
169 FDTGenericGPIOClass *fggc = FDT_GENERIC_GPIO_CLASS(klass);
170
171 dc->reset = zynqmp_iou_slcr_reset;
172 dc->realize = zynqmp_iou_slcr_realize;
173 dc->vmsd = &vmstate_zynqmp_iou_slcr;
174
175 fggc->controller_gpios = zynqmp_iou_slcr_controller_gpios;
176}
177
178static const TypeInfo zynqmp_iou_slcr_info = {
179 .name = TYPE_ZYNQMP_IOU_SLCR,
180 .parent = TYPE_SYS_BUS_DEVICE,
181 .instance_size = sizeof(ZynqMPIOUSLCR),
182 .class_init = zynqmp_iou_slcr_class_init,
183 .instance_init = zynqmp_iou_slcr_init,
184 .interfaces = (InterfaceInfo[]) {
185 { TYPE_FDT_GENERIC_GPIO },
186 { },
187 }
188};
189
190static void zynqmp_iou_slcr_register_types(void)
191{
192 type_register_static(&zynqmp_iou_slcr_info);
193}
194
195type_init(zynqmp_iou_slcr_register_types)
196