mmc: dw_mmc: support fifo mode in dwc mmc driver
some soc(rk3036 etc) use dw_mmc but do not have internal dma, so we implement fifo mode to read and write data. Signed-off-by: Lin Huang <hl@rock-chips.com> Acked-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
		
							parent
							
								
									f382eb833a
								
							
						
					
					
						commit
						a65f51b978
					
				| 
						 | 
				
			
			@ -94,12 +94,21 @@ static void dwmci_prepare_data(struct dwmci_host *host,
 | 
			
		|||
	dwmci_writel(host, DWMCI_BYTCNT, data->blocksize * data->blocks);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int dwmci_data_transfer(struct dwmci_host *host)
 | 
			
		||||
static int dwmci_data_transfer(struct dwmci_host *host, struct mmc_data *data)
 | 
			
		||||
{
 | 
			
		||||
	int ret = 0;
 | 
			
		||||
	unsigned int timeout = 240000;
 | 
			
		||||
	u32 mask;
 | 
			
		||||
	u32 timeout = 240000;
 | 
			
		||||
	u32 mask, size, i, len = 0;
 | 
			
		||||
	u32 *buf = NULL;
 | 
			
		||||
	ulong start = get_timer(0);
 | 
			
		||||
	u32 fifo_depth = (((host->fifoth_val & RX_WMARK_MASK) >>
 | 
			
		||||
			    RX_WMARK_SHIFT) + 1) * 2;
 | 
			
		||||
 | 
			
		||||
	size = data->blocksize * data->blocks / 4;
 | 
			
		||||
	if (data->flags == MMC_DATA_READ)
 | 
			
		||||
		buf = (unsigned int *)data->dest;
 | 
			
		||||
	else
 | 
			
		||||
		buf = (unsigned int *)data->src;
 | 
			
		||||
 | 
			
		||||
	for (;;) {
 | 
			
		||||
		mask = dwmci_readl(host, DWMCI_RINTSTS);
 | 
			
		||||
| 
						 | 
				
			
			@ -110,6 +119,36 @@ static int dwmci_data_transfer(struct dwmci_host *host)
 | 
			
		|||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (host->fifo_mode && size) {
 | 
			
		||||
			if (data->flags == MMC_DATA_READ) {
 | 
			
		||||
				if ((dwmci_readl(host, DWMCI_RINTSTS) &&
 | 
			
		||||
				     DWMCI_INTMSK_RXDR)) {
 | 
			
		||||
					len = dwmci_readl(host, DWMCI_STATUS);
 | 
			
		||||
					len = (len >> DWMCI_FIFO_SHIFT) &
 | 
			
		||||
						    DWMCI_FIFO_MASK;
 | 
			
		||||
					for (i = 0; i < len; i++)
 | 
			
		||||
						*buf++ =
 | 
			
		||||
						dwmci_readl(host, DWMCI_DATA);
 | 
			
		||||
					dwmci_writel(host, DWMCI_RINTSTS,
 | 
			
		||||
						     DWMCI_INTMSK_RXDR);
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				if ((dwmci_readl(host, DWMCI_RINTSTS) &&
 | 
			
		||||
				     DWMCI_INTMSK_TXDR)) {
 | 
			
		||||
					len = dwmci_readl(host, DWMCI_STATUS);
 | 
			
		||||
					len = fifo_depth - ((len >>
 | 
			
		||||
						   DWMCI_FIFO_SHIFT) &
 | 
			
		||||
						   DWMCI_FIFO_MASK);
 | 
			
		||||
					for (i = 0; i < len; i++)
 | 
			
		||||
						dwmci_writel(host, DWMCI_DATA,
 | 
			
		||||
							     *buf++);
 | 
			
		||||
					dwmci_writel(host, DWMCI_RINTSTS,
 | 
			
		||||
						     DWMCI_INTMSK_TXDR);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			size = size > len ? (size - len) : 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* Data arrived correctly. */
 | 
			
		||||
		if (mask & DWMCI_INTMSK_DTO) {
 | 
			
		||||
			ret = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -165,6 +204,12 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
 | 
			
		|||
	dwmci_writel(host, DWMCI_RINTSTS, DWMCI_INTMSK_ALL);
 | 
			
		||||
 | 
			
		||||
	if (data) {
 | 
			
		||||
		if (host->fifo_mode) {
 | 
			
		||||
			dwmci_writel(host, DWMCI_BLKSIZ, data->blocksize);
 | 
			
		||||
			dwmci_writel(host, DWMCI_BYTCNT,
 | 
			
		||||
				     data->blocksize * data->blocks);
 | 
			
		||||
			dwmci_wait_reset(host, DWMCI_CTRL_FIFO_RESET);
 | 
			
		||||
		} else {
 | 
			
		||||
			if (data->flags == MMC_DATA_READ) {
 | 
			
		||||
				bounce_buffer_start(&bbstate, (void*)data->dest,
 | 
			
		||||
						data->blocksize *
 | 
			
		||||
| 
						 | 
				
			
			@ -177,6 +222,7 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
 | 
			
		|||
			dwmci_prepare_data(host, data, cur_idmac,
 | 
			
		||||
					   bbstate.bounce_buffer);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dwmci_writel(host, DWMCI_CMDARG, cmd->cmdarg);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -249,13 +295,16 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	if (data) {
 | 
			
		||||
		ret = dwmci_data_transfer(host);
 | 
			
		||||
		ret = dwmci_data_transfer(host, data);
 | 
			
		||||
 | 
			
		||||
		/* only dma mode need it */
 | 
			
		||||
		if (!host->fifo_mode) {
 | 
			
		||||
			ctrl = dwmci_readl(host, DWMCI_CTRL);
 | 
			
		||||
			ctrl &= ~(DWMCI_DMA_EN);
 | 
			
		||||
			dwmci_writel(host, DWMCI_CTRL, ctrl);
 | 
			
		||||
			bounce_buffer_stop(&bbstate);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	udelay(100);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -105,6 +105,8 @@
 | 
			
		|||
 | 
			
		||||
/* Status Register */
 | 
			
		||||
#define DWMCI_BUSY		(1 << 9)
 | 
			
		||||
#define DWMCI_FIFO_MASK		0x1ff
 | 
			
		||||
#define DWMCI_FIFO_SHIFT	17
 | 
			
		||||
 | 
			
		||||
/* FIFOTH Register */
 | 
			
		||||
#define MSIZE(x)		((x) << 28)
 | 
			
		||||
| 
						 | 
				
			
			@ -180,6 +182,9 @@ struct dwmci_host {
 | 
			
		|||
	unsigned int (*get_mmc_clk)(struct dwmci_host *host, uint freq);
 | 
			
		||||
 | 
			
		||||
	struct mmc_config cfg;
 | 
			
		||||
 | 
			
		||||
	/* use fifo mode to read and write data */
 | 
			
		||||
	bool fifo_mode;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct dwmci_idmac {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue