hw/sd: ssi-sd: Support multiple block read
[qemu/ar7.git] / hw / sd / ssi-sd.c
blob6d20a240c69d7447705f597f8b53ce12b94f06d2
1 /*
2 * SSI to SD card adapter.
4 * Copyright (c) 2007-2009 CodeSourcery.
5 * Written by Paul Brook
7 * This code is licensed under the GNU GPL v2.
9 * Contributions after 2012-01-13 are licensed under the terms of the
10 * GNU GPL, version 2 or (at your option) any later version.
13 #include "qemu/osdep.h"
14 #include "sysemu/blockdev.h"
15 #include "hw/ssi/ssi.h"
16 #include "migration/vmstate.h"
17 #include "hw/qdev-properties.h"
18 #include "hw/sd/sd.h"
19 #include "qapi/error.h"
20 #include "qemu/crc-ccitt.h"
21 #include "qemu/module.h"
22 #include "qom/object.h"
24 //#define DEBUG_SSI_SD 1
26 #ifdef DEBUG_SSI_SD
27 #define DPRINTF(fmt, ...) \
28 do { printf("ssi_sd: " fmt , ## __VA_ARGS__); } while (0)
29 #define BADF(fmt, ...) \
30 do { fprintf(stderr, "ssi_sd: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
31 #else
32 #define DPRINTF(fmt, ...) do {} while(0)
33 #define BADF(fmt, ...) \
34 do { fprintf(stderr, "ssi_sd: error: " fmt , ## __VA_ARGS__);} while (0)
35 #endif
37 typedef enum {
38 SSI_SD_CMD = 0,
39 SSI_SD_CMDARG,
40 SSI_SD_PREP_RESP,
41 SSI_SD_RESPONSE,
42 SSI_SD_PREP_DATA,
43 SSI_SD_DATA_START,
44 SSI_SD_DATA_READ,
45 SSI_SD_DATA_CRC16,
46 } ssi_sd_mode;
48 struct ssi_sd_state {
49 SSIPeripheral ssidev;
50 uint32_t mode;
51 int cmd;
52 uint8_t cmdarg[4];
53 uint8_t response[5];
54 uint16_t crc16;
55 int32_t read_bytes;
56 int32_t arglen;
57 int32_t response_pos;
58 int32_t stopping;
59 SDBus sdbus;
62 #define TYPE_SSI_SD "ssi-sd"
63 OBJECT_DECLARE_SIMPLE_TYPE(ssi_sd_state, SSI_SD)
65 /* State word bits. */
66 #define SSI_SDR_LOCKED 0x0001
67 #define SSI_SDR_WP_ERASE 0x0002
68 #define SSI_SDR_ERROR 0x0004
69 #define SSI_SDR_CC_ERROR 0x0008
70 #define SSI_SDR_ECC_FAILED 0x0010
71 #define SSI_SDR_WP_VIOLATION 0x0020
72 #define SSI_SDR_ERASE_PARAM 0x0040
73 #define SSI_SDR_OUT_OF_RANGE 0x0080
74 #define SSI_SDR_IDLE 0x0100
75 #define SSI_SDR_ERASE_RESET 0x0200
76 #define SSI_SDR_ILLEGAL_COMMAND 0x0400
77 #define SSI_SDR_COM_CRC_ERROR 0x0800
78 #define SSI_SDR_ERASE_SEQ_ERROR 0x1000
79 #define SSI_SDR_ADDRESS_ERROR 0x2000
80 #define SSI_SDR_PARAMETER_ERROR 0x4000
82 /* single block read/write, multiple block read */
83 #define SSI_TOKEN_SINGLE 0xfe
85 /* dummy value - don't care */
86 #define SSI_DUMMY 0xff
88 static uint32_t ssi_sd_transfer(SSIPeripheral *dev, uint32_t val)
90 ssi_sd_state *s = SSI_SD(dev);
93 * Special case: allow CMD12 (STOP TRANSMISSION) while reading data.
95 * See "Physical Layer Specification Version 8.00" chapter 7.5.2.2,
96 * to avoid conflict between CMD12 response and next data block,
97 * timing of CMD12 should be controlled as follows:
99 * - CMD12 issued at the timing that end bit of CMD12 and end bit of
100 * data block is overlapped
101 * - CMD12 issued after one clock cycle after host receives a token
102 * (either Start Block token or Data Error token)
104 * We need to catch CMD12 in all of the data read states.
106 if (s->mode >= SSI_SD_PREP_DATA && s->mode <= SSI_SD_DATA_CRC16) {
107 if (val == 0x4c) {
108 s->mode = SSI_SD_CMD;
109 /* There must be at least one byte delay before the card responds */
110 s->stopping = 1;
114 switch (s->mode) {
115 case SSI_SD_CMD:
116 if (val == SSI_DUMMY) {
117 DPRINTF("NULL command\n");
118 return SSI_DUMMY;
120 s->cmd = val & 0x3f;
121 s->mode = SSI_SD_CMDARG;
122 s->arglen = 0;
123 return SSI_DUMMY;
124 case SSI_SD_CMDARG:
125 if (s->arglen == 4) {
126 SDRequest request;
127 uint8_t longresp[16];
128 /* FIXME: Check CRC. */
129 request.cmd = s->cmd;
130 request.arg = ldl_be_p(s->cmdarg);
131 DPRINTF("CMD%d arg 0x%08x\n", s->cmd, request.arg);
132 s->arglen = sdbus_do_command(&s->sdbus, &request, longresp);
133 if (s->arglen <= 0) {
134 s->arglen = 1;
135 s->response[0] = 4;
136 DPRINTF("SD command failed\n");
137 } else if (s->cmd == 58) {
138 /* CMD58 returns R3 response (OCR) */
139 DPRINTF("Returned OCR\n");
140 s->arglen = 5;
141 s->response[0] = 1;
142 memcpy(&s->response[1], longresp, 4);
143 } else if (s->arglen != 4) {
144 BADF("Unexpected response to cmd %d\n", s->cmd);
145 /* Illegal command is about as near as we can get. */
146 s->arglen = 1;
147 s->response[0] = 4;
148 } else {
149 /* All other commands return status. */
150 uint32_t cardstatus;
151 uint16_t status;
152 /* CMD13 returns a 2-byte statuse work. Other commands
153 only return the first byte. */
154 s->arglen = (s->cmd == 13) ? 2 : 1;
155 cardstatus = ldl_be_p(longresp);
156 status = 0;
157 if (((cardstatus >> 9) & 0xf) < 4)
158 status |= SSI_SDR_IDLE;
159 if (cardstatus & ERASE_RESET)
160 status |= SSI_SDR_ERASE_RESET;
161 if (cardstatus & ILLEGAL_COMMAND)
162 status |= SSI_SDR_ILLEGAL_COMMAND;
163 if (cardstatus & COM_CRC_ERROR)
164 status |= SSI_SDR_COM_CRC_ERROR;
165 if (cardstatus & ERASE_SEQ_ERROR)
166 status |= SSI_SDR_ERASE_SEQ_ERROR;
167 if (cardstatus & ADDRESS_ERROR)
168 status |= SSI_SDR_ADDRESS_ERROR;
169 if (cardstatus & CARD_IS_LOCKED)
170 status |= SSI_SDR_LOCKED;
171 if (cardstatus & (LOCK_UNLOCK_FAILED | WP_ERASE_SKIP))
172 status |= SSI_SDR_WP_ERASE;
173 if (cardstatus & SD_ERROR)
174 status |= SSI_SDR_ERROR;
175 if (cardstatus & CC_ERROR)
176 status |= SSI_SDR_CC_ERROR;
177 if (cardstatus & CARD_ECC_FAILED)
178 status |= SSI_SDR_ECC_FAILED;
179 if (cardstatus & WP_VIOLATION)
180 status |= SSI_SDR_WP_VIOLATION;
181 if (cardstatus & ERASE_PARAM)
182 status |= SSI_SDR_ERASE_PARAM;
183 if (cardstatus & (OUT_OF_RANGE | CID_CSD_OVERWRITE))
184 status |= SSI_SDR_OUT_OF_RANGE;
185 /* ??? Don't know what Parameter Error really means, so
186 assume it's set if the second byte is nonzero. */
187 if (status & 0xff)
188 status |= SSI_SDR_PARAMETER_ERROR;
189 s->response[0] = status >> 8;
190 s->response[1] = status;
191 DPRINTF("Card status 0x%02x\n", status);
193 s->mode = SSI_SD_PREP_RESP;
194 s->response_pos = 0;
195 } else {
196 s->cmdarg[s->arglen++] = val;
198 return SSI_DUMMY;
199 case SSI_SD_PREP_RESP:
200 DPRINTF("Prepare card response (Ncr)\n");
201 s->mode = SSI_SD_RESPONSE;
202 return SSI_DUMMY;
203 case SSI_SD_RESPONSE:
204 if (s->stopping) {
205 s->stopping = 0;
206 return SSI_DUMMY;
208 if (s->response_pos < s->arglen) {
209 DPRINTF("Response 0x%02x\n", s->response[s->response_pos]);
210 return s->response[s->response_pos++];
212 if (sdbus_data_ready(&s->sdbus)) {
213 DPRINTF("Data read\n");
214 s->mode = SSI_SD_DATA_START;
215 } else {
216 DPRINTF("End of command\n");
217 s->mode = SSI_SD_CMD;
219 return SSI_DUMMY;
220 case SSI_SD_PREP_DATA:
221 DPRINTF("Prepare data block (Nac)\n");
222 s->mode = SSI_SD_DATA_START;
223 return SSI_DUMMY;
224 case SSI_SD_DATA_START:
225 DPRINTF("Start read block\n");
226 s->mode = SSI_SD_DATA_READ;
227 s->response_pos = 0;
228 return SSI_TOKEN_SINGLE;
229 case SSI_SD_DATA_READ:
230 val = sdbus_read_byte(&s->sdbus);
231 s->read_bytes++;
232 s->crc16 = crc_ccitt_false(s->crc16, (uint8_t *)&val, 1);
233 if (!sdbus_data_ready(&s->sdbus) || s->read_bytes == 512) {
234 DPRINTF("Data read end\n");
235 s->mode = SSI_SD_DATA_CRC16;
237 return val;
238 case SSI_SD_DATA_CRC16:
239 val = (s->crc16 & 0xff00) >> 8;
240 s->crc16 <<= 8;
241 s->response_pos++;
242 if (s->response_pos == 2) {
243 DPRINTF("CRC16 read end\n");
244 if (s->read_bytes == 512 && s->cmd != 17) {
245 s->mode = SSI_SD_PREP_DATA;
246 } else {
247 s->mode = SSI_SD_CMD;
249 s->read_bytes = 0;
250 s->response_pos = 0;
252 return val;
254 /* Should never happen. */
255 return SSI_DUMMY;
258 static int ssi_sd_post_load(void *opaque, int version_id)
260 ssi_sd_state *s = (ssi_sd_state *)opaque;
262 if (s->mode > SSI_SD_DATA_CRC16) {
263 return -EINVAL;
265 if (s->mode == SSI_SD_CMDARG &&
266 (s->arglen < 0 || s->arglen >= ARRAY_SIZE(s->cmdarg))) {
267 return -EINVAL;
269 if (s->mode == SSI_SD_RESPONSE &&
270 (s->response_pos < 0 || s->response_pos >= ARRAY_SIZE(s->response) ||
271 (!s->stopping && s->arglen > ARRAY_SIZE(s->response)))) {
272 return -EINVAL;
275 return 0;
278 static const VMStateDescription vmstate_ssi_sd = {
279 .name = "ssi_sd",
280 .version_id = 6,
281 .minimum_version_id = 6,
282 .post_load = ssi_sd_post_load,
283 .fields = (VMStateField []) {
284 VMSTATE_UINT32(mode, ssi_sd_state),
285 VMSTATE_INT32(cmd, ssi_sd_state),
286 VMSTATE_UINT8_ARRAY(cmdarg, ssi_sd_state, 4),
287 VMSTATE_UINT8_ARRAY(response, ssi_sd_state, 5),
288 VMSTATE_UINT16(crc16, ssi_sd_state),
289 VMSTATE_INT32(read_bytes, ssi_sd_state),
290 VMSTATE_INT32(arglen, ssi_sd_state),
291 VMSTATE_INT32(response_pos, ssi_sd_state),
292 VMSTATE_INT32(stopping, ssi_sd_state),
293 VMSTATE_SSI_PERIPHERAL(ssidev, ssi_sd_state),
294 VMSTATE_END_OF_LIST()
298 static void ssi_sd_realize(SSIPeripheral *d, Error **errp)
300 ERRP_GUARD();
301 ssi_sd_state *s = SSI_SD(d);
302 DeviceState *carddev;
303 DriveInfo *dinfo;
305 qbus_create_inplace(&s->sdbus, sizeof(s->sdbus), TYPE_SD_BUS,
306 DEVICE(d), "sd-bus");
308 /* Create and plug in the sd card */
309 /* FIXME use a qdev drive property instead of drive_get_next() */
310 dinfo = drive_get_next(IF_SD);
311 carddev = qdev_new(TYPE_SD_CARD);
312 if (dinfo) {
313 if (!qdev_prop_set_drive_err(carddev, "drive",
314 blk_by_legacy_dinfo(dinfo), errp)) {
315 goto fail;
319 if (!object_property_set_bool(OBJECT(carddev), "spi", true, errp)) {
320 goto fail;
323 if (!qdev_realize_and_unref(carddev, BUS(&s->sdbus), errp)) {
324 goto fail;
327 return;
329 fail:
330 error_prepend(errp, "failed to init SD card: ");
333 static void ssi_sd_reset(DeviceState *dev)
335 ssi_sd_state *s = SSI_SD(dev);
337 s->mode = SSI_SD_CMD;
338 s->cmd = 0;
339 memset(s->cmdarg, 0, sizeof(s->cmdarg));
340 memset(s->response, 0, sizeof(s->response));
341 s->crc16 = 0;
342 s->read_bytes = 0;
343 s->arglen = 0;
344 s->response_pos = 0;
345 s->stopping = 0;
348 static void ssi_sd_class_init(ObjectClass *klass, void *data)
350 DeviceClass *dc = DEVICE_CLASS(klass);
351 SSIPeripheralClass *k = SSI_PERIPHERAL_CLASS(klass);
353 k->realize = ssi_sd_realize;
354 k->transfer = ssi_sd_transfer;
355 k->cs_polarity = SSI_CS_LOW;
356 dc->vmsd = &vmstate_ssi_sd;
357 dc->reset = ssi_sd_reset;
358 /* Reason: init() method uses drive_get_next() */
359 dc->user_creatable = false;
362 static const TypeInfo ssi_sd_info = {
363 .name = TYPE_SSI_SD,
364 .parent = TYPE_SSI_PERIPHERAL,
365 .instance_size = sizeof(ssi_sd_state),
366 .class_init = ssi_sd_class_init,
369 static void ssi_sd_register_types(void)
371 type_register_static(&ssi_sd_info);
374 type_init(ssi_sd_register_types)