xref: /openbmc/qemu/hw/sd/core.c (revision d2d08975fc01e4898ab43eae0d03d53e689048cd)
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 
sdbus_name(SDBus * sdbus)30 static inline const char *sdbus_name(SDBus *sdbus)
31 {
32     return sdbus->qbus.name;
33 }
34 
get_card(SDBus * sdbus)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 
sdbus_get_dat_lines(SDBus * sdbus)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 
sdbus_get_cmd_line(SDBus * sdbus)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 
sdbus_set_voltage(SDBus * sdbus,uint16_t millivolts)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 
sdbus_do_command(SDBus * sdbus,SDRequest * req,uint8_t * resp,size_t respsz)93 size_t sdbus_do_command(SDBus *sdbus, SDRequest *req,
94                         uint8_t *resp, size_t respsz)
95 {
96     SDState *card = get_card(sdbus);
97 
98     trace_sdbus_command(sdbus_name(sdbus), req->cmd, req->arg);
99     if (card) {
100         SDCardClass *sc = SDMMC_COMMON_GET_CLASS(card);
101 
102         return sc->do_command(card, req, resp, respsz);
103     }
104 
105     return 0;
106 }
107 
sdbus_write_byte(SDBus * sdbus,uint8_t value)108 void sdbus_write_byte(SDBus *sdbus, uint8_t value)
109 {
110     SDState *card = get_card(sdbus);
111 
112     trace_sdbus_write(sdbus_name(sdbus), value);
113     if (card) {
114         SDCardClass *sc = SDMMC_COMMON_GET_CLASS(card);
115 
116         sc->write_byte(card, value);
117     }
118 }
119 
sdbus_write_data(SDBus * sdbus,const void * buf,size_t length)120 void sdbus_write_data(SDBus *sdbus, const void *buf, size_t length)
121 {
122     SDState *card = get_card(sdbus);
123     const uint8_t *data = buf;
124 
125     if (card) {
126         SDCardClass *sc = SDMMC_COMMON_GET_CLASS(card);
127 
128         for (size_t i = 0; i < length; i++) {
129             trace_sdbus_write(sdbus_name(sdbus), data[i]);
130             sc->write_byte(card, data[i]);
131         }
132     }
133 }
134 
sdbus_read_byte(SDBus * sdbus)135 uint8_t sdbus_read_byte(SDBus *sdbus)
136 {
137     SDState *card = get_card(sdbus);
138     uint8_t value = 0;
139 
140     if (card) {
141         SDCardClass *sc = SDMMC_COMMON_GET_CLASS(card);
142 
143         value = sc->read_byte(card);
144     }
145     trace_sdbus_read(sdbus_name(sdbus), value);
146 
147     return value;
148 }
149 
sdbus_read_data(SDBus * sdbus,void * buf,size_t length)150 void sdbus_read_data(SDBus *sdbus, void *buf, size_t length)
151 {
152     SDState *card = get_card(sdbus);
153     uint8_t *data = buf;
154 
155     if (card) {
156         SDCardClass *sc = SDMMC_COMMON_GET_CLASS(card);
157 
158         for (size_t i = 0; i < length; i++) {
159             data[i] = sc->read_byte(card);
160             trace_sdbus_read(sdbus_name(sdbus), data[i]);
161         }
162     }
163 }
164 
sdbus_receive_ready(SDBus * sdbus)165 bool sdbus_receive_ready(SDBus *sdbus)
166 {
167     SDState *card = get_card(sdbus);
168 
169     if (card) {
170         SDCardClass *sc = SDMMC_COMMON_GET_CLASS(card);
171 
172         return sc->receive_ready(card);
173     }
174 
175     return false;
176 }
177 
sdbus_data_ready(SDBus * sdbus)178 bool sdbus_data_ready(SDBus *sdbus)
179 {
180     SDState *card = get_card(sdbus);
181 
182     if (card) {
183         SDCardClass *sc = SDMMC_COMMON_GET_CLASS(card);
184 
185         return sc->data_ready(card);
186     }
187 
188     return false;
189 }
190 
sdbus_get_inserted(SDBus * sdbus)191 bool sdbus_get_inserted(SDBus *sdbus)
192 {
193     SDState *card = get_card(sdbus);
194 
195     if (card) {
196         SDCardClass *sc = SDMMC_COMMON_GET_CLASS(card);
197 
198         return sc->get_inserted(card);
199     }
200 
201     return false;
202 }
203 
sdbus_get_readonly(SDBus * sdbus)204 bool sdbus_get_readonly(SDBus *sdbus)
205 {
206     SDState *card = get_card(sdbus);
207 
208     if (card) {
209         SDCardClass *sc = SDMMC_COMMON_GET_CLASS(card);
210 
211         return sc->get_readonly(card);
212     }
213 
214     return false;
215 }
216 
sdbus_set_inserted(SDBus * sdbus,bool inserted)217 void sdbus_set_inserted(SDBus *sdbus, bool inserted)
218 {
219     SDBusClass *sbc = SD_BUS_GET_CLASS(sdbus);
220     BusState *qbus = BUS(sdbus);
221 
222     if (sbc->set_inserted) {
223         sbc->set_inserted(qbus->parent, inserted);
224     }
225 }
226 
sdbus_set_readonly(SDBus * sdbus,bool readonly)227 void sdbus_set_readonly(SDBus *sdbus, bool readonly)
228 {
229     SDBusClass *sbc = SD_BUS_GET_CLASS(sdbus);
230     BusState *qbus = BUS(sdbus);
231 
232     if (sbc->set_readonly) {
233         sbc->set_readonly(qbus->parent, readonly);
234     }
235 }
236 
sdbus_reparent_card(SDBus * from,SDBus * to)237 void sdbus_reparent_card(SDBus *from, SDBus *to)
238 {
239     SDState *card = get_card(from);
240     SDCardClass *sc;
241     bool readonly;
242 
243     /* We directly reparent the card object rather than implementing this
244      * as a hotpluggable connection because we don't want to expose SD cards
245      * to users as being hotpluggable, and we can get away with it in this
246      * limited use case. This could perhaps be implemented more cleanly in
247      * future by adding support to the hotplug infrastructure for "device
248      * can be hotplugged only via code, not by user".
249      */
250 
251     if (!card) {
252         return;
253     }
254 
255     sc = SDMMC_COMMON_GET_CLASS(card);
256     readonly = sc->get_readonly(card);
257 
258     sdbus_set_inserted(from, false);
259     qdev_set_parent_bus(DEVICE(card), &to->qbus, &error_abort);
260     sdbus_set_inserted(to, true);
261     sdbus_set_readonly(to, readonly);
262 }
263 
264 static const TypeInfo sd_bus_types[] = {
265     {
266         .name           = TYPE_SD_BUS,
267         .parent         = TYPE_BUS,
268         .instance_size  = sizeof(SDBus),
269         .class_size     = sizeof(SDBusClass),
270     },
271 };
272 
273 DEFINE_TYPES(sd_bus_types)
274