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 SDState *sd_card;
60 SDState *mmc_card;
61 uint8_t drive_index;
62} ZynqMPSDHCIState;
63
64static void zynqmp_sdhci_slottype_handler(void *opaque, int n, int level)
65{
66 SDHCIState *ss = SYSBUS_SDHCI(opaque);
67 ZynqMPSDHCIState *s = ZYNQMP_SDHCI(opaque);
68
69 assert(n == 0);
70
71 ss->capareg = deposit64(ss->capareg, 30, 2, level);
72 s->card = extract64(ss->capareg, 30, 2) ? s->mmc_card : s->sd_card;
73 sd_set_cb(s->card, ss->ro_cb, ss->eject_cb);
74}
75
76static void zynqmp_sdhci_reset(DeviceState *dev)
77{
78 ZynqMPSDHCIState *s = ZYNQMP_SDHCI(dev);
79 SDHCIState *ss = SYSBUS_SDHCI(dev);
80 DeviceClass *dc_parent = DEVICE_CLASS(ZYNQMP_SDHCI_PARENT_CLASS);
81
82 dc_parent->reset(dev);
83
84 s->card = s->sd_card;
85 sd_set_cb(s->card, ss->ro_cb, ss->eject_cb);
86}
87
88static void zynqmp_sdhci_realize(DeviceState *dev, Error **errp)
89{
90 DeviceClass *dc_parent = DEVICE_CLASS(ZYNQMP_SDHCI_PARENT_CLASS);
91 ZynqMPSDHCIState *s = ZYNQMP_SDHCI(dev);
92 DriveInfo *di_sd, *di_mmc;
93 BlockBackend *blk_sd;
94 DeviceState *carddev_sd;
95 static int index_offset = 0;
96
97
98
99
100
101
102
103 if (!s->drive_index) {
104 s->drive_index += index_offset;
105 index_offset++;
106 }
107
108 di_sd = drive_get_by_index(IF_SD , s->drive_index);
109 blk_sd = di_sd ? blk_by_legacy_dinfo(di_sd) : NULL;
110
111 carddev_sd = qdev_create(qdev_get_child_bus(DEVICE(dev), "sd-bus"), TYPE_SD_CARD);
112
113 qdev_prop_set_drive(carddev_sd, "drive", blk_sd, &error_fatal);
114 object_property_set_bool(OBJECT(carddev_sd), false, "spi", &error_fatal);
115 object_property_set_bool(OBJECT(carddev_sd), false, "mmc", &error_fatal);
116 object_property_set_bool(OBJECT(carddev_sd), true, "realized", &error_fatal);
117
118 s->sd_card = SD_CARD(carddev_sd);
119
120 di_mmc = drive_get_by_index(IF_SD, (s->drive_index + 2));
121 s->mmc_card = mmc_init(di_mmc ? blk_by_legacy_dinfo(di_mmc) : NULL);
122
123 dc_parent->realize(dev, errp);
124
125 qdev_init_gpio_in_named(dev, zynqmp_sdhci_slottype_handler, "SLOTTYPE", 1);
126}
127
128static Property zynqmp_sdhci_properties[] = {
129 DEFINE_PROP_UINT8("drive-index", ZynqMPSDHCIState, drive_index, 0),
130 DEFINE_PROP_END_OF_LIST(),
131};
132
133static void zynqmp_sdhci_class_init(ObjectClass *klass, void *data)
134{
135 DeviceClass *dc = DEVICE_CLASS(klass);
136
137 dc->realize = zynqmp_sdhci_realize;
138 dc->props = zynqmp_sdhci_properties;
139 dc->reset = zynqmp_sdhci_reset;
140}
141
142static const TypeInfo zynqmp_sdhci_info = {
143 .name = TYPE_ZYNQMP_SDHCI,
144 .parent = TYPE_SYSBUS_SDHCI,
145 .class_init = zynqmp_sdhci_class_init,
146 .instance_size = sizeof(ZynqMPSDHCIState),
147};
148
149static void zynqmp_sdhci_register_types(void)
150{
151 type_register_static(&zynqmp_sdhci_info);
152}
153
154type_init(zynqmp_sdhci_register_types)
155