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