xref: /openbmc/qemu/hw/sd/core.c (revision b9ee1387e0cf0fba5a73a610d31cb9cead457dc0)
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