1c759a790SPeter Maydell /*
2c759a790SPeter Maydell * SD card bus interface code.
3c759a790SPeter Maydell *
4c759a790SPeter Maydell * Copyright (c) 2015 Linaro Limited
5c759a790SPeter Maydell *
6c759a790SPeter Maydell * Author:
7c759a790SPeter Maydell * Peter Maydell <peter.maydell@linaro.org>
8c759a790SPeter Maydell *
9c759a790SPeter Maydell * This program is free software; you can redistribute it and/or modify it
10c759a790SPeter Maydell * under the terms and conditions of the GNU General Public License,
11c759a790SPeter Maydell * version 2 or later, as published by the Free Software Foundation.
12c759a790SPeter Maydell *
13c759a790SPeter Maydell * This program is distributed in the hope it will be useful, but WITHOUT
14c759a790SPeter Maydell * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15c759a790SPeter Maydell * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16c759a790SPeter Maydell * more details.
17c759a790SPeter Maydell *
18c759a790SPeter Maydell * You should have received a copy of the GNU General Public License along with
19c759a790SPeter Maydell * this program. If not, see <http://www.gnu.org/licenses/>.
20c759a790SPeter Maydell */
21c759a790SPeter Maydell
22c759a790SPeter Maydell #include "qemu/osdep.h"
23c759a790SPeter Maydell #include "hw/qdev-core.h"
24c759a790SPeter Maydell #include "hw/sd/sd.h"
250b8fa32fSMarkus Armbruster #include "qemu/module.h"
26bb755ba4SPaolo Bonzini #include "qapi/error.h"
27*0bcea3f7SPhilippe Mathieu-Daudé #include "sdmmc-internal.h"
28238cd935SPhilippe Mathieu-Daudé #include "trace.h"
29238cd935SPhilippe Mathieu-Daudé
sdbus_name(SDBus * sdbus)30238cd935SPhilippe Mathieu-Daudé static inline const char *sdbus_name(SDBus *sdbus)
31238cd935SPhilippe Mathieu-Daudé {
32238cd935SPhilippe Mathieu-Daudé return sdbus->qbus.name;
33238cd935SPhilippe Mathieu-Daudé }
34c759a790SPeter Maydell
get_card(SDBus * sdbus)35c759a790SPeter Maydell static SDState *get_card(SDBus *sdbus)
36c759a790SPeter Maydell {
37c759a790SPeter Maydell /* We only ever have one child on the bus so just return it */
38c759a790SPeter Maydell BusChild *kid = QTAILQ_FIRST(&sdbus->qbus.children);
39c759a790SPeter Maydell
40c759a790SPeter Maydell if (!kid) {
41c759a790SPeter Maydell return NULL;
42c759a790SPeter Maydell }
43*0bcea3f7SPhilippe Mathieu-Daudé return SDMMC_COMMON(kid->child);
44c759a790SPeter Maydell }
45c759a790SPeter Maydell
sdbus_get_dat_lines(SDBus * sdbus)46da346922SPhilippe Mathieu-Daudé uint8_t sdbus_get_dat_lines(SDBus *sdbus)
47da346922SPhilippe Mathieu-Daudé {
48da346922SPhilippe Mathieu-Daudé SDState *slave = get_card(sdbus);
49da346922SPhilippe Mathieu-Daudé uint8_t dat_lines = 0b1111; /* 4 bit bus width */
50da346922SPhilippe Mathieu-Daudé
51da346922SPhilippe Mathieu-Daudé if (slave) {
52*0bcea3f7SPhilippe Mathieu-Daudé SDCardClass *sc = SDMMC_COMMON_GET_CLASS(slave);
53da346922SPhilippe Mathieu-Daudé
54da346922SPhilippe Mathieu-Daudé if (sc->get_dat_lines) {
55da346922SPhilippe Mathieu-Daudé dat_lines = sc->get_dat_lines(slave);
56da346922SPhilippe Mathieu-Daudé }
57da346922SPhilippe Mathieu-Daudé }
58da346922SPhilippe Mathieu-Daudé trace_sdbus_get_dat_lines(sdbus_name(sdbus), dat_lines);
59da346922SPhilippe Mathieu-Daudé
60da346922SPhilippe Mathieu-Daudé return dat_lines;
61da346922SPhilippe Mathieu-Daudé }
62da346922SPhilippe Mathieu-Daudé
sdbus_get_cmd_line(SDBus * sdbus)63da346922SPhilippe Mathieu-Daudé bool sdbus_get_cmd_line(SDBus *sdbus)
64da346922SPhilippe Mathieu-Daudé {
65da346922SPhilippe Mathieu-Daudé SDState *slave = get_card(sdbus);
66da346922SPhilippe Mathieu-Daudé bool cmd_line = true;
67da346922SPhilippe Mathieu-Daudé
68da346922SPhilippe Mathieu-Daudé if (slave) {
69*0bcea3f7SPhilippe Mathieu-Daudé SDCardClass *sc = SDMMC_COMMON_GET_CLASS(slave);
70da346922SPhilippe Mathieu-Daudé
71da346922SPhilippe Mathieu-Daudé if (sc->get_cmd_line) {
72da346922SPhilippe Mathieu-Daudé cmd_line = sc->get_cmd_line(slave);
73da346922SPhilippe Mathieu-Daudé }
74da346922SPhilippe Mathieu-Daudé }
75da346922SPhilippe Mathieu-Daudé trace_sdbus_get_cmd_line(sdbus_name(sdbus), cmd_line);
76da346922SPhilippe Mathieu-Daudé
77da346922SPhilippe Mathieu-Daudé return cmd_line;
78da346922SPhilippe Mathieu-Daudé }
79da346922SPhilippe Mathieu-Daudé
sdbus_set_voltage(SDBus * sdbus,uint16_t millivolts)800034ebe6SPhilippe Mathieu-Daudé void sdbus_set_voltage(SDBus *sdbus, uint16_t millivolts)
810034ebe6SPhilippe Mathieu-Daudé {
820034ebe6SPhilippe Mathieu-Daudé SDState *card = get_card(sdbus);
830034ebe6SPhilippe Mathieu-Daudé
840034ebe6SPhilippe Mathieu-Daudé trace_sdbus_set_voltage(sdbus_name(sdbus), millivolts);
850034ebe6SPhilippe Mathieu-Daudé if (card) {
86*0bcea3f7SPhilippe Mathieu-Daudé SDCardClass *sc = SDMMC_COMMON_GET_CLASS(card);
870034ebe6SPhilippe Mathieu-Daudé
880034ebe6SPhilippe Mathieu-Daudé assert(sc->set_voltage);
890034ebe6SPhilippe Mathieu-Daudé sc->set_voltage(card, millivolts);
900034ebe6SPhilippe Mathieu-Daudé }
910034ebe6SPhilippe Mathieu-Daudé }
920034ebe6SPhilippe Mathieu-Daudé
sdbus_do_command(SDBus * sdbus,SDRequest * req,uint8_t * response)93c759a790SPeter Maydell int sdbus_do_command(SDBus *sdbus, SDRequest *req, uint8_t *response)
94c759a790SPeter Maydell {
95c759a790SPeter Maydell SDState *card = get_card(sdbus);
96c759a790SPeter Maydell
9713606b99SPeter Maydell trace_sdbus_command(sdbus_name(sdbus), req->cmd, req->arg);
98c759a790SPeter Maydell if (card) {
99*0bcea3f7SPhilippe Mathieu-Daudé SDCardClass *sc = SDMMC_COMMON_GET_CLASS(card);
100c759a790SPeter Maydell
101c759a790SPeter Maydell return sc->do_command(card, req, response);
102c759a790SPeter Maydell }
103c759a790SPeter Maydell
104c759a790SPeter Maydell return 0;
105c759a790SPeter Maydell }
106c759a790SPeter Maydell
sdbus_write_byte(SDBus * sdbus,uint8_t value)10739017143SPhilippe Mathieu-Daudé void sdbus_write_byte(SDBus *sdbus, uint8_t value)
108c759a790SPeter Maydell {
109c759a790SPeter Maydell SDState *card = get_card(sdbus);
110c759a790SPeter Maydell
111238cd935SPhilippe Mathieu-Daudé trace_sdbus_write(sdbus_name(sdbus), value);
112c759a790SPeter Maydell if (card) {
113*0bcea3f7SPhilippe Mathieu-Daudé SDCardClass *sc = SDMMC_COMMON_GET_CLASS(card);
114c759a790SPeter Maydell
115c769a88dSPhilippe Mathieu-Daudé sc->write_byte(card, value);
116c759a790SPeter Maydell }
117c759a790SPeter Maydell }
118c759a790SPeter Maydell
sdbus_write_data(SDBus * sdbus,const void * buf,size_t length)119e35c343dSPhilippe Mathieu-Daudé void sdbus_write_data(SDBus *sdbus, const void *buf, size_t length)
120e35c343dSPhilippe Mathieu-Daudé {
121e35c343dSPhilippe Mathieu-Daudé SDState *card = get_card(sdbus);
122e35c343dSPhilippe Mathieu-Daudé const uint8_t *data = buf;
123e35c343dSPhilippe Mathieu-Daudé
124e35c343dSPhilippe Mathieu-Daudé if (card) {
125*0bcea3f7SPhilippe Mathieu-Daudé SDCardClass *sc = SDMMC_COMMON_GET_CLASS(card);
126e35c343dSPhilippe Mathieu-Daudé
127e35c343dSPhilippe Mathieu-Daudé for (size_t i = 0; i < length; i++) {
128e35c343dSPhilippe Mathieu-Daudé trace_sdbus_write(sdbus_name(sdbus), data[i]);
129e35c343dSPhilippe Mathieu-Daudé sc->write_byte(card, data[i]);
130e35c343dSPhilippe Mathieu-Daudé }
131e35c343dSPhilippe Mathieu-Daudé }
132e35c343dSPhilippe Mathieu-Daudé }
133e35c343dSPhilippe Mathieu-Daudé
sdbus_read_byte(SDBus * sdbus)1348467f622SPhilippe Mathieu-Daudé uint8_t sdbus_read_byte(SDBus *sdbus)
135c759a790SPeter Maydell {
136c759a790SPeter Maydell SDState *card = get_card(sdbus);
137238cd935SPhilippe Mathieu-Daudé uint8_t value = 0;
138c759a790SPeter Maydell
139c759a790SPeter Maydell if (card) {
140*0bcea3f7SPhilippe Mathieu-Daudé SDCardClass *sc = SDMMC_COMMON_GET_CLASS(card);
141c759a790SPeter Maydell
142c769a88dSPhilippe Mathieu-Daudé value = sc->read_byte(card);
143c759a790SPeter Maydell }
144238cd935SPhilippe Mathieu-Daudé trace_sdbus_read(sdbus_name(sdbus), value);
145c759a790SPeter Maydell
146238cd935SPhilippe Mathieu-Daudé return value;
147c759a790SPeter Maydell }
148c759a790SPeter Maydell
sdbus_read_data(SDBus * sdbus,void * buf,size_t length)1496505a91aSPhilippe Mathieu-Daudé void sdbus_read_data(SDBus *sdbus, void *buf, size_t length)
1506505a91aSPhilippe Mathieu-Daudé {
1516505a91aSPhilippe Mathieu-Daudé SDState *card = get_card(sdbus);
1526505a91aSPhilippe Mathieu-Daudé uint8_t *data = buf;
1536505a91aSPhilippe Mathieu-Daudé
1546505a91aSPhilippe Mathieu-Daudé if (card) {
155*0bcea3f7SPhilippe Mathieu-Daudé SDCardClass *sc = SDMMC_COMMON_GET_CLASS(card);
1566505a91aSPhilippe Mathieu-Daudé
1576505a91aSPhilippe Mathieu-Daudé for (size_t i = 0; i < length; i++) {
1586505a91aSPhilippe Mathieu-Daudé data[i] = sc->read_byte(card);
1596505a91aSPhilippe Mathieu-Daudé trace_sdbus_read(sdbus_name(sdbus), data[i]);
1606505a91aSPhilippe Mathieu-Daudé }
1616505a91aSPhilippe Mathieu-Daudé }
1626505a91aSPhilippe Mathieu-Daudé }
1636505a91aSPhilippe Mathieu-Daudé
sdbus_receive_ready(SDBus * sdbus)164995731d3SBin Meng bool sdbus_receive_ready(SDBus *sdbus)
165995731d3SBin Meng {
166995731d3SBin Meng SDState *card = get_card(sdbus);
167995731d3SBin Meng
168995731d3SBin Meng if (card) {
169*0bcea3f7SPhilippe Mathieu-Daudé SDCardClass *sc = SDMMC_COMMON_GET_CLASS(card);
170995731d3SBin Meng
171995731d3SBin Meng return sc->receive_ready(card);
172995731d3SBin Meng }
173995731d3SBin Meng
174995731d3SBin Meng return false;
175995731d3SBin Meng }
176995731d3SBin Meng
sdbus_data_ready(SDBus * sdbus)177c759a790SPeter Maydell bool sdbus_data_ready(SDBus *sdbus)
178c759a790SPeter Maydell {
179c759a790SPeter Maydell SDState *card = get_card(sdbus);
180c759a790SPeter Maydell
181c759a790SPeter Maydell if (card) {
182*0bcea3f7SPhilippe Mathieu-Daudé SDCardClass *sc = SDMMC_COMMON_GET_CLASS(card);
183c759a790SPeter Maydell
184c759a790SPeter Maydell return sc->data_ready(card);
185c759a790SPeter Maydell }
186c759a790SPeter Maydell
187c759a790SPeter Maydell return false;
188c759a790SPeter Maydell }
189c759a790SPeter Maydell
sdbus_get_inserted(SDBus * sdbus)190c759a790SPeter Maydell bool sdbus_get_inserted(SDBus *sdbus)
191c759a790SPeter Maydell {
192c759a790SPeter Maydell SDState *card = get_card(sdbus);
193c759a790SPeter Maydell
194c759a790SPeter Maydell if (card) {
195*0bcea3f7SPhilippe Mathieu-Daudé SDCardClass *sc = SDMMC_COMMON_GET_CLASS(card);
196c759a790SPeter Maydell
197c759a790SPeter Maydell return sc->get_inserted(card);
198c759a790SPeter Maydell }
199c759a790SPeter Maydell
200c759a790SPeter Maydell return false;
201c759a790SPeter Maydell }
202c759a790SPeter Maydell
sdbus_get_readonly(SDBus * sdbus)203c759a790SPeter Maydell bool sdbus_get_readonly(SDBus *sdbus)
204c759a790SPeter Maydell {
205c759a790SPeter Maydell SDState *card = get_card(sdbus);
206c759a790SPeter Maydell
207c759a790SPeter Maydell if (card) {
208*0bcea3f7SPhilippe Mathieu-Daudé SDCardClass *sc = SDMMC_COMMON_GET_CLASS(card);
209c759a790SPeter Maydell
210c759a790SPeter Maydell return sc->get_readonly(card);
211c759a790SPeter Maydell }
212c759a790SPeter Maydell
213c759a790SPeter Maydell return false;
214c759a790SPeter Maydell }
215c759a790SPeter Maydell
sdbus_set_inserted(SDBus * sdbus,bool inserted)216c759a790SPeter Maydell void sdbus_set_inserted(SDBus *sdbus, bool inserted)
217c759a790SPeter Maydell {
218c759a790SPeter Maydell SDBusClass *sbc = SD_BUS_GET_CLASS(sdbus);
219c759a790SPeter Maydell BusState *qbus = BUS(sdbus);
220c759a790SPeter Maydell
221c759a790SPeter Maydell if (sbc->set_inserted) {
222c759a790SPeter Maydell sbc->set_inserted(qbus->parent, inserted);
223c759a790SPeter Maydell }
224c759a790SPeter Maydell }
225c759a790SPeter Maydell
sdbus_set_readonly(SDBus * sdbus,bool readonly)226c759a790SPeter Maydell void sdbus_set_readonly(SDBus *sdbus, bool readonly)
227c759a790SPeter Maydell {
228c759a790SPeter Maydell SDBusClass *sbc = SD_BUS_GET_CLASS(sdbus);
229c759a790SPeter Maydell BusState *qbus = BUS(sdbus);
230c759a790SPeter Maydell
231c759a790SPeter Maydell if (sbc->set_readonly) {
232c759a790SPeter Maydell sbc->set_readonly(qbus->parent, readonly);
233c759a790SPeter Maydell }
234c759a790SPeter Maydell }
235c759a790SPeter Maydell
sdbus_reparent_card(SDBus * from,SDBus * to)23697fb87ccSClement Deschamps void sdbus_reparent_card(SDBus *from, SDBus *to)
23797fb87ccSClement Deschamps {
23897fb87ccSClement Deschamps SDState *card = get_card(from);
23997fb87ccSClement Deschamps SDCardClass *sc;
24097fb87ccSClement Deschamps bool readonly;
24197fb87ccSClement Deschamps
24297fb87ccSClement Deschamps /* We directly reparent the card object rather than implementing this
24397fb87ccSClement Deschamps * as a hotpluggable connection because we don't want to expose SD cards
24497fb87ccSClement Deschamps * to users as being hotpluggable, and we can get away with it in this
24597fb87ccSClement Deschamps * limited use case. This could perhaps be implemented more cleanly in
24697fb87ccSClement Deschamps * future by adding support to the hotplug infrastructure for "device
24797fb87ccSClement Deschamps * can be hotplugged only via code, not by user".
24897fb87ccSClement Deschamps */
24997fb87ccSClement Deschamps
25097fb87ccSClement Deschamps if (!card) {
25197fb87ccSClement Deschamps return;
25297fb87ccSClement Deschamps }
25397fb87ccSClement Deschamps
254*0bcea3f7SPhilippe Mathieu-Daudé sc = SDMMC_COMMON_GET_CLASS(card);
25597fb87ccSClement Deschamps readonly = sc->get_readonly(card);
25697fb87ccSClement Deschamps
25797fb87ccSClement Deschamps sdbus_set_inserted(from, false);
258bb755ba4SPaolo Bonzini qdev_set_parent_bus(DEVICE(card), &to->qbus, &error_abort);
25997fb87ccSClement Deschamps sdbus_set_inserted(to, true);
26097fb87ccSClement Deschamps sdbus_set_readonly(to, readonly);
26197fb87ccSClement Deschamps }
26297fb87ccSClement Deschamps
26388d2198cSPhilippe Mathieu-Daudé static const TypeInfo sd_bus_types[] = {
26488d2198cSPhilippe Mathieu-Daudé {
265c759a790SPeter Maydell .name = TYPE_SD_BUS,
266c759a790SPeter Maydell .parent = TYPE_BUS,
267c759a790SPeter Maydell .instance_size = sizeof(SDBus),
268c759a790SPeter Maydell .class_size = sizeof(SDBusClass),
26988d2198cSPhilippe Mathieu-Daudé },
270c759a790SPeter Maydell };
271c759a790SPeter Maydell
27288d2198cSPhilippe Mathieu-Daudé DEFINE_TYPES(sd_bus_types)
273