in host/rtsx_usb_sdmmc.c [285:447]
static void sd_send_cmd_get_rsp(struct rtsx_usb_sdmmc *host,
struct mmc_command *cmd)
{
struct rtsx_ucr *ucr = host->ucr;
u8 cmd_idx = (u8)cmd->opcode;
u32 arg = cmd->arg;
int err = 0;
int timeout = 100;
int i;
u8 *ptr;
int stat_idx = 0;
int len = 2;
u8 rsp_type;
dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD %d, arg = 0x%08x\n",
__func__, cmd_idx, arg);
/* Response type:
* R0
* R1, R5, R6, R7
* R1b
* R2
* R3, R4
*/
switch (mmc_resp_type(cmd)) {
case MMC_RSP_NONE:
rsp_type = SD_RSP_TYPE_R0;
break;
case MMC_RSP_R1:
rsp_type = SD_RSP_TYPE_R1;
break;
case MMC_RSP_R1_NO_CRC:
rsp_type = SD_RSP_TYPE_R1 | SD_NO_CHECK_CRC7;
break;
case MMC_RSP_R1B:
rsp_type = SD_RSP_TYPE_R1b;
break;
case MMC_RSP_R2:
rsp_type = SD_RSP_TYPE_R2;
break;
case MMC_RSP_R3:
rsp_type = SD_RSP_TYPE_R3;
break;
default:
dev_dbg(sdmmc_dev(host), "cmd->flag is not valid\n");
err = -EINVAL;
goto out;
}
if (rsp_type == SD_RSP_TYPE_R1b)
timeout = cmd->busy_timeout ? cmd->busy_timeout : 3000;
if (cmd->opcode == SD_SWITCH_VOLTAGE) {
err = rtsx_usb_write_register(ucr, SD_BUS_STAT,
SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP,
SD_CLK_TOGGLE_EN);
if (err)
goto out;
}
rtsx_usb_init_cmd(ucr);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CMD0, 0xFF, 0x40 | cmd_idx);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CMD1, 0xFF, (u8)(arg >> 24));
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CMD2, 0xFF, (u8)(arg >> 16));
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CMD3, 0xFF, (u8)(arg >> 8));
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CMD4, 0xFF, (u8)arg);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CFG2, 0xFF, rsp_type);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_DATA_SOURCE,
0x01, PINGPONG_BUFFER);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_TRANSFER,
0xFF, SD_TM_CMD_RSP | SD_TRANSFER_START);
rtsx_usb_add_cmd(ucr, CHECK_REG_CMD, SD_TRANSFER,
SD_TRANSFER_END | SD_STAT_IDLE,
SD_TRANSFER_END | SD_STAT_IDLE);
if (rsp_type == SD_RSP_TYPE_R2) {
/* Read data from ping-pong buffer */
for (i = PPBUF_BASE2; i < PPBUF_BASE2 + 16; i++)
rtsx_usb_add_cmd(ucr, READ_REG_CMD, (u16)i, 0, 0);
stat_idx = 16;
} else if (rsp_type != SD_RSP_TYPE_R0) {
/* Read data from SD_CMDx registers */
for (i = SD_CMD0; i <= SD_CMD4; i++)
rtsx_usb_add_cmd(ucr, READ_REG_CMD, (u16)i, 0, 0);
stat_idx = 5;
}
len += stat_idx;
rtsx_usb_add_cmd(ucr, READ_REG_CMD, SD_STAT1, 0, 0);
err = rtsx_usb_send_cmd(ucr, MODE_CR, 100);
if (err) {
dev_dbg(sdmmc_dev(host),
"rtsx_usb_send_cmd error (err = %d)\n", err);
goto out;
}
err = rtsx_usb_get_rsp(ucr, len, timeout);
if (err || (ucr->rsp_buf[0] & SD_TRANSFER_ERR)) {
sd_print_debug_regs(host);
sd_clear_error(host);
if (!err) {
dev_dbg(sdmmc_dev(host),
"Transfer failed (SD_TRANSFER = %02x)\n",
ucr->rsp_buf[0]);
err = -EIO;
} else {
dev_dbg(sdmmc_dev(host),
"rtsx_usb_get_rsp failed (err = %d)\n", err);
}
goto out;
}
if (rsp_type == SD_RSP_TYPE_R0) {
err = 0;
goto out;
}
/* Skip result of CHECK_REG_CMD */
ptr = ucr->rsp_buf + 1;
/* Check (Start,Transmission) bit of Response */
if ((ptr[0] & 0xC0) != 0) {
err = -EILSEQ;
dev_dbg(sdmmc_dev(host), "Invalid response bit\n");
goto out;
}
/* Check CRC7 */
if (!(rsp_type & SD_NO_CHECK_CRC7)) {
if (ptr[stat_idx] & SD_CRC7_ERR) {
err = -EILSEQ;
dev_dbg(sdmmc_dev(host), "CRC7 error\n");
goto out;
}
}
if (rsp_type == SD_RSP_TYPE_R2) {
/*
* The controller offloads the last byte {CRC-7, end bit 1'b1}
* of response type R2. Assign dummy CRC, 0, and end bit to the
* byte(ptr[16], goes into the LSB of resp[3] later).
*/
ptr[16] = 1;
for (i = 0; i < 4; i++) {
cmd->resp[i] = get_unaligned_be32(ptr + 1 + i * 4);
dev_dbg(sdmmc_dev(host), "cmd->resp[%d] = 0x%08x\n",
i, cmd->resp[i]);
}
} else {
cmd->resp[0] = get_unaligned_be32(ptr + 1);
dev_dbg(sdmmc_dev(host), "cmd->resp[0] = 0x%08x\n",
cmd->resp[0]);
}
out:
cmd->error = err;
}