[U-Boot] [PATCH] ftsdc010: improve performance and capability

Macpaul Lin macpaul at andestech.com
Thu Nov 3 10:35:41 CET 2011


This patch improve the performance by spliting flag examination code
in ftsdc010_send_cmd() into 3 functions.
This patch also reordered the function which made better capability to
some high performance cards against to the next version of ftsdc010
hardware.

Signed-off-by: Macpaul Lin <macpaul at andestech.com>
---
 drivers/mmc/ftsdc010_esdhc.c |  172 +++++++++++++++++++++++-------------------
 1 files changed, 93 insertions(+), 79 deletions(-)

diff --git a/drivers/mmc/ftsdc010_esdhc.c b/drivers/mmc/ftsdc010_esdhc.c
index e38dd87..538800b 100644
--- a/drivers/mmc/ftsdc010_esdhc.c
+++ b/drivers/mmc/ftsdc010_esdhc.c
@@ -90,8 +90,13 @@ static void ftsdc010_pio_read(struct mmc_host *host, char *buf, unsigned int siz
 
 	while (size) {
 		status = readl(&host->reg->status);
+		debug("%s: size: %08x\n", __func__, size);
 
 		if (status & FTSDC010_STATUS_FIFO_ORUN) {
+
+			debug("%s: FIFO OVERRUN: sta: %08x\n",
+					__func__, status);
+
 			fifo = host->fifo_len > size ?
 				size : host->fifo_len;
 
@@ -146,7 +151,7 @@ static void ftsdc010_pio_write(struct mmc_host *host, const char *buf,
 	while (size) {
 		status = readl(&host->reg->status);
 
-		if (status & FTSDC010_STATUS_FIFO_ORUN) {
+		if (status & FTSDC010_STATUS_FIFO_URUN) {
 			fifo = host->fifo_len > size ?
 				size : host->fifo_len;
 
@@ -158,7 +163,6 @@ static void ftsdc010_pio_write(struct mmc_host *host, const char *buf,
 				writel(*ptr, &host->reg->dwr);
 				ptr++;
 			}
-
 		} else {
 			udelay(1);
 			if (++retry >= FTSDC010_PIO_RETRY) {
@@ -169,56 +173,19 @@ static void ftsdc010_pio_write(struct mmc_host *host, const char *buf,
 	}
 }
 
-static int ftsdc010_pio_check_status(struct mmc *mmc, struct mmc_cmd *cmd,
+static int ftsdc010_check_rsp(struct mmc *mmc, struct mmc_cmd *cmd,
 			struct mmc_data *data)
 {
 	struct mmc_host *host = mmc->priv;
-
 	unsigned int sta, clear;
-	unsigned int i;
-
-	/* check response and hardware status */
-	clear = 0;
-
-	/* chech CMD_SEND */
-	for (i = 0; i < FTSDC010_CMD_RETRY; i++) {
-		sta = readl(&host->reg->status);
-		/* Command Complete */
-		if (sta & FTSDC010_STATUS_CMD_SEND) {
-			if (!data)
-				clear |= FTSDC010_CLR_CMD_SEND;
-			break;
-		}
-	}
-
-	if (i > FTSDC010_CMD_RETRY) {
-		printf("%s: send command timeout\n", __func__);
-		return TIMEOUT;
-	}
 
-	/* debug: print status register and command index*/
-	debug("sta: %08x cmd %d\n", sta, cmd->cmdidx);
-
-	/* handle data FIFO */
-	if ((sta & FTSDC010_STATUS_FIFO_ORUN) ||
-		(sta & FTSDC010_STATUS_FIFO_URUN)) {
-
-		/* Wrong DATA FIFO Flag */
-		if (data == NULL)
-			printf("%s, data fifo wrong: sta: %08x cmd %d\n",
-				__func__, sta, cmd->cmdidx);
-
-		if (sta & FTSDC010_STATUS_FIFO_ORUN)
-			clear |= FTSDC010_STATUS_FIFO_ORUN;
-		if (sta & FTSDC010_STATUS_FIFO_URUN)
-			clear |= FTSDC010_STATUS_FIFO_URUN;
-	}
+	sta = readl(&host->reg->status);
+	debug("%s: sta: %08x cmd %d\n", __func__, sta, cmd->cmdidx);
 
 	/* check RSP TIMEOUT or FAIL */
 	if (sta & FTSDC010_STATUS_RSP_TIMEOUT) {
 		/* RSP TIMEOUT */
-		debug("%s: RSP timeout: sta: %08x cmd %d\n",
-				__func__, sta, cmd->cmdidx);
+		debug("%s: RSP timeout: sta: %08x\n", __func__, sta);
 
 		clear |= FTSDC010_CLR_RSP_TIMEOUT;
 		writel(clear, &host->reg->clr);
@@ -226,47 +193,62 @@ static int ftsdc010_pio_check_status(struct mmc *mmc, struct mmc_cmd *cmd,
 		return TIMEOUT;
 	} else if (sta & FTSDC010_STATUS_RSP_CRC_FAIL) {
 		/* clear response fail bit */
-		debug("%s: RSP CRC FAIL: sta: %08x cmd %d\n",
-				__func__, sta, cmd->cmdidx);
+		debug("%s: RSP CRC FAIL: sta: %08x\n", __func__, sta);
 
 		clear |= FTSDC010_CLR_RSP_CRC_FAIL;
 		writel(clear, &host->reg->clr);
 
-		return 0;
+		return COMM_ERR;
 	} else if (sta & FTSDC010_STATUS_RSP_CRC_OK) {
 
 		/* clear response CRC OK bit */
 		clear |= FTSDC010_CLR_RSP_CRC_OK;
 	}
 
+	writel(clear, &host->reg->clr);
+	return 0;
+}
+
+static int ftsdc010_check_data(struct mmc *mmc, struct mmc_cmd *cmd,
+			struct mmc_data *data)
+{
+	struct mmc_host *host = mmc->priv;
+	unsigned int sta, clear;
+
+	sta = readl(&host->reg->status);
+	debug("%s: sta: %08x cmd %d\n", __func__, sta, cmd->cmdidx);
+
 	/* check DATA TIMEOUT or FAIL */
 	if (data) {
+		if (sta & FTSDC010_STATUS_DATA_END) {
+			/* Transfer Complete */
+			clear |= FTSDC010_STATUS_DATA_END;
+		}
+
+		if (sta & FTSDC010_STATUS_DATA_CRC_OK) {
+			/* Data CRC_OK */
+			clear |= FTSDC010_STATUS_DATA_CRC_OK;
+		}
+
 		if (sta & FTSDC010_STATUS_DATA_TIMEOUT) {
 			/* DATA TIMEOUT */
-			debug("%s: DATA TIMEOUT: sta: %08x\n",
-					__func__, sta);
+			debug("%s: DATA TIMEOUT: sta: %08x\n", __func__, sta);
 
 			clear |= FTSDC010_STATUS_DATA_TIMEOUT;
 			writel(sta, &host->reg->clr);
+
 			return TIMEOUT;
 		} else if (sta & FTSDC010_STATUS_DATA_CRC_FAIL) {
 			/* Error Interrupt */
-			debug("%s: DATA CRC FAIL: sta: %08x\n",
-					__func__, sta);
+			debug("%s: DATA CRC FAIL: sta: %08x\n", __func__, sta);
 
 			clear |= FTSDC010_STATUS_DATA_CRC_FAIL;
 			writel(clear, &host->reg->clr);
 
-			return 0;
-		} else if (sta & FTSDC010_STATUS_DATA_END) {
-			/* Transfer Complete */
-			clear |= FTSDC010_STATUS_DATA_END;
+			return COMM_ERR;
 		}
+		writel(clear, &host->reg->clr);
 	}
-
-	/* transaction is success and clear status register */
-	writel(clear, &host->reg->clr);
-
 	return 0;
 }
 
@@ -281,6 +263,9 @@ static int ftsdc010_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
 	unsigned int ccon;
 	unsigned int mask, tmpmask;
 	unsigned int ret;
+	unsigned int sta, clear, i;
+
+	ret = 0;
 
 	if (data)
 		mask = FTSDC010_INT_MASK_RSP_TIMEOUT;
@@ -290,13 +275,8 @@ static int ftsdc010_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
 		mask = FTSDC010_INT_MASK_CMD_SEND;
 
 	/* write argu reg */
-	debug("%s: cmd->arg: %08x\n", __func__, cmd->cmdarg);
 	writel(cmd->cmdarg, &host->reg->argu);
 
-	/* setup cmd reg */
-	debug("cmd: %d\n", cmd->cmdidx);
-	debug("resp: %08x\n", cmd->resp_type);
-
 	/* setup commnad */
 	ccon = FTSDC010_CMD_IDX(cmd->cmdidx);
 
@@ -342,6 +322,45 @@ static int ftsdc010_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
 	writel(ccon, &host->reg->cmd);
 	udelay(4*FTSDC010_DELAY_UNIT);
 
+	/* check CMD_SEND */
+	/*
+	 * Note:
+	 *	Do not clear FTSDC010_CLR_CMD_SEND flag here,
+	 *	(write FTSDC010_CLR_CMD_SEND bit to clear register)
+	 *	it will made the driver becomes very slow.
+	 *	If the operation hasn't been finished, hardware will
+	 *	clear this bit automatically.
+	 */
+	for (i = 0; i < FTSDC010_CMD_RETRY; i++) {
+		sta = readl(&host->reg->status);
+		/* Command Complete */
+		if (sta & FTSDC010_STATUS_CMD_SEND) {
+			if (!data)
+				clear |= FTSDC010_CLR_CMD_SEND;
+			break;
+		}
+	}
+
+	if (i > FTSDC010_CMD_RETRY) {
+		printf("%s: send command timeout\n", __func__);
+		return TIMEOUT;
+	}
+
+	/* check rsp status */
+	ret = ftsdc010_check_rsp(mmc, cmd, data);
+	if (ret)
+		return ret;
+
+	/* read response if we have RSP_OK */
+	if (ccon & FTSDC010_CMD_LONG_RSP) {
+		cmd->response[0] = readl(&host->reg->rsp3);
+		cmd->response[1] = readl(&host->reg->rsp2);
+		cmd->response[2] = readl(&host->reg->rsp1);
+		cmd->response[3] = readl(&host->reg->rsp0);
+	} else {
+		cmd->response[0] = readl(&host->reg->rsp0);
+	}
+
 	/* read/write data */
 	if (data && (data->flags & MMC_DATA_READ)) {
 		ftsdc010_pio_read(host, data->dest,
@@ -351,19 +370,11 @@ static int ftsdc010_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
 				data->blocksize * data->blocks);
 	}
 
-	/* pio check response status */
-	ret = ftsdc010_pio_check_status(mmc, cmd, data);
-	if (!ret) {
-		/* if it is long response */
-		if (ccon & FTSDC010_CMD_LONG_RSP) {
-			cmd->response[0] = readl(&host->reg->rsp3);
-			cmd->response[1] = readl(&host->reg->rsp2);
-			cmd->response[2] = readl(&host->reg->rsp1);
-			cmd->response[3] = readl(&host->reg->rsp0);
-
-		} else {
-			cmd->response[0] = readl(&host->reg->rsp0);
-		}
+	/* check data status */
+	if (data) {
+		ret = ftsdc010_check_data(mmc, cmd, data);
+		if (ret)
+			return ret;
 	}
 
 	udelay(FTSDC010_DELAY_UNIT);
@@ -431,8 +442,6 @@ static int ftsdc010_setup_data(struct mmc *mmc, struct mmc_data *data)
 	/* always reset fifo since last transfer may fail */
 	dcon |= FTSDC010_DCR_FIFO_RST;
 
-	/* handle sdio */
-	dcon = data->blocksize | data->blocks << 15;
 	if (data->blocks > 1)
 		dcon |= FTSDC010_SDIO_CTRL1_SDIO_BLK_MODE;
 #endif
@@ -518,7 +527,7 @@ static void ftsdc010_set_clk(struct mmc *mmc)
 				break;
 		}
 
-		debug("%s: computed real_rete: %x, clk_div: %x\n",
+		debug("%s: computed real_rate: %x, clk_div: %x\n",
 			 __func__, real_rate, clk_div);
 
 		if (clk_div > 127)
@@ -579,6 +588,7 @@ static void ftsdc010_set_ios(struct mmc *mmc)
 static void ftsdc010_reset(struct mmc_host *host)
 {
 	unsigned int timeout;
+	unsigned int sta;
 
 	/* Do SDC_RST: Software reset for all register */
 	writel(FTSDC010_CMD_SDC_RST, &host->reg->cmd);
@@ -598,6 +608,10 @@ static void ftsdc010_reset(struct mmc_host *host)
 		timeout--;
 		udelay(10*FTSDC010_DELAY_UNIT);
 	}
+
+	sta = readl(&host->reg->status);
+	if (sta & FTSDC010_STATUS_CARD_CHANGE)
+		writel(FTSDC010_CLR_CARD_CHANGE, &host->reg->clr);
 }
 
 static int ftsdc010_core_init(struct mmc *mmc)
-- 
1.7.3.5



More information about the U-Boot mailing list