master
c 302 lines 6.97 KB
Raw
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/core/qdev.h"
24 #include "hw/sd/sd.h"
25 #include "qemu/module.h"
26 #include "qapi/error.h"
27 #include "qemu/cutils.h"
28 #include "sdmmc-internal.h"
29 #include "trace.h"
30
31 static inline const char *sdbus_name(SDBus *sdbus)
32 {
33 return sdbus->qbus.name;
34 }
35
36 static SDState *get_card(SDBus *sdbus)
37 {
38 /* We only ever have one child on the bus so just return it */
39 BusChild *kid = QTAILQ_FIRST(&sdbus->qbus.children);
40
41 if (!kid) {
42 return NULL;
43 }
44 return SDMMC_COMMON(kid->child);
45 }
46
47 static void sdbus_write_dump(const char *bus_name, const void *buf, size_t len)
48 {
49 g_autoptr(GString) str = NULL;
50
51 if (trace_event_get_state_backends(TRACE_SDBUS_WRITE)) {
52 str = qemu_hexdump_line(NULL, buf, len, 8, 0);
53 trace_sdbus_write(bus_name, str->str);
54 }
55 }
56
57 static void sdbus_read_dump(const char *bus_name, const void *buf, size_t len)
58 {
59 g_autoptr(GString) str = NULL;
60
61 if (trace_event_get_state_backends(TRACE_SDBUS_READ)) {
62 str = qemu_hexdump_line(NULL, buf, len, 8, 0);
63 trace_sdbus_read(bus_name, str->str);
64 }
65 }
66
67 uint8_t sdbus_get_dat_lines(SDBus *sdbus)
68 {
69 SDState *slave = get_card(sdbus);
70 uint8_t dat_lines = 0b1111; /* 4 bit bus width */
71
72 if (slave) {
73 SDCardClass *sc = SDMMC_COMMON_GET_CLASS(slave);
74
75 if (sc->get_dat_lines) {
76 dat_lines = sc->get_dat_lines(slave);
77 }
78 }
79 trace_sdbus_get_dat_lines(sdbus_name(sdbus), dat_lines);
80
81 return dat_lines;
82 }
83
84 bool sdbus_get_cmd_line(SDBus *sdbus)
85 {
86 SDState *slave = get_card(sdbus);
87 bool cmd_line = true;
88
89 if (slave) {
90 SDCardClass *sc = SDMMC_COMMON_GET_CLASS(slave);
91
92 if (sc->get_cmd_line) {
93 cmd_line = sc->get_cmd_line(slave);
94 }
95 }
96 trace_sdbus_get_cmd_line(sdbus_name(sdbus), cmd_line);
97
98 return cmd_line;
99 }
100
101 void sdbus_set_voltage(SDBus *sdbus, uint16_t millivolts)
102 {
103 SDState *card = get_card(sdbus);
104
105 trace_sdbus_set_voltage(sdbus_name(sdbus), millivolts);
106 if (card) {
107 SDCardClass *sc = SDMMC_COMMON_GET_CLASS(card);
108
109 assert(sc->set_voltage);
110 sc->set_voltage(card, millivolts);
111 }
112 }
113
114 size_t sdbus_do_command(SDBus *sdbus, SDRequest *req,
115 uint8_t *resp, size_t respsz)
116 {
117 SDState *card = get_card(sdbus);
118
119 trace_sdbus_command(sdbus_name(sdbus), req->cmd, req->arg);
120 if (card) {
121 SDCardClass *sc = SDMMC_COMMON_GET_CLASS(card);
122
123 return sc->do_command(card, req, resp, respsz);
124 }
125
126 return 0;
127 }
128
129 void sdbus_write_byte(SDBus *sdbus, uint8_t value)
130 {
131 SDState *card = get_card(sdbus);
132
133 sdbus_write_dump(sdbus_name(sdbus), &value, 1);
134 if (card) {
135 SDCardClass *sc = SDMMC_COMMON_GET_CLASS(card);
136
137 sc->write_data(card, &value, 1);
138 }
139 }
140
141 void sdbus_write_data(SDBus *sdbus, const void *buf, size_t length)
142 {
143 SDState *card = get_card(sdbus);
144
145 sdbus_write_dump(sdbus_name(sdbus), buf, length);
146 if (card) {
147 SDCardClass *sc = SDMMC_COMMON_GET_CLASS(card);
148
149 while (length > 0) {
150 size_t written = sc->write_data(card, buf, length);
151
152 g_assert(written >= 1);
153
154 buf += written;
155 length -= written;
156 }
157 }
158 }
159
160 uint8_t sdbus_read_byte(SDBus *sdbus)
161 {
162 SDState *card = get_card(sdbus);
163 uint8_t value = 0;
164
165 if (card) {
166 SDCardClass *sc = SDMMC_COMMON_GET_CLASS(card);
167
168 sc->read_data(card, &value, 1);
169 }
170 sdbus_read_dump(sdbus_name(sdbus), &value, 1);
171
172 return value;
173 }
174
175 void sdbus_read_data(SDBus *sdbus, void *buf, size_t length)
176 {
177 SDState *card = get_card(sdbus);
178
179 if (card) {
180 SDCardClass *sc = SDMMC_COMMON_GET_CLASS(card);
181
182 while (length > 0) {
183 size_t read = sc->read_data(card, buf, length);
184
185 g_assert(read >= 1);
186
187 buf += read;
188 length -= read;
189 }
190 }
191 sdbus_read_dump(sdbus_name(sdbus), buf, length);
192 }
193
194 bool sdbus_receive_ready(SDBus *sdbus)
195 {
196 SDState *card = get_card(sdbus);
197
198 if (card) {
199 SDCardClass *sc = SDMMC_COMMON_GET_CLASS(card);
200
201 return sc->receive_ready(card);
202 }
203
204 return false;
205 }
206
207 bool sdbus_data_ready(SDBus *sdbus)
208 {
209 SDState *card = get_card(sdbus);
210
211 if (card) {
212 SDCardClass *sc = SDMMC_COMMON_GET_CLASS(card);
213
214 return sc->data_ready(card);
215 }
216
217 return false;
218 }
219
220 bool sdbus_get_inserted(SDBus *sdbus)
221 {
222 SDState *card = get_card(sdbus);
223
224 if (card) {
225 SDCardClass *sc = SDMMC_COMMON_GET_CLASS(card);
226
227 return sc->get_inserted(card);
228 }
229
230 return false;
231 }
232
233 bool sdbus_get_readonly(SDBus *sdbus)
234 {
235 SDState *card = get_card(sdbus);
236
237 if (card) {
238 SDCardClass *sc = SDMMC_COMMON_GET_CLASS(card);
239
240 return sc->get_readonly(card);
241 }
242
243 return false;
244 }
245
246 void sdbus_set_inserted(SDBus *sdbus, bool inserted)
247 {
248 SDBusClass *sbc = SD_BUS_GET_CLASS(sdbus);
249 BusState *qbus = BUS(sdbus);
250
251 if (sbc->set_inserted) {
252 sbc->set_inserted(qbus->parent, inserted);
253 }
254 }
255
256 void sdbus_set_readonly(SDBus *sdbus, bool readonly)
257 {
258 SDBusClass *sbc = SD_BUS_GET_CLASS(sdbus);
259 BusState *qbus = BUS(sdbus);
260
261 if (sbc->set_readonly) {
262 sbc->set_readonly(qbus->parent, readonly);
263 }
264 }
265
266 void sdbus_reparent_card(SDBus *from, SDBus *to)
267 {
268 SDState *card = get_card(from);
269 SDCardClass *sc;
270 bool readonly;
271
272 /* We directly reparent the card object rather than implementing this
273 * as a hotpluggable connection because we don't want to expose SD cards
274 * to users as being hotpluggable, and we can get away with it in this
275 * limited use case. This could perhaps be implemented more cleanly in
276 * future by adding support to the hotplug infrastructure for "device
277 * can be hotplugged only via code, not by user".
278 */
279
280 if (!card) {
281 return;
282 }
283
284 sc = SDMMC_COMMON_GET_CLASS(card);
285 readonly = sc->get_readonly(card);
286
287 sdbus_set_inserted(from, false);
288 qdev_set_parent_bus(DEVICE(card), &to->qbus, &error_abort);
289 sdbus_set_inserted(to, true);
290 sdbus_set_readonly(to, readonly);
291 }
292
293 static const TypeInfo sd_bus_types[] = {
294 {
295 .name = TYPE_SD_BUS,
296 .parent = TYPE_BUS,
297 .instance_size = sizeof(SDBus),
298 .class_size = sizeof(SDBusClass),
299 },
300 };
301
302 DEFINE_TYPES(sd_bus_types)