xref: /openbmc/qemu/hw/sd/core.c (revision 5ade579b)
1 /*
2  * SD card bus interface code.
3  *
4  * Copyright (c) 2015 Linaro Limited
5  *
6  * Author:
7  *  Peter Maydell <peter.maydell@linaro.org>
8  *
9  * This program is free software; you can redistribute it and/or modify it
10  * under the terms and conditions of the GNU General Public License,
11  * version 2 or later, as published by the Free Software Foundation.
12  *
13  * This program is distributed in the hope it will be useful, but WITHOUT
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
16  * more details.
17  *
18  * You should have received a copy of the GNU General Public License along with
19  * this program.  If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include "qemu/osdep.h"
23 #include "hw/qdev-core.h"
24 #include "hw/sd/sd.h"
25 #include "qemu/module.h"
26 #include "qapi/error.h"
27 #include "trace.h"
28 
29 static inline const char *sdbus_name(SDBus *sdbus)
30 {
31     return sdbus->qbus.name;
32 }
33 
34 static SDState *get_card(SDBus *sdbus)
35 {
36     /* We only ever have one child on the bus so just return it */
37     BusChild *kid = QTAILQ_FIRST(&sdbus->qbus.children);
38 
39     if (!kid) {
40         return NULL;
41     }
42     return SD_CARD(kid->child);
43 }
44 
45 uint8_t sdbus_get_dat_lines(SDBus *sdbus)
46 {
47     SDState *slave = get_card(sdbus);
48     uint8_t dat_lines = 0b1111; /* 4 bit bus width */
49 
50     if (slave) {
51         SDCardClass *sc = SD_CARD_GET_CLASS(slave);
52 
53         if (sc->get_dat_lines) {
54             dat_lines = sc->get_dat_lines(slave);
55         }
56     }
57     trace_sdbus_get_dat_lines(sdbus_name(sdbus), dat_lines);
58 
59     return dat_lines;
60 }
61 
62 bool sdbus_get_cmd_line(SDBus *sdbus)
63 {
64     SDState *slave = get_card(sdbus);
65     bool cmd_line = true;
66 
67     if (slave) {
68         SDCardClass *sc = SD_CARD_GET_CLASS(slave);
69 
70         if (sc->get_cmd_line) {
71             cmd_line = sc->get_cmd_line(slave);
72         }
73     }
74     trace_sdbus_get_cmd_line(sdbus_name(sdbus), cmd_line);
75 
76     return cmd_line;
77 }
78 
79 void sdbus_set_voltage(SDBus *sdbus, uint16_t millivolts)
80 {
81     SDState *card = get_card(sdbus);
82 
83     trace_sdbus_set_voltage(sdbus_name(sdbus), millivolts);
84     if (card) {
85         SDCardClass *sc = SD_CARD_GET_CLASS(card);
86 
87         assert(sc->set_voltage);
88         sc->set_voltage(card, millivolts);
89     }
90 }
91 
92 int sdbus_do_command(SDBus *sdbus, SDRequest *req, uint8_t *response)
93 {
94     SDState *card = get_card(sdbus);
95 
96     trace_sdbus_command(sdbus_name(sdbus), req->cmd, req->arg);
97     if (card) {
98         SDCardClass *sc = SD_CARD_GET_CLASS(card);
99 
100         return sc->do_command(card, req, response);
101     }
102 
103     return 0;
104 }
105 
106 void sdbus_write_byte(SDBus *sdbus, uint8_t value)
107 {
108     SDState *card = get_card(sdbus);
109 
110     trace_sdbus_write(sdbus_name(sdbus), value);
111     if (card) {
112         SDCardClass *sc = SD_CARD_GET_CLASS(card);
113 
114         sc->write_byte(card, value);
115     }
116 }
117 
118 void sdbus_write_data(SDBus *sdbus, const void *buf, size_t length)
119 {
120     SDState *card = get_card(sdbus);
121     const uint8_t *data = buf;
122 
123     if (card) {
124         SDCardClass *sc = SD_CARD_GET_CLASS(card);
125 
126         for (size_t i = 0; i < length; i++) {
127             trace_sdbus_write(sdbus_name(sdbus), data[i]);
128             sc->write_byte(card, data[i]);
129         }
130     }
131 }
132 
133 uint8_t sdbus_read_byte(SDBus *sdbus)
134 {
135     SDState *card = get_card(sdbus);
136     uint8_t value = 0;
137 
138     if (card) {
139         SDCardClass *sc = SD_CARD_GET_CLASS(card);
140 
141         value = sc->read_byte(card);
142     }
143     trace_sdbus_read(sdbus_name(sdbus), value);
144 
145     return value;
146 }
147 
148 void sdbus_read_data(SDBus *sdbus, void *buf, size_t length)
149 {
150     SDState *card = get_card(sdbus);
151     uint8_t *data = buf;
152 
153     if (card) {
154         SDCardClass *sc = SD_CARD_GET_CLASS(card);
155 
156         for (size_t i = 0; i < length; i++) {
157             data[i] = sc->read_byte(card);
158             trace_sdbus_read(sdbus_name(sdbus), data[i]);
159         }
160     }
161 }
162 
163 bool sdbus_data_ready(SDBus *sdbus)
164 {
165     SDState *card = get_card(sdbus);
166 
167     if (card) {
168         SDCardClass *sc = SD_CARD_GET_CLASS(card);
169 
170         return sc->data_ready(card);
171     }
172 
173     return false;
174 }
175 
176 bool sdbus_get_inserted(SDBus *sdbus)
177 {
178     SDState *card = get_card(sdbus);
179 
180     if (card) {
181         SDCardClass *sc = SD_CARD_GET_CLASS(card);
182 
183         return sc->get_inserted(card);
184     }
185 
186     return false;
187 }
188 
189 bool sdbus_get_readonly(SDBus *sdbus)
190 {
191     SDState *card = get_card(sdbus);
192 
193     if (card) {
194         SDCardClass *sc = SD_CARD_GET_CLASS(card);
195 
196         return sc->get_readonly(card);
197     }
198 
199     return false;
200 }
201 
202 void sdbus_set_inserted(SDBus *sdbus, bool inserted)
203 {
204     SDBusClass *sbc = SD_BUS_GET_CLASS(sdbus);
205     BusState *qbus = BUS(sdbus);
206 
207     if (sbc->set_inserted) {
208         sbc->set_inserted(qbus->parent, inserted);
209     }
210 }
211 
212 void sdbus_set_readonly(SDBus *sdbus, bool readonly)
213 {
214     SDBusClass *sbc = SD_BUS_GET_CLASS(sdbus);
215     BusState *qbus = BUS(sdbus);
216 
217     if (sbc->set_readonly) {
218         sbc->set_readonly(qbus->parent, readonly);
219     }
220 }
221 
222 void sdbus_reparent_card(SDBus *from, SDBus *to)
223 {
224     SDState *card = get_card(from);
225     SDCardClass *sc;
226     bool readonly;
227 
228     /* We directly reparent the card object rather than implementing this
229      * as a hotpluggable connection because we don't want to expose SD cards
230      * to users as being hotpluggable, and we can get away with it in this
231      * limited use case. This could perhaps be implemented more cleanly in
232      * future by adding support to the hotplug infrastructure for "device
233      * can be hotplugged only via code, not by user".
234      */
235 
236     if (!card) {
237         return;
238     }
239 
240     sc = SD_CARD_GET_CLASS(card);
241     readonly = sc->get_readonly(card);
242 
243     sdbus_set_inserted(from, false);
244     qdev_set_parent_bus(DEVICE(card), &to->qbus, &error_abort);
245     sdbus_set_inserted(to, true);
246     sdbus_set_readonly(to, readonly);
247 }
248 
249 static const TypeInfo sd_bus_info = {
250     .name = TYPE_SD_BUS,
251     .parent = TYPE_BUS,
252     .instance_size = sizeof(SDBus),
253     .class_size = sizeof(SDBusClass),
254 };
255 
256 static void sd_bus_register_types(void)
257 {
258     type_register_static(&sd_bus_info);
259 }
260 
261 type_init(sd_bus_register_types)
262