2 * SSI to SD card adapter.
4 * Copyright (c) 2007 CodeSourcery.
5 * Written by Paul Brook
7 * This code is licenced under the GPL.
13 //#define DEBUG_SSI_SD 1
16 #define DPRINTF(fmt, args...) \
17 do { printf("ssi_sd: " fmt , ##args); } while (0)
18 #define BADF(fmt, args...) \
19 do { fprintf(stderr, "ssi_sd: error: " fmt , ##args); exit(1);} while (0)
21 #define DPRINTF(fmt, args...) do {} while(0)
22 #define BADF(fmt, args...) \
23 do { fprintf(stderr, "ssi_sd: error: " fmt , ##args);} while (0)
45 /* State word bits. */
46 #define SSI_SDR_LOCKED 0x0001
47 #define SSI_SDR_WP_ERASE 0x0002
48 #define SSI_SDR_ERROR 0x0004
49 #define SSI_SDR_CC_ERROR 0x0008
50 #define SSI_SDR_ECC_FAILED 0x0010
51 #define SSI_SDR_WP_VIOLATION 0x0020
52 #define SSI_SDR_ERASE_PARAM 0x0040
53 #define SSI_SDR_OUT_OF_RANGE 0x0080
54 #define SSI_SDR_IDLE 0x0100
55 #define SSI_SDR_ERASE_RESET 0x0200
56 #define SSI_SDR_ILLEGAL_COMMAND 0x0400
57 #define SSI_SDR_COM_CRC_ERROR 0x0800
58 #define SSI_SDR_ERASE_SEQ_ERROR 0x1000
59 #define SSI_SDR_ADDRESS_ERROR 0x2000
60 #define SSI_SDR_PARAMETER_ERROR 0x4000
62 int ssi_sd_xfer(void *opaque
, int val
)
64 ssi_sd_state
*s
= (ssi_sd_state
*)opaque
;
66 /* Special case: allow CMD12 (STOP TRANSMISSION) while reading data. */
67 if (s
->mode
== SSI_SD_DATA_READ
&& val
== 0x4d) {
69 /* There must be at least one byte delay before the card responds. */
76 DPRINTF("NULL command\n");
80 s
->mode
= SSI_SD_CMDARG
;
85 struct sd_request_s request
;
87 /* FIXME: Check CRC. */
89 request
.arg
= (s
->cmdarg
[0] << 24) | (s
->cmdarg
[1] << 16)
90 | (s
->cmdarg
[2] << 8) | s
->cmdarg
[3];
91 DPRINTF("CMD%d arg 0x%08x\n", s
->cmd
, request
.arg
);
92 s
->arglen
= sd_do_command(s
->sd
, &request
, longresp
);
96 DPRINTF("SD command failed\n");
97 } else if (s
->cmd
== 58) {
98 /* CMD58 returns R3 response (OCR) */
99 DPRINTF("Returned OCR\n");
102 memcpy(&s
->response
[1], longresp
, 4);
103 } else if (s
->arglen
!= 4) {
104 BADF("Unexpected response to cmd %d\n", s
->cmd
);
105 /* Illegal command is about as near as we can get. */
109 /* All other commands return status. */
112 /* CMD13 returns a 2-byte statuse work. Other commands
113 only return the first byte. */
114 s
->arglen
= (s
->cmd
== 13) ? 2 : 1;
115 cardstatus
= (longresp
[0] << 24) | (longresp
[1] << 16)
116 | (longresp
[2] << 8) | longresp
[3];
118 if (((cardstatus
>> 9) & 0xf) < 4)
119 status
|= SSI_SDR_IDLE
;
120 if (cardstatus
& ERASE_RESET
)
121 status
|= SSI_SDR_ERASE_RESET
;
122 if (cardstatus
& ILLEGAL_COMMAND
)
123 status
|= SSI_SDR_ILLEGAL_COMMAND
;
124 if (cardstatus
& COM_CRC_ERROR
)
125 status
|= SSI_SDR_COM_CRC_ERROR
;
126 if (cardstatus
& ERASE_SEQ_ERROR
)
127 status
|= SSI_SDR_ERASE_SEQ_ERROR
;
128 if (cardstatus
& ADDRESS_ERROR
)
129 status
|= SSI_SDR_ADDRESS_ERROR
;
130 if (cardstatus
& CARD_IS_LOCKED
)
131 status
|= SSI_SDR_LOCKED
;
132 if (cardstatus
& (LOCK_UNLOCK_FAILED
| WP_ERASE_SKIP
))
133 status
|= SSI_SDR_WP_ERASE
;
134 if (cardstatus
& SD_ERROR
)
135 status
|= SSI_SDR_ERROR
;
136 if (cardstatus
& CC_ERROR
)
137 status
|= SSI_SDR_CC_ERROR
;
138 if (cardstatus
& CARD_ECC_FAILED
)
139 status
|= SSI_SDR_ECC_FAILED
;
140 if (cardstatus
& WP_VIOLATION
)
141 status
|= SSI_SDR_WP_VIOLATION
;
142 if (cardstatus
& ERASE_PARAM
)
143 status
|= SSI_SDR_ERASE_PARAM
;
144 if (cardstatus
& (OUT_OF_RANGE
| CID_CSD_OVERWRITE
))
145 status
|= SSI_SDR_OUT_OF_RANGE
;
146 /* ??? Don't know what Parameter Error really means, so
147 assume it's set if the second byte is nonzero. */
149 status
|= SSI_SDR_PARAMETER_ERROR
;
150 s
->response
[0] = status
>> 8;
151 s
->response
[1] = status
;
152 DPRINTF("Card status 0x%02x\n", status
);
154 s
->mode
= SSI_SD_RESPONSE
;
157 s
->cmdarg
[s
->arglen
++] = val
;
160 case SSI_SD_RESPONSE
:
165 if (s
->response_pos
< s
->arglen
) {
166 DPRINTF("Response 0x%02x\n", s
->response
[s
->response_pos
]);
167 return s
->response
[s
->response_pos
++];
169 if (sd_data_ready(s
->sd
)) {
170 DPRINTF("Data read\n");
171 s
->mode
= SSI_SD_DATA_START
;
173 DPRINTF("End of command\n");
174 s
->mode
= SSI_SD_CMD
;
177 case SSI_SD_DATA_START
:
178 DPRINTF("Start read block\n");
179 s
->mode
= SSI_SD_DATA_READ
;
181 case SSI_SD_DATA_READ
:
182 val
= sd_read_data(s
->sd
);
183 if (!sd_data_ready(s
->sd
)) {
184 DPRINTF("Data read end\n");
185 s
->mode
= SSI_SD_CMD
;
189 /* Should never happen. */
193 void *ssi_sd_init(BlockDriverState
*bs
)
197 s
= (ssi_sd_state
*)qemu_mallocz(sizeof(ssi_sd_state
));
198 s
->mode
= SSI_SD_CMD
;
199 s
->sd
= sd_init(bs
, 1);