Beispiel #1
0
int rtsx_pci_read_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 *val)
{
    int err, i, finished = 0;
    u16 data;
    u8 *ptr, tmp;

    rtsx_pci_init_cmd(pcr);

    rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYADDR, 0xFF, addr);
    rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYRWCTL, 0xFF, 0x80);

    err = rtsx_pci_send_cmd(pcr, 100);
    if (err < 0)
        return err;

    for (i = 0; i < 100000; i++) {
        err = rtsx_pci_read_register(pcr, PHYRWCTL, &tmp);
        if (err < 0)
            return err;

        if (!(tmp & 0x80)) {
            finished = 1;
            break;
        }
    }

    if (!finished)
        return -ETIMEDOUT;

    rtsx_pci_init_cmd(pcr);

    rtsx_pci_add_cmd(pcr, READ_REG_CMD, PHYDATA0, 0, 0);
    rtsx_pci_add_cmd(pcr, READ_REG_CMD, PHYDATA1, 0, 0);

    err = rtsx_pci_send_cmd(pcr, 100);
    if (err < 0)
        return err;

    ptr = rtsx_pci_get_cmd_data(pcr);
    data = ((u16)ptr[1] << 8) | ptr[0];

    if (val)
        *val = data;

    return 0;
}
Beispiel #2
0
static void sd_print_debug_regs(struct realtek_pci_sdmmc *host)
{
	struct rtsx_pcr *pcr = host->pcr;
	u16 i;
	u8 *ptr;

	/* Print SD host internal registers */
	rtsx_pci_init_cmd(pcr);
	for (i = 0xFDA0; i <= 0xFDAE; i++)
		rtsx_pci_add_cmd(pcr, READ_REG_CMD, i, 0, 0);
	for (i = 0xFD52; i <= 0xFD69; i++)
		rtsx_pci_add_cmd(pcr, READ_REG_CMD, i, 0, 0);
	rtsx_pci_send_cmd(pcr, 100);

	ptr = rtsx_pci_get_cmd_data(pcr);
	for (i = 0xFDA0; i <= 0xFDAE; i++)
		dev_dbg(sdmmc_dev(host), "0x%04X: 0x%02x\n", i, *(ptr++));
	for (i = 0xFD52; i <= 0xFD69; i++)
		dev_dbg(sdmmc_dev(host), "0x%04X: 0x%02x\n", i, *(ptr++));
}
Beispiel #3
0
static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host,
		struct mmc_command *cmd)
{
	struct rtsx_pcr *pcr = host->pcr;
	u8 cmd_idx = (u8)cmd->opcode;
	u32 arg = cmd->arg;
	int err = 0;
	int timeout = 100;
	int i;
	u8 *ptr;
	int stat_idx = 0;
	u8 rsp_type;
	int rsp_len = 5;
	bool clock_toggled = false;

	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;
		rsp_len = 0;
		break;
	case MMC_RSP_R1:
		rsp_type = SD_RSP_TYPE_R1;
		break;
	case MMC_RSP_R1 & ~MMC_RSP_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;
		rsp_len = 16;
		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 = 3000;

	if (cmd->opcode == SD_SWITCH_VOLTAGE) {
		err = rtsx_pci_write_register(pcr, SD_BUS_STAT,
				0xFF, SD_CLK_TOGGLE_EN);
		if (err < 0)
			goto out;

		clock_toggled = true;
	}

	rtsx_pci_init_cmd(pcr);

	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD0, 0xFF, 0x40 | cmd_idx);
	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD1, 0xFF, (u8)(arg >> 24));
	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD2, 0xFF, (u8)(arg >> 16));
	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD3, 0xFF, (u8)(arg >> 8));
	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD4, 0xFF, (u8)arg);

	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG2, 0xFF, rsp_type);
	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_DATA_SOURCE,
			0x01, PINGPONG_BUFFER);
	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_TRANSFER,
			0xFF, SD_TM_CMD_RSP | SD_TRANSFER_START);
	rtsx_pci_add_cmd(pcr, 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_pci_add_cmd(pcr, 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_pci_add_cmd(pcr, READ_REG_CMD, (u16)i, 0, 0);
		stat_idx = 5;
	}

	rtsx_pci_add_cmd(pcr, READ_REG_CMD, SD_STAT1, 0, 0);

	err = rtsx_pci_send_cmd(pcr, timeout);
	if (err < 0) {
		sd_print_debug_regs(host);
		sd_clear_error(host);
		dev_dbg(sdmmc_dev(host),
			"rtsx_pci_send_cmd error (err = %d)\n", err);
		goto out;
	}

	if (rsp_type == SD_RSP_TYPE_R0) {
		err = 0;
		goto out;
	}

	/* Eliminate returned value of CHECK_REG_CMD */
	ptr = rtsx_pci_get_cmd_data(pcr) + 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;

	if (err && clock_toggled)
		rtsx_pci_write_register(pcr, SD_BUS_STAT,
				SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, 0);
}
Beispiel #4
0
static int ms_read_bytes(struct realtek_pci_ms *host, u8 tpc,
		u8 cfg, u8 cnt, u8 *data, u8 *int_reg)
{
	struct rtsx_pcr *pcr = host->pcr;
	int err, i;
	u8 *ptr;

	dev_dbg(ms_dev(host), "%s: tpc = 0x%02x\n", __func__, tpc);

	if (!data)
		return -EINVAL;

	rtsx_pci_init_cmd(pcr);

	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_TPC, 0xFF, tpc);
	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_BYTE_CNT, 0xFF, cnt);
	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, cfg);
	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_DATA_SOURCE,
			0x01, PINGPONG_BUFFER);

	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_TRANSFER,
			0xFF, MS_TRANSFER_START | MS_TM_READ_BYTES);
	rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, MS_TRANSFER,
			MS_TRANSFER_END, MS_TRANSFER_END);
	for (i = 0; i < cnt - 1; i++)
		rtsx_pci_add_cmd(pcr, READ_REG_CMD, PPBUF_BASE2 + i, 0, 0);
	if (cnt % 2)
		rtsx_pci_add_cmd(pcr, READ_REG_CMD, PPBUF_BASE2 + cnt, 0, 0);
	else
		rtsx_pci_add_cmd(pcr, READ_REG_CMD,
				PPBUF_BASE2 + cnt - 1, 0, 0);
	if (int_reg)
		rtsx_pci_add_cmd(pcr, READ_REG_CMD, MS_TRANS_CFG, 0, 0);

	err = rtsx_pci_send_cmd(pcr, 5000);
	if (err < 0) {
		u8 val;

		rtsx_pci_read_register(pcr, MS_TRANS_CFG, &val);
		dev_dbg(ms_dev(host), "MS_TRANS_CFG: 0x%02x\n", val);

		if (int_reg)
			*int_reg = val & 0x0F;

		ms_print_debug_regs(host);

		ms_clear_error(host);

		if (!(tpc & 0x08)) {
			if (val & MS_CRC16_ERR)
				return -EIO;
		} else {
			if (!(val & 0x80)) {
				if (val & (MS_INT_ERR | MS_INT_CMDNK))
					return -EIO;
			}
		}

		return -ETIMEDOUT;
	}

	ptr = rtsx_pci_get_cmd_data(pcr) + 1;
	for (i = 0; i < cnt; i++)
		data[i] = *ptr++;

	if (int_reg)
		*int_reg = *ptr & 0x0F;

	return 0;
}