static void sd_send_cmd_get_rsp()

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;
}