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