xref: /rk3399_ARM-atf/drivers/synopsys/emmc/dw_mmc.c (revision 2a82a9c95f6c06079f58d69315544a6b49cf64a4)
15dbdb7daSHaojian Zhuang /*
25dbdb7daSHaojian Zhuang  * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
35dbdb7daSHaojian Zhuang  *
482cb2c1aSdp-arm  * SPDX-License-Identifier: BSD-3-Clause
55dbdb7daSHaojian Zhuang  */
65dbdb7daSHaojian Zhuang 
75dbdb7daSHaojian Zhuang #include <arch.h>
85dbdb7daSHaojian Zhuang #include <arch_helpers.h>
95dbdb7daSHaojian Zhuang #include <assert.h>
105dbdb7daSHaojian Zhuang #include <debug.h>
115dbdb7daSHaojian Zhuang #include <delay_timer.h>
125dbdb7daSHaojian Zhuang #include <dw_mmc.h>
135dbdb7daSHaojian Zhuang #include <errno.h>
147a8b4830SHaojian Zhuang #include <mmc.h>
155dbdb7daSHaojian Zhuang #include <mmio.h>
165dbdb7daSHaojian Zhuang #include <string.h>
175dbdb7daSHaojian Zhuang 
185dbdb7daSHaojian Zhuang #define DWMMC_CTRL			(0x00)
195dbdb7daSHaojian Zhuang #define CTRL_IDMAC_EN			(1 << 25)
205dbdb7daSHaojian Zhuang #define CTRL_DMA_EN			(1 << 5)
215dbdb7daSHaojian Zhuang #define CTRL_INT_EN			(1 << 4)
225dbdb7daSHaojian Zhuang #define CTRL_DMA_RESET			(1 << 2)
235dbdb7daSHaojian Zhuang #define CTRL_FIFO_RESET			(1 << 1)
245dbdb7daSHaojian Zhuang #define CTRL_RESET			(1 << 0)
255dbdb7daSHaojian Zhuang #define CTRL_RESET_ALL			(CTRL_DMA_RESET | CTRL_FIFO_RESET | \
265dbdb7daSHaojian Zhuang 					 CTRL_RESET)
275dbdb7daSHaojian Zhuang 
285dbdb7daSHaojian Zhuang #define DWMMC_PWREN			(0x04)
295dbdb7daSHaojian Zhuang #define DWMMC_CLKDIV			(0x08)
305dbdb7daSHaojian Zhuang #define DWMMC_CLKSRC			(0x0c)
315dbdb7daSHaojian Zhuang #define DWMMC_CLKENA			(0x10)
325dbdb7daSHaojian Zhuang #define DWMMC_TMOUT			(0x14)
335dbdb7daSHaojian Zhuang #define DWMMC_CTYPE			(0x18)
345dbdb7daSHaojian Zhuang #define CTYPE_8BIT			(1 << 16)
355dbdb7daSHaojian Zhuang #define CTYPE_4BIT			(1)
365dbdb7daSHaojian Zhuang #define CTYPE_1BIT			(0)
375dbdb7daSHaojian Zhuang 
385dbdb7daSHaojian Zhuang #define DWMMC_BLKSIZ			(0x1c)
395dbdb7daSHaojian Zhuang #define DWMMC_BYTCNT			(0x20)
405dbdb7daSHaojian Zhuang #define DWMMC_INTMASK			(0x24)
415dbdb7daSHaojian Zhuang #define INT_EBE				(1 << 15)
425dbdb7daSHaojian Zhuang #define INT_SBE				(1 << 13)
435dbdb7daSHaojian Zhuang #define INT_HLE				(1 << 12)
445dbdb7daSHaojian Zhuang #define INT_FRUN			(1 << 11)
455dbdb7daSHaojian Zhuang #define INT_DRT				(1 << 9)
465dbdb7daSHaojian Zhuang #define INT_RTO				(1 << 8)
475dbdb7daSHaojian Zhuang #define INT_DCRC			(1 << 7)
485dbdb7daSHaojian Zhuang #define INT_RCRC			(1 << 6)
495dbdb7daSHaojian Zhuang #define INT_RXDR			(1 << 5)
505dbdb7daSHaojian Zhuang #define INT_TXDR			(1 << 4)
515dbdb7daSHaojian Zhuang #define INT_DTO				(1 << 3)
525dbdb7daSHaojian Zhuang #define INT_CMD_DONE			(1 << 2)
535dbdb7daSHaojian Zhuang #define INT_RE				(1 << 1)
545dbdb7daSHaojian Zhuang 
555dbdb7daSHaojian Zhuang #define DWMMC_CMDARG			(0x28)
565dbdb7daSHaojian Zhuang #define DWMMC_CMD			(0x2c)
575dbdb7daSHaojian Zhuang #define CMD_START			(1 << 31)
585dbdb7daSHaojian Zhuang #define CMD_USE_HOLD_REG		(1 << 29)	/* 0 if SDR50/100 */
595dbdb7daSHaojian Zhuang #define CMD_UPDATE_CLK_ONLY		(1 << 21)
605dbdb7daSHaojian Zhuang #define CMD_SEND_INIT			(1 << 15)
615dbdb7daSHaojian Zhuang #define CMD_STOP_ABORT_CMD		(1 << 14)
625dbdb7daSHaojian Zhuang #define CMD_WAIT_PRVDATA_COMPLETE	(1 << 13)
635dbdb7daSHaojian Zhuang #define CMD_WRITE			(1 << 10)
645dbdb7daSHaojian Zhuang #define CMD_DATA_TRANS_EXPECT		(1 << 9)
655dbdb7daSHaojian Zhuang #define CMD_CHECK_RESP_CRC		(1 << 8)
665dbdb7daSHaojian Zhuang #define CMD_RESP_LEN			(1 << 7)
675dbdb7daSHaojian Zhuang #define CMD_RESP_EXPECT			(1 << 6)
685dbdb7daSHaojian Zhuang #define CMD(x)				(x & 0x3f)
695dbdb7daSHaojian Zhuang 
705dbdb7daSHaojian Zhuang #define DWMMC_RESP0			(0x30)
715dbdb7daSHaojian Zhuang #define DWMMC_RESP1			(0x34)
725dbdb7daSHaojian Zhuang #define DWMMC_RESP2			(0x38)
735dbdb7daSHaojian Zhuang #define DWMMC_RESP3			(0x3c)
745dbdb7daSHaojian Zhuang #define DWMMC_RINTSTS			(0x44)
755dbdb7daSHaojian Zhuang #define DWMMC_STATUS			(0x48)
765dbdb7daSHaojian Zhuang #define STATUS_DATA_BUSY		(1 << 9)
775dbdb7daSHaojian Zhuang 
785dbdb7daSHaojian Zhuang #define DWMMC_FIFOTH			(0x4c)
795dbdb7daSHaojian Zhuang #define FIFOTH_TWMARK(x)		(x & 0xfff)
805dbdb7daSHaojian Zhuang #define FIFOTH_RWMARK(x)		((x & 0x1ff) << 16)
815dbdb7daSHaojian Zhuang #define FIFOTH_DMA_BURST_SIZE(x)	((x & 0x7) << 28)
825dbdb7daSHaojian Zhuang 
835dbdb7daSHaojian Zhuang #define DWMMC_DEBNCE			(0x64)
845dbdb7daSHaojian Zhuang #define DWMMC_BMOD			(0x80)
855dbdb7daSHaojian Zhuang #define BMOD_ENABLE			(1 << 7)
865dbdb7daSHaojian Zhuang #define BMOD_FB				(1 << 1)
875dbdb7daSHaojian Zhuang #define BMOD_SWRESET			(1 << 0)
885dbdb7daSHaojian Zhuang 
895dbdb7daSHaojian Zhuang #define DWMMC_DBADDR			(0x88)
905dbdb7daSHaojian Zhuang #define DWMMC_IDSTS			(0x8c)
915dbdb7daSHaojian Zhuang #define DWMMC_IDINTEN			(0x90)
925dbdb7daSHaojian Zhuang #define DWMMC_CARDTHRCTL		(0x100)
935dbdb7daSHaojian Zhuang #define CARDTHRCTL_RD_THR(x)		((x & 0xfff) << 16)
945dbdb7daSHaojian Zhuang #define CARDTHRCTL_RD_THR_EN		(1 << 0)
955dbdb7daSHaojian Zhuang 
965dbdb7daSHaojian Zhuang #define IDMAC_DES0_DIC			(1 << 1)
975dbdb7daSHaojian Zhuang #define IDMAC_DES0_LD			(1 << 2)
985dbdb7daSHaojian Zhuang #define IDMAC_DES0_FS			(1 << 3)
995dbdb7daSHaojian Zhuang #define IDMAC_DES0_CH			(1 << 4)
1005dbdb7daSHaojian Zhuang #define IDMAC_DES0_ER			(1 << 5)
1015dbdb7daSHaojian Zhuang #define IDMAC_DES0_CES			(1 << 30)
1025dbdb7daSHaojian Zhuang #define IDMAC_DES0_OWN			(1 << 31)
1035dbdb7daSHaojian Zhuang #define IDMAC_DES1_BS1(x)		((x) & 0x1fff)
1045dbdb7daSHaojian Zhuang #define IDMAC_DES2_BS2(x)		(((x) & 0x1fff) << 13)
1055dbdb7daSHaojian Zhuang 
1065dbdb7daSHaojian Zhuang #define DWMMC_DMA_MAX_BUFFER_SIZE	(512 * 8)
1075dbdb7daSHaojian Zhuang 
1085dbdb7daSHaojian Zhuang #define DWMMC_8BIT_MODE			(1 << 6)
1095dbdb7daSHaojian Zhuang 
1107a8b4830SHaojian Zhuang #define DWMMC_ADDRESS_MASK		U(0x0f)
1117a8b4830SHaojian Zhuang 
1125dbdb7daSHaojian Zhuang #define TIMEOUT				100000
1135dbdb7daSHaojian Zhuang 
1145dbdb7daSHaojian Zhuang struct dw_idmac_desc {
1155dbdb7daSHaojian Zhuang 	unsigned int	des0;
1165dbdb7daSHaojian Zhuang 	unsigned int	des1;
1175dbdb7daSHaojian Zhuang 	unsigned int	des2;
1185dbdb7daSHaojian Zhuang 	unsigned int	des3;
1195dbdb7daSHaojian Zhuang };
1205dbdb7daSHaojian Zhuang 
1215dbdb7daSHaojian Zhuang static void dw_init(void);
1227a8b4830SHaojian Zhuang static int dw_send_cmd(struct mmc_cmd *cmd);
1237a8b4830SHaojian Zhuang static int dw_set_ios(unsigned int clk, unsigned int width);
1245dbdb7daSHaojian Zhuang static int dw_prepare(int lba, uintptr_t buf, size_t size);
1255dbdb7daSHaojian Zhuang static int dw_read(int lba, uintptr_t buf, size_t size);
1265dbdb7daSHaojian Zhuang static int dw_write(int lba, uintptr_t buf, size_t size);
1275dbdb7daSHaojian Zhuang 
1287a8b4830SHaojian Zhuang static const struct mmc_ops dw_mmc_ops = {
1295dbdb7daSHaojian Zhuang 	.init		= dw_init,
1305dbdb7daSHaojian Zhuang 	.send_cmd	= dw_send_cmd,
1315dbdb7daSHaojian Zhuang 	.set_ios	= dw_set_ios,
1325dbdb7daSHaojian Zhuang 	.prepare	= dw_prepare,
1335dbdb7daSHaojian Zhuang 	.read		= dw_read,
1345dbdb7daSHaojian Zhuang 	.write		= dw_write,
1355dbdb7daSHaojian Zhuang };
1365dbdb7daSHaojian Zhuang 
1375dbdb7daSHaojian Zhuang static dw_mmc_params_t dw_params;
1385dbdb7daSHaojian Zhuang 
1395dbdb7daSHaojian Zhuang static void dw_update_clk(void)
1405dbdb7daSHaojian Zhuang {
1415dbdb7daSHaojian Zhuang 	unsigned int data;
1425dbdb7daSHaojian Zhuang 
1435dbdb7daSHaojian Zhuang 	mmio_write_32(dw_params.reg_base + DWMMC_CMD,
1445dbdb7daSHaojian Zhuang 		      CMD_WAIT_PRVDATA_COMPLETE | CMD_UPDATE_CLK_ONLY |
1455dbdb7daSHaojian Zhuang 		      CMD_START);
1465dbdb7daSHaojian Zhuang 	while (1) {
1475dbdb7daSHaojian Zhuang 		data = mmio_read_32(dw_params.reg_base + DWMMC_CMD);
1485dbdb7daSHaojian Zhuang 		if ((data & CMD_START) == 0)
1495dbdb7daSHaojian Zhuang 			break;
1505dbdb7daSHaojian Zhuang 		data = mmio_read_32(dw_params.reg_base + DWMMC_RINTSTS);
151e52f5291SHaojian Zhuang 		assert((data & INT_HLE) == 0);
1525dbdb7daSHaojian Zhuang 	}
1535dbdb7daSHaojian Zhuang }
1545dbdb7daSHaojian Zhuang 
1555dbdb7daSHaojian Zhuang static void dw_set_clk(int clk)
1565dbdb7daSHaojian Zhuang {
1575dbdb7daSHaojian Zhuang 	unsigned int data;
1585dbdb7daSHaojian Zhuang 	int div;
1595dbdb7daSHaojian Zhuang 
1605dbdb7daSHaojian Zhuang 	assert(clk > 0);
1615dbdb7daSHaojian Zhuang 
1625dbdb7daSHaojian Zhuang 	for (div = 1; div < 256; div++) {
1635dbdb7daSHaojian Zhuang 		if ((dw_params.clk_rate / (2 * div)) <= clk) {
1645dbdb7daSHaojian Zhuang 			break;
1655dbdb7daSHaojian Zhuang 		}
1665dbdb7daSHaojian Zhuang 	}
1675dbdb7daSHaojian Zhuang 	assert(div < 256);
1685dbdb7daSHaojian Zhuang 
1695dbdb7daSHaojian Zhuang 	/* wait until controller is idle */
1705dbdb7daSHaojian Zhuang 	do {
1715dbdb7daSHaojian Zhuang 		data = mmio_read_32(dw_params.reg_base + DWMMC_STATUS);
1725dbdb7daSHaojian Zhuang 	} while (data & STATUS_DATA_BUSY);
1735dbdb7daSHaojian Zhuang 
1745dbdb7daSHaojian Zhuang 	/* disable clock before change clock rate */
1755dbdb7daSHaojian Zhuang 	mmio_write_32(dw_params.reg_base + DWMMC_CLKENA, 0);
1765dbdb7daSHaojian Zhuang 	dw_update_clk();
1775dbdb7daSHaojian Zhuang 
1785dbdb7daSHaojian Zhuang 	mmio_write_32(dw_params.reg_base + DWMMC_CLKDIV, div);
1795dbdb7daSHaojian Zhuang 	dw_update_clk();
1805dbdb7daSHaojian Zhuang 
1815dbdb7daSHaojian Zhuang 	/* enable clock */
1825dbdb7daSHaojian Zhuang 	mmio_write_32(dw_params.reg_base + DWMMC_CLKENA, 1);
1835dbdb7daSHaojian Zhuang 	mmio_write_32(dw_params.reg_base + DWMMC_CLKSRC, 0);
1845dbdb7daSHaojian Zhuang 	dw_update_clk();
1855dbdb7daSHaojian Zhuang }
1865dbdb7daSHaojian Zhuang 
1875dbdb7daSHaojian Zhuang static void dw_init(void)
1885dbdb7daSHaojian Zhuang {
1895dbdb7daSHaojian Zhuang 	unsigned int data;
1905dbdb7daSHaojian Zhuang 	uintptr_t base;
1915dbdb7daSHaojian Zhuang 
1927a8b4830SHaojian Zhuang 	assert((dw_params.reg_base & MMC_BLOCK_MASK) == 0);
1935dbdb7daSHaojian Zhuang 
1945dbdb7daSHaojian Zhuang 	base = dw_params.reg_base;
1955dbdb7daSHaojian Zhuang 	mmio_write_32(base + DWMMC_PWREN, 1);
1965dbdb7daSHaojian Zhuang 	mmio_write_32(base + DWMMC_CTRL, CTRL_RESET_ALL);
1975dbdb7daSHaojian Zhuang 	do {
1985dbdb7daSHaojian Zhuang 		data = mmio_read_32(base + DWMMC_CTRL);
1995dbdb7daSHaojian Zhuang 	} while (data);
2005dbdb7daSHaojian Zhuang 
2015dbdb7daSHaojian Zhuang 	/* enable DMA in CTRL */
2025dbdb7daSHaojian Zhuang 	data = CTRL_INT_EN | CTRL_DMA_EN | CTRL_IDMAC_EN;
2035dbdb7daSHaojian Zhuang 	mmio_write_32(base + DWMMC_CTRL, data);
2045dbdb7daSHaojian Zhuang 	mmio_write_32(base + DWMMC_RINTSTS, ~0);
2055dbdb7daSHaojian Zhuang 	mmio_write_32(base + DWMMC_INTMASK, 0);
2065dbdb7daSHaojian Zhuang 	mmio_write_32(base + DWMMC_TMOUT, ~0);
2075dbdb7daSHaojian Zhuang 	mmio_write_32(base + DWMMC_IDINTEN, ~0);
2087a8b4830SHaojian Zhuang 	mmio_write_32(base + DWMMC_BLKSIZ, MMC_BLOCK_SIZE);
2095dbdb7daSHaojian Zhuang 	mmio_write_32(base + DWMMC_BYTCNT, 256 * 1024);
2105dbdb7daSHaojian Zhuang 	mmio_write_32(base + DWMMC_DEBNCE, 0x00ffffff);
2115dbdb7daSHaojian Zhuang 	mmio_write_32(base + DWMMC_BMOD, BMOD_SWRESET);
2125dbdb7daSHaojian Zhuang 	do {
2135dbdb7daSHaojian Zhuang 		data = mmio_read_32(base + DWMMC_BMOD);
2145dbdb7daSHaojian Zhuang 	} while (data & BMOD_SWRESET);
2155dbdb7daSHaojian Zhuang 	/* enable DMA in BMOD */
2165dbdb7daSHaojian Zhuang 	data |= BMOD_ENABLE | BMOD_FB;
2175dbdb7daSHaojian Zhuang 	mmio_write_32(base + DWMMC_BMOD, data);
2185dbdb7daSHaojian Zhuang 
2195dbdb7daSHaojian Zhuang 	udelay(100);
2207a8b4830SHaojian Zhuang 	dw_set_clk(MMC_BOOT_CLK_RATE);
2215dbdb7daSHaojian Zhuang 	udelay(100);
2225dbdb7daSHaojian Zhuang }
2235dbdb7daSHaojian Zhuang 
2247a8b4830SHaojian Zhuang static int dw_send_cmd(struct mmc_cmd *cmd)
2255dbdb7daSHaojian Zhuang {
2265dbdb7daSHaojian Zhuang 	unsigned int op, data, err_mask;
2275dbdb7daSHaojian Zhuang 	uintptr_t base;
2285dbdb7daSHaojian Zhuang 	int timeout;
2295dbdb7daSHaojian Zhuang 
2305dbdb7daSHaojian Zhuang 	assert(cmd);
2315dbdb7daSHaojian Zhuang 
2325dbdb7daSHaojian Zhuang 	base = dw_params.reg_base;
2335dbdb7daSHaojian Zhuang 
2345dbdb7daSHaojian Zhuang 	switch (cmd->cmd_idx) {
2357a8b4830SHaojian Zhuang 	case 0:
2365dbdb7daSHaojian Zhuang 		op = CMD_SEND_INIT;
2375dbdb7daSHaojian Zhuang 		break;
2387a8b4830SHaojian Zhuang 	case 12:
2395dbdb7daSHaojian Zhuang 		op = CMD_STOP_ABORT_CMD;
2405dbdb7daSHaojian Zhuang 		break;
2417a8b4830SHaojian Zhuang 	case 13:
2425dbdb7daSHaojian Zhuang 		op = CMD_WAIT_PRVDATA_COMPLETE;
2435dbdb7daSHaojian Zhuang 		break;
2447a8b4830SHaojian Zhuang 	case 8:
2457a8b4830SHaojian Zhuang 	case 17:
2467a8b4830SHaojian Zhuang 	case 18:
2475dbdb7daSHaojian Zhuang 		op = CMD_DATA_TRANS_EXPECT | CMD_WAIT_PRVDATA_COMPLETE;
2485dbdb7daSHaojian Zhuang 		break;
2497a8b4830SHaojian Zhuang 	case 24:
2507a8b4830SHaojian Zhuang 	case 25:
2515dbdb7daSHaojian Zhuang 		op = CMD_WRITE | CMD_DATA_TRANS_EXPECT |
2525dbdb7daSHaojian Zhuang 		     CMD_WAIT_PRVDATA_COMPLETE;
2535dbdb7daSHaojian Zhuang 		break;
2545dbdb7daSHaojian Zhuang 	default:
2555dbdb7daSHaojian Zhuang 		op = 0;
2565dbdb7daSHaojian Zhuang 		break;
2575dbdb7daSHaojian Zhuang 	}
2585dbdb7daSHaojian Zhuang 	op |= CMD_USE_HOLD_REG | CMD_START;
2595dbdb7daSHaojian Zhuang 	switch (cmd->resp_type) {
2605dbdb7daSHaojian Zhuang 	case 0:
2615dbdb7daSHaojian Zhuang 		break;
262*2a82a9c9SJun Nie 	case MMC_RESPONSE_R2:
2635dbdb7daSHaojian Zhuang 		op |= CMD_RESP_EXPECT | CMD_CHECK_RESP_CRC |
2645dbdb7daSHaojian Zhuang 		      CMD_RESP_LEN;
2655dbdb7daSHaojian Zhuang 		break;
266*2a82a9c9SJun Nie 	case MMC_RESPONSE_R1:
267*2a82a9c9SJun Nie 	case MMC_RESPONSE_R1B:
268*2a82a9c9SJun Nie 	case MMC_RESPONSE_R3:
269*2a82a9c9SJun Nie 	case MMC_RESPONSE_R5:
2705dbdb7daSHaojian Zhuang 		op |= CMD_RESP_EXPECT;
2715dbdb7daSHaojian Zhuang 		break;
2725dbdb7daSHaojian Zhuang 	default:
2735dbdb7daSHaojian Zhuang 		op |= CMD_RESP_EXPECT | CMD_CHECK_RESP_CRC;
2745dbdb7daSHaojian Zhuang 		break;
2755dbdb7daSHaojian Zhuang 	}
2765dbdb7daSHaojian Zhuang 	timeout = TIMEOUT;
2775dbdb7daSHaojian Zhuang 	do {
2785dbdb7daSHaojian Zhuang 		data = mmio_read_32(base + DWMMC_STATUS);
2795dbdb7daSHaojian Zhuang 		if (--timeout <= 0)
2805dbdb7daSHaojian Zhuang 			panic();
2815dbdb7daSHaojian Zhuang 	} while (data & STATUS_DATA_BUSY);
2825dbdb7daSHaojian Zhuang 
2835dbdb7daSHaojian Zhuang 	mmio_write_32(base + DWMMC_RINTSTS, ~0);
2845dbdb7daSHaojian Zhuang 	mmio_write_32(base + DWMMC_CMDARG, cmd->cmd_arg);
2855dbdb7daSHaojian Zhuang 	mmio_write_32(base + DWMMC_CMD, op | cmd->cmd_idx);
2865dbdb7daSHaojian Zhuang 
2875dbdb7daSHaojian Zhuang 	err_mask = INT_EBE | INT_HLE | INT_RTO | INT_RCRC | INT_RE |
2885dbdb7daSHaojian Zhuang 		   INT_DCRC | INT_DRT | INT_SBE;
2895dbdb7daSHaojian Zhuang 	timeout = TIMEOUT;
2905dbdb7daSHaojian Zhuang 	do {
2915dbdb7daSHaojian Zhuang 		udelay(500);
2925dbdb7daSHaojian Zhuang 		data = mmio_read_32(base + DWMMC_RINTSTS);
2935dbdb7daSHaojian Zhuang 
2945dbdb7daSHaojian Zhuang 		if (data & err_mask)
2955dbdb7daSHaojian Zhuang 			return -EIO;
2965dbdb7daSHaojian Zhuang 		if (data & INT_DTO)
2975dbdb7daSHaojian Zhuang 			break;
2985dbdb7daSHaojian Zhuang 		if (--timeout == 0) {
2995dbdb7daSHaojian Zhuang 			ERROR("%s, RINTSTS:0x%x\n", __func__, data);
3005dbdb7daSHaojian Zhuang 			panic();
3015dbdb7daSHaojian Zhuang 		}
3025dbdb7daSHaojian Zhuang 	} while (!(data & INT_CMD_DONE));
3035dbdb7daSHaojian Zhuang 
3045dbdb7daSHaojian Zhuang 	if (op & CMD_RESP_EXPECT) {
3055dbdb7daSHaojian Zhuang 		cmd->resp_data[0] = mmio_read_32(base + DWMMC_RESP0);
3065dbdb7daSHaojian Zhuang 		if (op & CMD_RESP_LEN) {
3075dbdb7daSHaojian Zhuang 			cmd->resp_data[1] = mmio_read_32(base + DWMMC_RESP1);
3085dbdb7daSHaojian Zhuang 			cmd->resp_data[2] = mmio_read_32(base + DWMMC_RESP2);
3095dbdb7daSHaojian Zhuang 			cmd->resp_data[3] = mmio_read_32(base + DWMMC_RESP3);
3105dbdb7daSHaojian Zhuang 		}
3115dbdb7daSHaojian Zhuang 	}
3125dbdb7daSHaojian Zhuang 	return 0;
3135dbdb7daSHaojian Zhuang }
3145dbdb7daSHaojian Zhuang 
3157a8b4830SHaojian Zhuang static int dw_set_ios(unsigned int clk, unsigned int width)
3165dbdb7daSHaojian Zhuang {
3175dbdb7daSHaojian Zhuang 	switch (width) {
3187a8b4830SHaojian Zhuang 	case MMC_BUS_WIDTH_1:
3195dbdb7daSHaojian Zhuang 		mmio_write_32(dw_params.reg_base + DWMMC_CTYPE, CTYPE_1BIT);
3205dbdb7daSHaojian Zhuang 		break;
3217a8b4830SHaojian Zhuang 	case MMC_BUS_WIDTH_4:
3225dbdb7daSHaojian Zhuang 		mmio_write_32(dw_params.reg_base + DWMMC_CTYPE, CTYPE_4BIT);
3235dbdb7daSHaojian Zhuang 		break;
3247a8b4830SHaojian Zhuang 	case MMC_BUS_WIDTH_8:
3255dbdb7daSHaojian Zhuang 		mmio_write_32(dw_params.reg_base + DWMMC_CTYPE, CTYPE_8BIT);
3265dbdb7daSHaojian Zhuang 		break;
3275dbdb7daSHaojian Zhuang 	default:
3285dbdb7daSHaojian Zhuang 		assert(0);
3295aa7498aSJonathan Wright 		break;
3305dbdb7daSHaojian Zhuang 	}
3315dbdb7daSHaojian Zhuang 	dw_set_clk(clk);
3325dbdb7daSHaojian Zhuang 	return 0;
3335dbdb7daSHaojian Zhuang }
3345dbdb7daSHaojian Zhuang 
3355dbdb7daSHaojian Zhuang static int dw_prepare(int lba, uintptr_t buf, size_t size)
3365dbdb7daSHaojian Zhuang {
3375dbdb7daSHaojian Zhuang 	struct dw_idmac_desc *desc;
3385dbdb7daSHaojian Zhuang 	int desc_cnt, i, last;
3395dbdb7daSHaojian Zhuang 	uintptr_t base;
3405dbdb7daSHaojian Zhuang 
3417a8b4830SHaojian Zhuang 	assert(((buf & DWMMC_ADDRESS_MASK) == 0) &&
3427a8b4830SHaojian Zhuang 	       ((size % MMC_BLOCK_SIZE) == 0) &&
3435dbdb7daSHaojian Zhuang 	       (dw_params.desc_size > 0) &&
3447a8b4830SHaojian Zhuang 	       ((dw_params.reg_base & MMC_BLOCK_MASK) == 0) &&
3457a8b4830SHaojian Zhuang 	       ((dw_params.desc_base & MMC_BLOCK_MASK) == 0) &&
3467a8b4830SHaojian Zhuang 	       ((dw_params.desc_size & MMC_BLOCK_MASK) == 0));
3477a8b4830SHaojian Zhuang 
3487a8b4830SHaojian Zhuang 	flush_dcache_range(buf, size);
3495dbdb7daSHaojian Zhuang 
3505dbdb7daSHaojian Zhuang 	desc_cnt = (size + DWMMC_DMA_MAX_BUFFER_SIZE - 1) /
3515dbdb7daSHaojian Zhuang 		   DWMMC_DMA_MAX_BUFFER_SIZE;
3525dbdb7daSHaojian Zhuang 	assert(desc_cnt * sizeof(struct dw_idmac_desc) < dw_params.desc_size);
3535dbdb7daSHaojian Zhuang 
3545dbdb7daSHaojian Zhuang 	base = dw_params.reg_base;
3555dbdb7daSHaojian Zhuang 	desc = (struct dw_idmac_desc *)dw_params.desc_base;
3565dbdb7daSHaojian Zhuang 	mmio_write_32(base + DWMMC_BYTCNT, size);
3575dbdb7daSHaojian Zhuang 	mmio_write_32(base + DWMMC_RINTSTS, ~0);
3585dbdb7daSHaojian Zhuang 	for (i = 0; i < desc_cnt; i++) {
3595dbdb7daSHaojian Zhuang 		desc[i].des0 = IDMAC_DES0_OWN | IDMAC_DES0_CH | IDMAC_DES0_DIC;
3605dbdb7daSHaojian Zhuang 		desc[i].des1 = IDMAC_DES1_BS1(DWMMC_DMA_MAX_BUFFER_SIZE);
3615dbdb7daSHaojian Zhuang 		desc[i].des2 = buf + DWMMC_DMA_MAX_BUFFER_SIZE * i;
3625dbdb7daSHaojian Zhuang 		desc[i].des3 = dw_params.desc_base +
3635dbdb7daSHaojian Zhuang 			       (sizeof(struct dw_idmac_desc)) * (i + 1);
3645dbdb7daSHaojian Zhuang 	}
3655dbdb7daSHaojian Zhuang 	/* first descriptor */
3665dbdb7daSHaojian Zhuang 	desc->des0 |= IDMAC_DES0_FS;
3675dbdb7daSHaojian Zhuang 	/* last descriptor */
3685dbdb7daSHaojian Zhuang 	last = desc_cnt - 1;
3695dbdb7daSHaojian Zhuang 	(desc + last)->des0 |= IDMAC_DES0_LD;
3705dbdb7daSHaojian Zhuang 	(desc + last)->des0 &= ~(IDMAC_DES0_DIC | IDMAC_DES0_CH);
3715dbdb7daSHaojian Zhuang 	(desc + last)->des1 = IDMAC_DES1_BS1(size - (last *
3725dbdb7daSHaojian Zhuang 				  DWMMC_DMA_MAX_BUFFER_SIZE));
3735dbdb7daSHaojian Zhuang 	/* set next descriptor address as 0 */
3745dbdb7daSHaojian Zhuang 	(desc + last)->des3 = 0;
3755dbdb7daSHaojian Zhuang 
3765dbdb7daSHaojian Zhuang 	mmio_write_32(base + DWMMC_DBADDR, dw_params.desc_base);
3777a8b4830SHaojian Zhuang 	flush_dcache_range(dw_params.desc_base,
3785dbdb7daSHaojian Zhuang 			   desc_cnt * DWMMC_DMA_MAX_BUFFER_SIZE);
3795dbdb7daSHaojian Zhuang 
3805dbdb7daSHaojian Zhuang 	return 0;
3815dbdb7daSHaojian Zhuang }
3825dbdb7daSHaojian Zhuang 
3835dbdb7daSHaojian Zhuang static int dw_read(int lba, uintptr_t buf, size_t size)
3845dbdb7daSHaojian Zhuang {
3855dbdb7daSHaojian Zhuang 	return 0;
3865dbdb7daSHaojian Zhuang }
3875dbdb7daSHaojian Zhuang 
3885dbdb7daSHaojian Zhuang static int dw_write(int lba, uintptr_t buf, size_t size)
3895dbdb7daSHaojian Zhuang {
3905dbdb7daSHaojian Zhuang 	return 0;
3915dbdb7daSHaojian Zhuang }
3925dbdb7daSHaojian Zhuang 
3937a8b4830SHaojian Zhuang void dw_mmc_init(dw_mmc_params_t *params, struct mmc_device_info *info)
3945dbdb7daSHaojian Zhuang {
3955dbdb7daSHaojian Zhuang 	assert((params != 0) &&
3967a8b4830SHaojian Zhuang 	       ((params->reg_base & MMC_BLOCK_MASK) == 0) &&
3977a8b4830SHaojian Zhuang 	       ((params->desc_base & MMC_BLOCK_MASK) == 0) &&
3987a8b4830SHaojian Zhuang 	       ((params->desc_size & MMC_BLOCK_MASK) == 0) &&
3995dbdb7daSHaojian Zhuang 	       (params->desc_size > 0) &&
4005dbdb7daSHaojian Zhuang 	       (params->clk_rate > 0) &&
4017a8b4830SHaojian Zhuang 	       ((params->bus_width == MMC_BUS_WIDTH_1) ||
4027a8b4830SHaojian Zhuang 		(params->bus_width == MMC_BUS_WIDTH_4) ||
4037a8b4830SHaojian Zhuang 		(params->bus_width == MMC_BUS_WIDTH_8)));
4045dbdb7daSHaojian Zhuang 
4055dbdb7daSHaojian Zhuang 	memcpy(&dw_params, params, sizeof(dw_mmc_params_t));
4067a8b4830SHaojian Zhuang 	mmc_init(&dw_mmc_ops, params->clk_rate, params->bus_width,
4077a8b4830SHaojian Zhuang 		 params->flags, info);
4085dbdb7daSHaojian Zhuang }
409