1775616c3Spbrook /* 2775616c3Spbrook * SSI to SD card adapter. 3775616c3Spbrook * 45493e33fSPaul Brook * Copyright (c) 2007-2009 CodeSourcery. 5775616c3Spbrook * Written by Paul Brook 6775616c3Spbrook * 7*d56f3efaSBin Meng * Copyright (c) 2021 Wind River Systems, Inc. 8*d56f3efaSBin Meng * Improved by Bin Meng <bin.meng@windriver.com> 9*d56f3efaSBin Meng * 10*d56f3efaSBin Meng * Validated with U-Boot v2021.01 and Linux v5.10 mmc_spi driver 11*d56f3efaSBin Meng * 128e31bf38SMatthew Fernandez * This code is licensed under the GNU GPL v2. 136b620ca3SPaolo Bonzini * 146b620ca3SPaolo Bonzini * Contributions after 2012-01-13 are licensed under the terms of the 156b620ca3SPaolo Bonzini * GNU GPL, version 2 or (at your option) any later version. 16775616c3Spbrook */ 17775616c3Spbrook 180430891cSPeter Maydell #include "qemu/osdep.h" 199c17d615SPaolo Bonzini #include "sysemu/blockdev.h" 208fd06719SAlistair Francis #include "hw/ssi/ssi.h" 21d6454270SMarkus Armbruster #include "migration/vmstate.h" 22a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h" 23e3382ef0SSai Pavan Boddu #include "hw/sd/sd.h" 247673bb4cSCédric Le Goater #include "qapi/error.h" 252d174cc3SBin Meng #include "qemu/crc-ccitt.h" 260b8fa32fSMarkus Armbruster #include "qemu/module.h" 27db1015e9SEduardo Habkost #include "qom/object.h" 28775616c3Spbrook 29775616c3Spbrook //#define DEBUG_SSI_SD 1 30775616c3Spbrook 31775616c3Spbrook #ifdef DEBUG_SSI_SD 32001faf32SBlue Swirl #define DPRINTF(fmt, ...) \ 33001faf32SBlue Swirl do { printf("ssi_sd: " fmt , ## __VA_ARGS__); } while (0) 34001faf32SBlue Swirl #define BADF(fmt, ...) \ 35001faf32SBlue Swirl do { fprintf(stderr, "ssi_sd: error: " fmt , ## __VA_ARGS__); exit(1);} while (0) 36775616c3Spbrook #else 37001faf32SBlue Swirl #define DPRINTF(fmt, ...) do {} while(0) 38001faf32SBlue Swirl #define BADF(fmt, ...) \ 39001faf32SBlue Swirl do { fprintf(stderr, "ssi_sd: error: " fmt , ## __VA_ARGS__);} while (0) 40775616c3Spbrook #endif 41775616c3Spbrook 42775616c3Spbrook typedef enum { 432ccfd336SDr. David Alan Gilbert SSI_SD_CMD = 0, 44775616c3Spbrook SSI_SD_CMDARG, 45281c5c95SBin Meng SSI_SD_PREP_RESP, 46775616c3Spbrook SSI_SD_RESPONSE, 473a67cbe6SBin Meng SSI_SD_PREP_DATA, 48775616c3Spbrook SSI_SD_DATA_START, 49775616c3Spbrook SSI_SD_DATA_READ, 502d174cc3SBin Meng SSI_SD_DATA_CRC16, 515020e3cbSBin Meng SSI_SD_DATA_WRITE, 525020e3cbSBin Meng SSI_SD_SKIP_CRC16, 53775616c3Spbrook } ssi_sd_mode; 54775616c3Spbrook 55db1015e9SEduardo Habkost struct ssi_sd_state { 56ec7e429bSPhilippe Mathieu-Daudé SSIPeripheral ssidev; 572ccfd336SDr. David Alan Gilbert uint32_t mode; 58775616c3Spbrook int cmd; 59775616c3Spbrook uint8_t cmdarg[4]; 60775616c3Spbrook uint8_t response[5]; 612d174cc3SBin Meng uint16_t crc16; 621365d863SBin Meng int32_t read_bytes; 635020e3cbSBin Meng int32_t write_bytes; 642ccfd336SDr. David Alan Gilbert int32_t arglen; 652ccfd336SDr. David Alan Gilbert int32_t response_pos; 662ccfd336SDr. David Alan Gilbert int32_t stopping; 67c3abd913SPhilippe Mathieu-Daudé SDBus sdbus; 68db1015e9SEduardo Habkost }; 69775616c3Spbrook 708046d44fSPeter Maydell #define TYPE_SSI_SD "ssi-sd" 718063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(ssi_sd_state, SSI_SD) 728046d44fSPeter Maydell 73775616c3Spbrook /* State word bits. */ 74775616c3Spbrook #define SSI_SDR_LOCKED 0x0001 75775616c3Spbrook #define SSI_SDR_WP_ERASE 0x0002 76775616c3Spbrook #define SSI_SDR_ERROR 0x0004 77775616c3Spbrook #define SSI_SDR_CC_ERROR 0x0008 78775616c3Spbrook #define SSI_SDR_ECC_FAILED 0x0010 79775616c3Spbrook #define SSI_SDR_WP_VIOLATION 0x0020 80775616c3Spbrook #define SSI_SDR_ERASE_PARAM 0x0040 81775616c3Spbrook #define SSI_SDR_OUT_OF_RANGE 0x0080 82775616c3Spbrook #define SSI_SDR_IDLE 0x0100 83775616c3Spbrook #define SSI_SDR_ERASE_RESET 0x0200 84775616c3Spbrook #define SSI_SDR_ILLEGAL_COMMAND 0x0400 85775616c3Spbrook #define SSI_SDR_COM_CRC_ERROR 0x0800 86775616c3Spbrook #define SSI_SDR_ERASE_SEQ_ERROR 0x1000 87775616c3Spbrook #define SSI_SDR_ADDRESS_ERROR 0x2000 88775616c3Spbrook #define SSI_SDR_PARAMETER_ERROR 0x4000 89775616c3Spbrook 90*d56f3efaSBin Meng /* multiple block write */ 91*d56f3efaSBin Meng #define SSI_TOKEN_MULTI_WRITE 0xfc 92*d56f3efaSBin Meng /* terminate multiple block write */ 93*d56f3efaSBin Meng #define SSI_TOKEN_STOP_TRAN 0xfd 94bc1edaf2SBin Meng /* single block read/write, multiple block read */ 95bc1edaf2SBin Meng #define SSI_TOKEN_SINGLE 0xfe 96bc1edaf2SBin Meng 97bc1edaf2SBin Meng /* dummy value - don't care */ 98bc1edaf2SBin Meng #define SSI_DUMMY 0xff 99bc1edaf2SBin Meng 1005020e3cbSBin Meng /* data accepted */ 1015020e3cbSBin Meng #define DATA_RESPONSE_ACCEPTED 0x05 1025020e3cbSBin Meng 103ec7e429bSPhilippe Mathieu-Daudé static uint32_t ssi_sd_transfer(SSIPeripheral *dev, uint32_t val) 104775616c3Spbrook { 105213f63dfSPeter Maydell ssi_sd_state *s = SSI_SD(dev); 106*d56f3efaSBin Meng SDRequest request; 107*d56f3efaSBin Meng uint8_t longresp[16]; 108775616c3Spbrook 1091365d863SBin Meng /* 1101365d863SBin Meng * Special case: allow CMD12 (STOP TRANSMISSION) while reading data. 1111365d863SBin Meng * 1121365d863SBin Meng * See "Physical Layer Specification Version 8.00" chapter 7.5.2.2, 1131365d863SBin Meng * to avoid conflict between CMD12 response and next data block, 1141365d863SBin Meng * timing of CMD12 should be controlled as follows: 1151365d863SBin Meng * 1161365d863SBin Meng * - CMD12 issued at the timing that end bit of CMD12 and end bit of 1171365d863SBin Meng * data block is overlapped 1181365d863SBin Meng * - CMD12 issued after one clock cycle after host receives a token 1191365d863SBin Meng * (either Start Block token or Data Error token) 1201365d863SBin Meng * 1211365d863SBin Meng * We need to catch CMD12 in all of the data read states. 1221365d863SBin Meng */ 1231365d863SBin Meng if (s->mode >= SSI_SD_PREP_DATA && s->mode <= SSI_SD_DATA_CRC16) { 1241365d863SBin Meng if (val == 0x4c) { 125775616c3Spbrook s->mode = SSI_SD_CMD; 1261365d863SBin Meng /* There must be at least one byte delay before the card responds */ 127775616c3Spbrook s->stopping = 1; 128775616c3Spbrook } 1291365d863SBin Meng } 130775616c3Spbrook 131775616c3Spbrook switch (s->mode) { 132775616c3Spbrook case SSI_SD_CMD: 1335020e3cbSBin Meng switch (val) { 1345020e3cbSBin Meng case SSI_DUMMY: 135775616c3Spbrook DPRINTF("NULL command\n"); 136bc1edaf2SBin Meng return SSI_DUMMY; 1375020e3cbSBin Meng break; 1385020e3cbSBin Meng case SSI_TOKEN_SINGLE: 139*d56f3efaSBin Meng case SSI_TOKEN_MULTI_WRITE: 1405020e3cbSBin Meng DPRINTF("Start write block\n"); 1415020e3cbSBin Meng s->mode = SSI_SD_DATA_WRITE; 1425020e3cbSBin Meng return SSI_DUMMY; 143*d56f3efaSBin Meng case SSI_TOKEN_STOP_TRAN: 144*d56f3efaSBin Meng DPRINTF("Stop multiple write\n"); 145*d56f3efaSBin Meng 146*d56f3efaSBin Meng /* manually issue cmd12 to stop the transfer */ 147*d56f3efaSBin Meng request.cmd = 12; 148*d56f3efaSBin Meng request.arg = 0; 149*d56f3efaSBin Meng s->arglen = sdbus_do_command(&s->sdbus, &request, longresp); 150*d56f3efaSBin Meng if (s->arglen <= 0) { 151*d56f3efaSBin Meng s->arglen = 1; 152*d56f3efaSBin Meng /* a zero value indicates the card is busy */ 153*d56f3efaSBin Meng s->response[0] = 0; 154*d56f3efaSBin Meng DPRINTF("SD card busy\n"); 155*d56f3efaSBin Meng } else { 156*d56f3efaSBin Meng s->arglen = 1; 157*d56f3efaSBin Meng /* a non-zero value indicates the card is ready */ 158*d56f3efaSBin Meng s->response[0] = SSI_DUMMY; 159*d56f3efaSBin Meng } 160*d56f3efaSBin Meng 161*d56f3efaSBin Meng return SSI_DUMMY; 162775616c3Spbrook } 1635020e3cbSBin Meng 164775616c3Spbrook s->cmd = val & 0x3f; 165775616c3Spbrook s->mode = SSI_SD_CMDARG; 166775616c3Spbrook s->arglen = 0; 167bc1edaf2SBin Meng return SSI_DUMMY; 168775616c3Spbrook case SSI_SD_CMDARG: 169775616c3Spbrook if (s->arglen == 4) { 170775616c3Spbrook /* FIXME: Check CRC. */ 171775616c3Spbrook request.cmd = s->cmd; 172b3141c06SPhilippe Mathieu-Daudé request.arg = ldl_be_p(s->cmdarg); 173775616c3Spbrook DPRINTF("CMD%d arg 0x%08x\n", s->cmd, request.arg); 174c3abd913SPhilippe Mathieu-Daudé s->arglen = sdbus_do_command(&s->sdbus, &request, longresp); 175775616c3Spbrook if (s->arglen <= 0) { 176775616c3Spbrook s->arglen = 1; 177775616c3Spbrook s->response[0] = 4; 178775616c3Spbrook DPRINTF("SD command failed\n"); 179775616c3Spbrook } else if (s->cmd == 58) { 180775616c3Spbrook /* CMD58 returns R3 response (OCR) */ 181775616c3Spbrook DPRINTF("Returned OCR\n"); 182775616c3Spbrook s->arglen = 5; 183775616c3Spbrook s->response[0] = 1; 184775616c3Spbrook memcpy(&s->response[1], longresp, 4); 185775616c3Spbrook } else if (s->arglen != 4) { 186775616c3Spbrook BADF("Unexpected response to cmd %d\n", s->cmd); 187775616c3Spbrook /* Illegal command is about as near as we can get. */ 188775616c3Spbrook s->arglen = 1; 189775616c3Spbrook s->response[0] = 4; 190775616c3Spbrook } else { 191775616c3Spbrook /* All other commands return status. */ 192775616c3Spbrook uint32_t cardstatus; 193775616c3Spbrook uint16_t status; 194775616c3Spbrook /* CMD13 returns a 2-byte statuse work. Other commands 195775616c3Spbrook only return the first byte. */ 196775616c3Spbrook s->arglen = (s->cmd == 13) ? 2 : 1; 197b3141c06SPhilippe Mathieu-Daudé cardstatus = ldl_be_p(longresp); 198775616c3Spbrook status = 0; 199775616c3Spbrook if (((cardstatus >> 9) & 0xf) < 4) 200775616c3Spbrook status |= SSI_SDR_IDLE; 201775616c3Spbrook if (cardstatus & ERASE_RESET) 202775616c3Spbrook status |= SSI_SDR_ERASE_RESET; 203775616c3Spbrook if (cardstatus & ILLEGAL_COMMAND) 204775616c3Spbrook status |= SSI_SDR_ILLEGAL_COMMAND; 205775616c3Spbrook if (cardstatus & COM_CRC_ERROR) 206775616c3Spbrook status |= SSI_SDR_COM_CRC_ERROR; 207775616c3Spbrook if (cardstatus & ERASE_SEQ_ERROR) 208775616c3Spbrook status |= SSI_SDR_ERASE_SEQ_ERROR; 209775616c3Spbrook if (cardstatus & ADDRESS_ERROR) 210775616c3Spbrook status |= SSI_SDR_ADDRESS_ERROR; 211775616c3Spbrook if (cardstatus & CARD_IS_LOCKED) 212775616c3Spbrook status |= SSI_SDR_LOCKED; 213775616c3Spbrook if (cardstatus & (LOCK_UNLOCK_FAILED | WP_ERASE_SKIP)) 214775616c3Spbrook status |= SSI_SDR_WP_ERASE; 215775616c3Spbrook if (cardstatus & SD_ERROR) 216775616c3Spbrook status |= SSI_SDR_ERROR; 217775616c3Spbrook if (cardstatus & CC_ERROR) 218775616c3Spbrook status |= SSI_SDR_CC_ERROR; 219775616c3Spbrook if (cardstatus & CARD_ECC_FAILED) 220775616c3Spbrook status |= SSI_SDR_ECC_FAILED; 221775616c3Spbrook if (cardstatus & WP_VIOLATION) 222775616c3Spbrook status |= SSI_SDR_WP_VIOLATION; 223775616c3Spbrook if (cardstatus & ERASE_PARAM) 224775616c3Spbrook status |= SSI_SDR_ERASE_PARAM; 225775616c3Spbrook if (cardstatus & (OUT_OF_RANGE | CID_CSD_OVERWRITE)) 226775616c3Spbrook status |= SSI_SDR_OUT_OF_RANGE; 227775616c3Spbrook /* ??? Don't know what Parameter Error really means, so 228775616c3Spbrook assume it's set if the second byte is nonzero. */ 229775616c3Spbrook if (status & 0xff) 230775616c3Spbrook status |= SSI_SDR_PARAMETER_ERROR; 231775616c3Spbrook s->response[0] = status >> 8; 232775616c3Spbrook s->response[1] = status; 233775616c3Spbrook DPRINTF("Card status 0x%02x\n", status); 234775616c3Spbrook } 235281c5c95SBin Meng s->mode = SSI_SD_PREP_RESP; 236775616c3Spbrook s->response_pos = 0; 237775616c3Spbrook } else { 238775616c3Spbrook s->cmdarg[s->arglen++] = val; 239775616c3Spbrook } 240bc1edaf2SBin Meng return SSI_DUMMY; 241281c5c95SBin Meng case SSI_SD_PREP_RESP: 242281c5c95SBin Meng DPRINTF("Prepare card response (Ncr)\n"); 243281c5c95SBin Meng s->mode = SSI_SD_RESPONSE; 244bc1edaf2SBin Meng return SSI_DUMMY; 245775616c3Spbrook case SSI_SD_RESPONSE: 246775616c3Spbrook if (s->stopping) { 247775616c3Spbrook s->stopping = 0; 248bc1edaf2SBin Meng return SSI_DUMMY; 249775616c3Spbrook } 250775616c3Spbrook if (s->response_pos < s->arglen) { 251775616c3Spbrook DPRINTF("Response 0x%02x\n", s->response[s->response_pos]); 252775616c3Spbrook return s->response[s->response_pos++]; 253775616c3Spbrook } 254c3abd913SPhilippe Mathieu-Daudé if (sdbus_data_ready(&s->sdbus)) { 255775616c3Spbrook DPRINTF("Data read\n"); 256775616c3Spbrook s->mode = SSI_SD_DATA_START; 257775616c3Spbrook } else { 258775616c3Spbrook DPRINTF("End of command\n"); 259775616c3Spbrook s->mode = SSI_SD_CMD; 260775616c3Spbrook } 261bc1edaf2SBin Meng return SSI_DUMMY; 2623a67cbe6SBin Meng case SSI_SD_PREP_DATA: 2633a67cbe6SBin Meng DPRINTF("Prepare data block (Nac)\n"); 2643a67cbe6SBin Meng s->mode = SSI_SD_DATA_START; 265bc1edaf2SBin Meng return SSI_DUMMY; 266775616c3Spbrook case SSI_SD_DATA_START: 267775616c3Spbrook DPRINTF("Start read block\n"); 268775616c3Spbrook s->mode = SSI_SD_DATA_READ; 2692d174cc3SBin Meng s->response_pos = 0; 270bc1edaf2SBin Meng return SSI_TOKEN_SINGLE; 271775616c3Spbrook case SSI_SD_DATA_READ: 2728467f622SPhilippe Mathieu-Daudé val = sdbus_read_byte(&s->sdbus); 2731365d863SBin Meng s->read_bytes++; 2742d174cc3SBin Meng s->crc16 = crc_ccitt_false(s->crc16, (uint8_t *)&val, 1); 2751365d863SBin Meng if (!sdbus_data_ready(&s->sdbus) || s->read_bytes == 512) { 276775616c3Spbrook DPRINTF("Data read end\n"); 2772d174cc3SBin Meng s->mode = SSI_SD_DATA_CRC16; 2782d174cc3SBin Meng } 2792d174cc3SBin Meng return val; 2802d174cc3SBin Meng case SSI_SD_DATA_CRC16: 2812d174cc3SBin Meng val = (s->crc16 & 0xff00) >> 8; 2822d174cc3SBin Meng s->crc16 <<= 8; 2832d174cc3SBin Meng s->response_pos++; 2842d174cc3SBin Meng if (s->response_pos == 2) { 2852d174cc3SBin Meng DPRINTF("CRC16 read end\n"); 2861365d863SBin Meng if (s->read_bytes == 512 && s->cmd != 17) { 2871365d863SBin Meng s->mode = SSI_SD_PREP_DATA; 2881365d863SBin Meng } else { 289775616c3Spbrook s->mode = SSI_SD_CMD; 2901365d863SBin Meng } 2911365d863SBin Meng s->read_bytes = 0; 2922d174cc3SBin Meng s->response_pos = 0; 293775616c3Spbrook } 294775616c3Spbrook return val; 2955020e3cbSBin Meng case SSI_SD_DATA_WRITE: 2965020e3cbSBin Meng sdbus_write_byte(&s->sdbus, val); 2975020e3cbSBin Meng s->write_bytes++; 2985020e3cbSBin Meng if (!sdbus_receive_ready(&s->sdbus) || s->write_bytes == 512) { 2995020e3cbSBin Meng DPRINTF("Data write end\n"); 3005020e3cbSBin Meng s->mode = SSI_SD_SKIP_CRC16; 3015020e3cbSBin Meng s->response_pos = 0; 3025020e3cbSBin Meng } 3035020e3cbSBin Meng return val; 3045020e3cbSBin Meng case SSI_SD_SKIP_CRC16: 3055020e3cbSBin Meng /* we don't verify the crc16 */ 3065020e3cbSBin Meng s->response_pos++; 3075020e3cbSBin Meng if (s->response_pos == 2) { 3085020e3cbSBin Meng DPRINTF("CRC16 receive end\n"); 3095020e3cbSBin Meng s->mode = SSI_SD_RESPONSE; 3105020e3cbSBin Meng s->write_bytes = 0; 3115020e3cbSBin Meng s->arglen = 1; 3125020e3cbSBin Meng s->response[0] = DATA_RESPONSE_ACCEPTED; 3135020e3cbSBin Meng s->response_pos = 0; 3145020e3cbSBin Meng } 3155020e3cbSBin Meng return SSI_DUMMY; 316775616c3Spbrook } 317775616c3Spbrook /* Should never happen. */ 318bc1edaf2SBin Meng return SSI_DUMMY; 319775616c3Spbrook } 320775616c3Spbrook 3212ccfd336SDr. David Alan Gilbert static int ssi_sd_post_load(void *opaque, int version_id) 32223e39294Spbrook { 32323e39294Spbrook ssi_sd_state *s = (ssi_sd_state *)opaque; 32423e39294Spbrook 3255020e3cbSBin Meng if (s->mode > SSI_SD_SKIP_CRC16) { 32623e39294Spbrook return -EINVAL; 3272ccfd336SDr. David Alan Gilbert } 328a9c380dbSMichael S. Tsirkin if (s->mode == SSI_SD_CMDARG && 329a9c380dbSMichael S. Tsirkin (s->arglen < 0 || s->arglen >= ARRAY_SIZE(s->cmdarg))) { 330a9c380dbSMichael S. Tsirkin return -EINVAL; 331a9c380dbSMichael S. Tsirkin } 332a9c380dbSMichael S. Tsirkin if (s->mode == SSI_SD_RESPONSE && 333a9c380dbSMichael S. Tsirkin (s->response_pos < 0 || s->response_pos >= ARRAY_SIZE(s->response) || 334a9c380dbSMichael S. Tsirkin (!s->stopping && s->arglen > ARRAY_SIZE(s->response)))) { 335a9c380dbSMichael S. Tsirkin return -EINVAL; 336a9c380dbSMichael S. Tsirkin } 33723e39294Spbrook 33823e39294Spbrook return 0; 33923e39294Spbrook } 34023e39294Spbrook 3412ccfd336SDr. David Alan Gilbert static const VMStateDescription vmstate_ssi_sd = { 3422ccfd336SDr. David Alan Gilbert .name = "ssi_sd", 3435020e3cbSBin Meng .version_id = 7, 3445020e3cbSBin Meng .minimum_version_id = 7, 3452ccfd336SDr. David Alan Gilbert .post_load = ssi_sd_post_load, 3462ccfd336SDr. David Alan Gilbert .fields = (VMStateField []) { 3472ccfd336SDr. David Alan Gilbert VMSTATE_UINT32(mode, ssi_sd_state), 3482ccfd336SDr. David Alan Gilbert VMSTATE_INT32(cmd, ssi_sd_state), 3492ccfd336SDr. David Alan Gilbert VMSTATE_UINT8_ARRAY(cmdarg, ssi_sd_state, 4), 3502ccfd336SDr. David Alan Gilbert VMSTATE_UINT8_ARRAY(response, ssi_sd_state, 5), 3512d174cc3SBin Meng VMSTATE_UINT16(crc16, ssi_sd_state), 3521365d863SBin Meng VMSTATE_INT32(read_bytes, ssi_sd_state), 3535020e3cbSBin Meng VMSTATE_INT32(write_bytes, ssi_sd_state), 3542ccfd336SDr. David Alan Gilbert VMSTATE_INT32(arglen, ssi_sd_state), 3552ccfd336SDr. David Alan Gilbert VMSTATE_INT32(response_pos, ssi_sd_state), 3562ccfd336SDr. David Alan Gilbert VMSTATE_INT32(stopping, ssi_sd_state), 357ec7e429bSPhilippe Mathieu-Daudé VMSTATE_SSI_PERIPHERAL(ssidev, ssi_sd_state), 3582ccfd336SDr. David Alan Gilbert VMSTATE_END_OF_LIST() 3592ccfd336SDr. David Alan Gilbert } 3602ccfd336SDr. David Alan Gilbert }; 3612ccfd336SDr. David Alan Gilbert 362ec7e429bSPhilippe Mathieu-Daudé static void ssi_sd_realize(SSIPeripheral *d, Error **errp) 363775616c3Spbrook { 364de1b3800SVladimir Sementsov-Ogievskiy ERRP_GUARD(); 365213f63dfSPeter Maydell ssi_sd_state *s = SSI_SD(d); 366c3abd913SPhilippe Mathieu-Daudé DeviceState *carddev; 36713839974SMarkus Armbruster DriveInfo *dinfo; 368775616c3Spbrook 369c3abd913SPhilippe Mathieu-Daudé qbus_create_inplace(&s->sdbus, sizeof(s->sdbus), TYPE_SD_BUS, 370c3abd913SPhilippe Mathieu-Daudé DEVICE(d), "sd-bus"); 371c3abd913SPhilippe Mathieu-Daudé 372c3abd913SPhilippe Mathieu-Daudé /* Create and plug in the sd card */ 373af9e40aaSMarkus Armbruster /* FIXME use a qdev drive property instead of drive_get_next() */ 37413839974SMarkus Armbruster dinfo = drive_get_next(IF_SD); 3753e80f690SMarkus Armbruster carddev = qdev_new(TYPE_SD_CARD); 376c3abd913SPhilippe Mathieu-Daudé if (dinfo) { 3770c0e618dSMarkus Armbruster if (!qdev_prop_set_drive_err(carddev, "drive", 378de1b3800SVladimir Sementsov-Ogievskiy blk_by_legacy_dinfo(dinfo), errp)) { 379709dfb64SVladimir Sementsov-Ogievskiy goto fail; 380c3abd913SPhilippe Mathieu-Daudé } 381709dfb64SVladimir Sementsov-Ogievskiy } 382709dfb64SVladimir Sementsov-Ogievskiy 383de1b3800SVladimir Sementsov-Ogievskiy if (!object_property_set_bool(OBJECT(carddev), "spi", true, errp)) { 384709dfb64SVladimir Sementsov-Ogievskiy goto fail; 385709dfb64SVladimir Sementsov-Ogievskiy } 386709dfb64SVladimir Sementsov-Ogievskiy 387de1b3800SVladimir Sementsov-Ogievskiy if (!qdev_realize_and_unref(carddev, BUS(&s->sdbus), errp)) { 388709dfb64SVladimir Sementsov-Ogievskiy goto fail; 3894f8a066bSKevin Wolf } 390709dfb64SVladimir Sementsov-Ogievskiy 391709dfb64SVladimir Sementsov-Ogievskiy return; 392709dfb64SVladimir Sementsov-Ogievskiy 393709dfb64SVladimir Sementsov-Ogievskiy fail: 394de1b3800SVladimir Sementsov-Ogievskiy error_prepend(errp, "failed to init SD card: "); 395775616c3Spbrook } 3965493e33fSPaul Brook 3978046d44fSPeter Maydell static void ssi_sd_reset(DeviceState *dev) 3988046d44fSPeter Maydell { 3998046d44fSPeter Maydell ssi_sd_state *s = SSI_SD(dev); 4008046d44fSPeter Maydell 4018046d44fSPeter Maydell s->mode = SSI_SD_CMD; 4028046d44fSPeter Maydell s->cmd = 0; 4038046d44fSPeter Maydell memset(s->cmdarg, 0, sizeof(s->cmdarg)); 4048046d44fSPeter Maydell memset(s->response, 0, sizeof(s->response)); 4052d174cc3SBin Meng s->crc16 = 0; 4061365d863SBin Meng s->read_bytes = 0; 4075020e3cbSBin Meng s->write_bytes = 0; 4088046d44fSPeter Maydell s->arglen = 0; 4098046d44fSPeter Maydell s->response_pos = 0; 4108046d44fSPeter Maydell s->stopping = 0; 4118046d44fSPeter Maydell } 4128046d44fSPeter Maydell 413cd6c4cf2SAnthony Liguori static void ssi_sd_class_init(ObjectClass *klass, void *data) 414cd6c4cf2SAnthony Liguori { 4152ccfd336SDr. David Alan Gilbert DeviceClass *dc = DEVICE_CLASS(klass); 416ec7e429bSPhilippe Mathieu-Daudé SSIPeripheralClass *k = SSI_PERIPHERAL_CLASS(klass); 417cd6c4cf2SAnthony Liguori 4187673bb4cSCédric Le Goater k->realize = ssi_sd_realize; 419cd6c4cf2SAnthony Liguori k->transfer = ssi_sd_transfer; 4208120e714SPeter A. G. Crosthwaite k->cs_polarity = SSI_CS_LOW; 4212ccfd336SDr. David Alan Gilbert dc->vmsd = &vmstate_ssi_sd; 4228046d44fSPeter Maydell dc->reset = ssi_sd_reset; 42361e9e3cbSMarkus Armbruster /* Reason: init() method uses drive_get_next() */ 42461e9e3cbSMarkus Armbruster dc->user_creatable = false; 425cd6c4cf2SAnthony Liguori } 426cd6c4cf2SAnthony Liguori 4278c43a6f0SAndreas Färber static const TypeInfo ssi_sd_info = { 4288046d44fSPeter Maydell .name = TYPE_SSI_SD, 429ec7e429bSPhilippe Mathieu-Daudé .parent = TYPE_SSI_PERIPHERAL, 43039bffca2SAnthony Liguori .instance_size = sizeof(ssi_sd_state), 431cd6c4cf2SAnthony Liguori .class_init = ssi_sd_class_init, 4325493e33fSPaul Brook }; 4335493e33fSPaul Brook 43483f7d43aSAndreas Färber static void ssi_sd_register_types(void) 4355493e33fSPaul Brook { 43639bffca2SAnthony Liguori type_register_static(&ssi_sd_info); 4375493e33fSPaul Brook } 4385493e33fSPaul Brook 43983f7d43aSAndreas Färber type_init(ssi_sd_register_types) 440