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 "sysemu/blockdev.h"
33#include "sysemu/block-backend.h"
34
35#include "hw/fdt_generic_util.h"
36
37#include "hw/sd/sd.h"
38#include "hw/sd/sdhci.h"
39#include "qapi/error.h"
40
41#ifndef ZYNQMP_SDHCI_ERR_DEBUG
42#define ZYNQMP_SDHCI_ERR_DEBUG 0
43#endif
44
45#define TYPE_ZYNQMP_SDHCI "xilinx.zynqmp-sdhci"
46
47#define ZYNQMP_SDHCI(obj) \
48 OBJECT_CHECK(ZynqMPSDHCIState, (obj), TYPE_ZYNQMP_SDHCI)
49
50#define ZYNQMP_SDHCI_PARENT_CLASS \
51 object_class_get_parent(object_class_by_name(TYPE_ZYNQMP_SDHCI))
52
53typedef struct ZynqMPSDHCIState {
54
55 SDHCIState parent_obj;
56
57
58 SDState *card;
59 uint8_t drive_index;
60 bool is_mmc;
61} ZynqMPSDHCIState;
62
63static void zynqmp_sdhci_slottype_handler(void *opaque, int n, int level)
64{
65 ZynqMPSDHCIState *s = ZYNQMP_SDHCI(opaque);
66
67 assert(n == 0);
68
69 if (!s->card) {
70
71 return;
72 }
73
74 if (level != s->is_mmc) {
75 qemu_log_mask(LOG_GUEST_ERROR, "WARNING: Inserted %s Card but"
76 " Slot configured as %s\n",
77 s->is_mmc ? "MMC" : "SD",
78 level ? "MMC" : "SD");
79 }
80}
81
82static void zynqmp_sdhci_reset(DeviceState *dev)
83{
84 ZynqMPSDHCIState *s = ZYNQMP_SDHCI(dev);
85 SDHCIState *ss = SYSBUS_SDHCI(dev);
86 DeviceClass *dc_parent = DEVICE_CLASS(ZYNQMP_SDHCI_PARENT_CLASS);
87
88 dc_parent->reset(dev);
89
90 sd_set_cb(s->card, ss->ro_cb, ss->eject_cb);
91}
92
93static void zynqmp_sdhci_realize(DeviceState *dev, Error **errp)
94{
95 DeviceClass *dc_parent = DEVICE_CLASS(ZYNQMP_SDHCI_PARENT_CLASS);
96 ZynqMPSDHCIState *s = ZYNQMP_SDHCI(dev);
97 DriveInfo *di_sd, *di_mmc;
98 DeviceState *carddev_sd;
99 static int index_offset = 0;
100
101
102
103
104
105
106
107 if (!s->drive_index) {
108 s->drive_index += index_offset;
109 index_offset++;
110 }
111
112 qdev_prop_set_uint32(dev, "capareg",
113 (uint32_t) SDHC_CAPAB_REG_DEFAULT | (1 << 28));
114 carddev_sd = qdev_create(qdev_get_child_bus(DEVICE(dev), "sd-bus"),
115 TYPE_SD_CARD);
116 object_property_set_bool(OBJECT(carddev_sd), false, "spi", &error_fatal);
117
118
119
120
121
122
123
124
125 di_sd = drive_get_by_index(IF_SD , s->drive_index);
126 di_mmc = drive_get_by_index(IF_SD, (s->drive_index + 2));
127
128 if (di_sd && di_mmc) {
129 if (!di_sd->is_default && !di_mmc->is_default) {
130 error_setg(&error_fatal, "Cannot attach both an MMC"
131 " and an SD card into the same slot");
132 }
133 }
134
135 if (di_sd) {
136 qdev_prop_set_drive(carddev_sd, "drive", blk_by_legacy_dinfo(di_sd),
137 &error_fatal);
138 object_property_set_bool(OBJECT(carddev_sd), false, "mmc",
139 &error_fatal);
140 }
141
142 if (di_mmc) {
143 qdev_prop_set_drive(carddev_sd, "drive", blk_by_legacy_dinfo(di_mmc),
144 &error_fatal);
145 object_property_set_bool(OBJECT(carddev_sd), true, "mmc", &error_fatal);
146 s->is_mmc = true;
147 }
148
149 object_property_set_bool(OBJECT(carddev_sd), true, "realized",
150 &error_fatal);
151
152 qdev_init_gpio_in_named(dev, zynqmp_sdhci_slottype_handler, "SLOTTYPE", 1);
153 s->card = SD_CARD(carddev_sd);
154
155 dc_parent->realize(dev, errp);
156}
157
158static Property zynqmp_sdhci_properties[] = {
159 DEFINE_PROP_UINT8("drive-index", ZynqMPSDHCIState, drive_index, 0),
160 DEFINE_PROP_END_OF_LIST(),
161};
162
163static void zynqmp_sdhci_class_init(ObjectClass *klass, void *data)
164{
165 DeviceClass *dc = DEVICE_CLASS(klass);
166
167 dc->realize = zynqmp_sdhci_realize;
168 dc->props = zynqmp_sdhci_properties;
169 dc->reset = zynqmp_sdhci_reset;
170}
171
172static const TypeInfo zynqmp_sdhci_info = {
173 .name = TYPE_ZYNQMP_SDHCI,
174 .parent = TYPE_SYSBUS_SDHCI,
175 .class_init = zynqmp_sdhci_class_init,
176 .instance_size = sizeof(ZynqMPSDHCIState),
177};
178
179static void zynqmp_sdhci_register_types(void)
180{
181 type_register_static(&zynqmp_sdhci_info);
182}
183
184type_init(zynqmp_sdhci_register_types)
185