Exemplo n.º 1
0
int write_single_block(struct sd_card *card,
		uint32_t blknr,
		unsigned char * buf)
{
	uint32_t count;
	uint32_t value;

	count = 0;

	set32(base_address + MMCHS_SD_IE, MMCHS_SD_IE_BWR_ENABLE,
			MMCHS_SD_IE_BWR_ENABLE_ENABLE);
	//set32(base_address + MMCHS_SD_IE, 0xfff , 0xfff);
	set32(base_address + MMCHS_SD_BLK, MMCHS_SD_BLK_BLEN, 512);

	/* Set timeout */
	set32(base_address + MMCHS_SD_SYSCTL, MMCHS_SD_SYSCTL_DTO,
			MMCHS_SD_SYSCTL_DTO_2POW27);

	if (mmchs_send_cmd(MMCHS_SD_CMD_INDX_CMD(MMC_WRITE_BLOCK_SINGLE) /* write single block */
	| MMCHS_SD_CMD_DP_DATA /* Command with data transfer */
	| MMCHS_SD_CMD_RSP_TYPE_48B /* type (R1b) */
	| MMCHS_SD_CMD_MSBS_SINGLE /* single block */
	| MMCHS_SD_CMD_DDIR_WRITE /* write to the card */
	, blknr)) {
		return 1;
	}

	/* Wait for the MMCHS_SD_IE_BWR_ENABLE interrupt */
	while ((read32(base_address + MMCHS_SD_STAT) & MMCHS_SD_IE_BWR_ENABLE) == 0) {
		count++;
	}

	if (!(read32(base_address + MMCHS_SD_PSTATE) & MMCHS_SD_PSTATE_BWE_EN)) {
		return 1; /* not ready to write data */
	}
	for (count = 0; count < 512; count += 4) {
		*((char*) &value) = buf[count];
		*((char*) &value + 1) = buf[count + 1];
		*((char*) &value + 2) = buf[count + 2];
		*((char*) &value + 3) = buf[count + 3];
		write32(base_address + MMCHS_SD_DATA, value);
	}

	/* Wait for TC */
	while ((read32(base_address + MMCHS_SD_STAT) & MMCHS_SD_IE_TC_ENABLE_ENABLE)
			== 0) {
		count++;
	}
	write32(base_address + MMCHS_SD_STAT, MMCHS_SD_IE_TC_ENABLE_CLEAR);
	write32(base_address + MMCHS_SD_STAT, MMCHS_SD_IE_CC_ENABLE_CLEAR);/* finished.  */
	/* clear the bwr interrupt FIXME is this right when writing?*/
	write32(base_address + MMCHS_SD_STAT, MMCHS_SD_IE_BWR_ENABLE_CLEAR);
	set32(base_address + MMCHS_SD_IE, MMCHS_SD_IE_BWR_ENABLE,
			MMCHS_SD_IE_BWR_ENABLE_DISABLE);
	return 0;
}
Exemplo n.º 2
0
int read_single_block(struct sd_card *card,
		uint32_t blknr,
		unsigned char * buf)
{
	uint32_t count;
	uint32_t value;

	count = 0;

	set32(base_address + MMCHS_SD_IE, MMCHS_SD_IE_BRR_ENABLE,
			MMCHS_SD_IE_BRR_ENABLE_ENABLE);

	set32(base_address + MMCHS_SD_BLK, MMCHS_SD_BLK_BLEN, 512);

	if (mmchs_send_cmd(MMCHS_SD_CMD_INDX_CMD(MMC_READ_BLOCK_SINGLE) /* read single block */
	| MMCHS_SD_CMD_DP_DATA /* Command with data transfer */
	| MMCHS_SD_CMD_RSP_TYPE_48B /* type (R1) */
	| MMCHS_SD_CMD_MSBS_SINGLE /* single block */
	| MMCHS_SD_CMD_DDIR_READ /* read data from card */
	, blknr)) {
		return 1;
	}

	while ((read32(base_address + MMCHS_SD_STAT)
			& MMCHS_SD_IE_BRR_ENABLE_ENABLE) == 0) {
		count++;
	}

	if (!(read32(base_address + MMCHS_SD_PSTATE) & MMCHS_SD_PSTATE_BRE_EN)) {
		return 1; /* We are not allowed to read data from the data buffer */
	}

	for (count = 0; count < 512; count += 4) {
		value = read32(base_address + MMCHS_SD_DATA);
		buf[count] = *((char*) &value);
		buf[count + 1] = *((char*) &value + 1);
		buf[count + 2] = *((char*) &value + 2);
		buf[count + 3] = *((char*) &value + 3);
	}

	/* Wait for TC */

	while ((read32(base_address + MMCHS_SD_STAT) & MMCHS_SD_IE_TC_ENABLE_ENABLE)
			== 0) {
		count++;
	}
	write32(base_address + MMCHS_SD_STAT, MMCHS_SD_IE_TC_ENABLE_CLEAR);

	/* clear and disable the bbr interrupt */
	write32(base_address + MMCHS_SD_STAT, MMCHS_SD_IE_BRR_ENABLE_CLEAR);
	set32(base_address + MMCHS_SD_IE, MMCHS_SD_IE_BRR_ENABLE,
			MMCHS_SD_IE_BRR_ENABLE_DISABLE);
	return 0;
}
Exemplo n.º 3
0
int mmc_send_cmd(struct mmc_command *c)
{

	/* convert the command to a hsmmc command */
	int ret;
	uint32_t cmd, arg;
	cmd = MMCHS_SD_CMD_INDX_CMD(c->cmd);
	arg = c->args;

	switch (c->resp_type) {
		case RESP_LEN_48_CHK_BUSY:
			cmd |= MMCHS_SD_CMD_RSP_TYPE_48B_BUSY;
			break;
		case RESP_LEN_48:
			cmd |= MMCHS_SD_CMD_RSP_TYPE_48B;
			break;
		case RESP_LEN_136:
			cmd |= MMCHS_SD_CMD_RSP_TYPE_136B;
			break;
		case NO_RESPONSE:
			cmd |= MMCHS_SD_CMD_RSP_TYPE_NO_RESP;
			break;
		default:
			return 1;
	}

	ret = mmchs_send_cmd(cmd, arg);

	/* copy response into cmd->resp	 */
	switch (c->resp_type) {
		case RESP_LEN_48_CHK_BUSY:
		case RESP_LEN_48:
			c->resp[0] = read32(base_address + MMCHS_SD_RSP10);
			break;
		case RESP_LEN_136:
			c->resp[0] = read32(base_address + MMCHS_SD_RSP10);
			c->resp[1] = read32(base_address + MMCHS_SD_RSP32);
			c->resp[2] = read32(base_address + MMCHS_SD_RSP54);
			c->resp[3] = read32(base_address + MMCHS_SD_RSP76);
			break;
		case NO_RESPONSE:
			break;
		default:
			return 1;
	}

	return ret;
}
Exemplo n.º 4
0
int
mmc_send_cmd(struct mmc_command *c)
{

	/* convert the command to a hsmmc command */
	int ret;
	uint32_t cmd, arg;
	uint32_t count;
	uint32_t value;
	cmd = MMCHS_SD_CMD_INDX_CMD(c->cmd);
	arg = c->args;

	switch (c->resp_type) {
	case RESP_LEN_48_CHK_BUSY:
		cmd |= MMCHS_SD_CMD_RSP_TYPE_48B_BUSY;
		break;
	case RESP_LEN_48:
		cmd |= MMCHS_SD_CMD_RSP_TYPE_48B;
		break;
	case RESP_LEN_136:
		cmd |= MMCHS_SD_CMD_RSP_TYPE_136B;
		break;
	case NO_RESPONSE:
		cmd |= MMCHS_SD_CMD_RSP_TYPE_NO_RESP;
		break;
	default:
		return 1;
	}

	/* read single block */
	if (c->cmd == MMC_READ_BLOCK_SINGLE) {
		cmd |= MMCHS_SD_CMD_DP_DATA;	/* Command with data transfer */
		cmd |= MMCHS_SD_CMD_MSBS_SINGLE;	/* single block */
		cmd |= MMCHS_SD_CMD_DDIR_READ;	/* read data from card */

	}

	/* write single block */
	if (c->cmd == MMC_WRITE_BLOCK_SINGLE) {
		cmd |= MMCHS_SD_CMD_DP_DATA;	/* Command with data transfer */
		cmd |= MMCHS_SD_CMD_MSBS_SINGLE;	/* single block */
		cmd |= MMCHS_SD_CMD_DDIR_WRITE;	/* write to the card */
	}

	/* check we are in a sane state */
	if ((read32(base_address + MMCHS_SD_STAT) & 0xffffu)) {
		mmc_log_warn(&log, "%s, interrupt already raised stat  %08x\n",
		    __FUNCTION__, read32(base_address + MMCHS_SD_STAT));
		write32(base_address + MMCHS_SD_STAT,
		    MMCHS_SD_IE_CC_ENABLE_CLEAR);
	}

	if (cmd & MMCHS_SD_CMD_DP_DATA) {
		if (cmd & MMCHS_SD_CMD_DDIR_READ) {
			/* if we are going to read enable the buffer ready
			 * interrupt */
			set32(base_address + MMCHS_SD_IE,
			    MMCHS_SD_IE_BRR_ENABLE,
			    MMCHS_SD_IE_BRR_ENABLE_ENABLE);
		} else {
			set32(base_address + MMCHS_SD_IE,
			    MMCHS_SD_IE_BWR_ENABLE,
			    MMCHS_SD_IE_BWR_ENABLE_ENABLE);
		}
	}

	set32(base_address + MMCHS_SD_BLK, MMCHS_SD_BLK_BLEN, 512);

	ret = mmchs_send_cmd(cmd, arg);

	/* copy response into cmd->resp */
	switch (c->resp_type) {
	case RESP_LEN_48_CHK_BUSY:
	case RESP_LEN_48:
		c->resp[0] = read32(base_address + MMCHS_SD_RSP10);
		break;
	case RESP_LEN_136:
		c->resp[0] = read32(base_address + MMCHS_SD_RSP10);
		c->resp[1] = read32(base_address + MMCHS_SD_RSP32);
		c->resp[2] = read32(base_address + MMCHS_SD_RSP54);
		c->resp[3] = read32(base_address + MMCHS_SD_RSP76);
		break;
	case NO_RESPONSE:
		break;
	default:
		return 1;
	}

	if (cmd & MMCHS_SD_CMD_DP_DATA) {
		count = 0;
		assert(c->data_len);
		if (cmd & MMCHS_SD_CMD_DDIR_READ) {
			if (intr_wait(MMCHS_SD_IE_BRR_ENABLE_ENABLE)) {
				intr_assert(MMCHS_SD_IE_BRR_ENABLE_ENABLE);
				mmc_log_warn(&log,
				    "Timeout waiting for interrupt\n");
				return 1;
			}

			if (!(read32(base_address +
				    MMCHS_SD_PSTATE) & MMCHS_SD_PSTATE_BRE_EN))
			{
				mmc_log_warn(&log,
				    "Problem BRE should be true\n");
				return 1;	/* We are not allowed to read
						 * data from the data buffer */
			}

			for (count = 0; count < c->data_len; count += 4) {
				value = read32(base_address + MMCHS_SD_DATA);
				c->data[count] = *((char *) &value);
				c->data[count + 1] = *((char *) &value + 1);
				c->data[count + 2] = *((char *) &value + 2);
				c->data[count + 3] = *((char *) &value + 3);
			}

			/* Wait for TC */
			if (intr_wait(MMCHS_SD_IE_TC_ENABLE_ENABLE)) {
				intr_assert(MMCHS_SD_IE_TC_ENABLE_ENABLE);
				mmc_log_warn(&log,
				    "Timeout waiting for interrupt\n");
				return 1;
			}

			write32(base_address + MMCHS_SD_STAT,
			    MMCHS_SD_IE_TC_ENABLE_CLEAR);

			/* clear and disable the bbr interrupt */
			write32(base_address + MMCHS_SD_STAT,
			    MMCHS_SD_IE_BRR_ENABLE_CLEAR);
			set32(base_address + MMCHS_SD_IE,
			    MMCHS_SD_IE_BRR_ENABLE,
			    MMCHS_SD_IE_BRR_ENABLE_DISABLE);
		} else {
			/* Wait for the MMCHS_SD_IE_BWR_ENABLE interrupt */
			if (intr_wait(MMCHS_SD_IE_BWR_ENABLE)) {
				intr_assert(MMCHS_SD_IE_BWR_ENABLE);
				mmc_log_warn(&log, "WFI failed\n");
				return 1;
			}
			/* clear the interrupt directly */
			intr_assert(MMCHS_SD_IE_BWR_ENABLE);

			if (!(read32(base_address +
				    MMCHS_SD_PSTATE) & MMCHS_SD_PSTATE_BWE_EN))
			{
				mmc_log_warn(&log,
				    "Error expected Buffer to be write enabled\n");
				return 1;	/* not ready to write data */
			}

			for (count = 0; count < 512; count += 4) {
				while (!(read32(base_address +
					    MMCHS_SD_PSTATE) &
					MMCHS_SD_PSTATE_BWE_EN)) {
					mmc_log_trace(&log,
					    "Error expected Buffer to be write enabled(%d)\n",
					    count);
				}
				*((char *) &value) = c->data[count];
				*((char *) &value + 1) = c->data[count + 1];
				*((char *) &value + 2) = c->data[count + 2];
				*((char *) &value + 3) = c->data[count + 3];
				write32(base_address + MMCHS_SD_DATA, value);
			}

			/* Wait for TC */
			if (intr_wait(MMCHS_SD_IE_TC_ENABLE_CLEAR)) {
				intr_assert(MMCHS_SD_IE_TC_ENABLE_CLEAR);
				mmc_log_warn(&log,
				    "(Write) Timeout waiting for transfer complete\n");
				return 1;
			}
			intr_assert(MMCHS_SD_IE_TC_ENABLE_CLEAR);
			set32(base_address + MMCHS_SD_IE,
			    MMCHS_SD_IE_BWR_ENABLE,
			    MMCHS_SD_IE_BWR_ENABLE_DISABLE);

		}
	}
	return ret;
}