diff mbox series

[U-Boot,v3,3/6] mmc: mmc_spi: Re-write driver using DM framework

Message ID 20190708041004.6252-4-anup.patel@wdc.com
State Accepted
Commit 05e35d429745253752b68f73146c22268ec9a5a8
Delegated to: Peng Fan
Headers show
Series SiFive SPI MMC Support | expand

Commit Message

Anup Patel July 8, 2019, 4:10 a.m. UTC
From: Bhargav Shah <bhargavshah1988@gmail.com>

This patch rewrites MMC SPI driver using U-Boot DM
framework and get it's working on SiFive Unleashed
board.

Signed-off-by: Bhargav Shah <bhargavshah1988@gmail.com>
Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Tested-by: Bin Meng <bmeng.cn@gmail.com>
---
 drivers/mmc/Kconfig          |  18 ++
 drivers/mmc/mmc_spi.c        | 469 ++++++++++++++++++++++-------------
 scripts/config_whitelist.txt |   6 -
 3 files changed, 320 insertions(+), 173 deletions(-)

Comments

Peng Fan July 11, 2019, 6:36 a.m. UTC | #1
Hi Anup,

> Subject: [PATCH v3 3/6] mmc: mmc_spi: Re-write driver using DM framework
> 
> From: Bhargav Shah <bhargavshah1988@gmail.com>
> 
> This patch rewrites MMC SPI driver using U-Boot DM framework and get it's
> working on SiFive Unleashed board.

So you drop the non-DM part, I saw there are still one user
./include/configs/UCP1020.h:441:#define CONFIG_MMC_SPI

Will this switching to DM break that?

Regards,
Peng.

> 
> Signed-off-by: Bhargav Shah <bhargavshah1988@gmail.com>
> Signed-off-by: Anup Patel <anup.patel@wdc.com>
> Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
> Tested-by: Bin Meng <bmeng.cn@gmail.com>
> ---
>  drivers/mmc/Kconfig          |  18 ++
>  drivers/mmc/mmc_spi.c        | 469
> ++++++++++++++++++++++-------------
>  scripts/config_whitelist.txt |   6 -
>  3 files changed, 320 insertions(+), 173 deletions(-)
> 
> diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index
> c23299ea96..f750dad00a 100644
> --- a/drivers/mmc/Kconfig
> +++ b/drivers/mmc/Kconfig
> @@ -46,6 +46,24 @@ config SPL_DM_MMC
> 
>  if MMC
> 
> +config MMC_SPI
> +	bool "Support for SPI-based MMC controller"
> +	depends on DM_MMC && DM_SPI
> +	help
> +	  This selects SPI-based MMC controllers.
> +	  If you have an MMC controller on a SPI bus, say Y here.
> +
> +	  If unsure, say N.
> +
> +config MMC_SPI_CRC_ON
> +	bool "Support CRC for SPI-based MMC controller"
> +	depends on MMC_SPI
> +	default y
> +	help
> +	  This enables CRC for SPI-based MMC controllers.
> +
> +	  If unsure, say N.
> +
>  config ARM_PL180_MMCI
>  	bool "ARM AMBA Multimedia Card Interface and compatible support"
>  	depends on DM_MMC && OF_CONTROL
> diff --git a/drivers/mmc/mmc_spi.c b/drivers/mmc/mmc_spi.c index
> 4f57990d9c..f3d687ae80 100644
> --- a/drivers/mmc/mmc_spi.c
> +++ b/drivers/mmc/mmc_spi.c
> @@ -2,6 +2,8 @@
>   * generic mmc spi driver
>   *
>   * Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw>
> + * Copyright 2019 Bhargav Shah <bhargavshah1988@gmail.com>
> + *
>   * Licensed under the GPL-2 or later.
>   */
>  #include <common.h>
> @@ -9,21 +11,23 @@
>  #include <malloc.h>
>  #include <part.h>
>  #include <mmc.h>
> -#include <spi.h>
> +#include <stdlib.h>
>  #include <u-boot/crc.h>
>  #include <linux/crc7.h>
>  #include <asm/byteorder.h>
> +#include <dm.h>
> +#include <spi.h>
> 
>  /* MMC/SD in SPI mode reports R1 status always */
> -#define R1_SPI_IDLE		(1 << 0)
> -#define R1_SPI_ERASE_RESET	(1 << 1)
> -#define R1_SPI_ILLEGAL_COMMAND	(1 << 2)
> -#define R1_SPI_COM_CRC		(1 << 3)
> -#define R1_SPI_ERASE_SEQ	(1 << 4)
> -#define R1_SPI_ADDRESS		(1 << 5)
> -#define R1_SPI_PARAMETER	(1 << 6)
> +#define R1_SPI_IDLE			BIT(0)
> +#define R1_SPI_ERASE_RESET		BIT(1)
> +#define R1_SPI_ILLEGAL_COMMAND		BIT(2)
> +#define R1_SPI_COM_CRC			BIT(3)
> +#define R1_SPI_ERASE_SEQ		BIT(4)
> +#define R1_SPI_ADDRESS			BIT(5)
> +#define R1_SPI_PARAMETER		BIT(6)
>  /* R1 bit 7 is always zero, reuse this bit for error */
> -#define R1_SPI_ERROR		(1 << 7)
> +#define R1_SPI_ERROR			BIT(7)
> 
>  /* Response tokens used to ack each block written: */
>  #define SPI_MMC_RESPONSE_CODE(x)	((x) & 0x1f)
> @@ -34,28 +38,45 @@
>  /* Read and write blocks start with these tokens and end with crc;
>   * on error, read tokens act like a subset of R2_SPI_* values.
>   */
> -#define SPI_TOKEN_SINGLE	0xfe	/* single block r/w, multiblock read */
> -#define SPI_TOKEN_MULTI_WRITE	0xfc	/* multiblock write */
> -#define SPI_TOKEN_STOP_TRAN	0xfd	/* terminate multiblock write */
> +/* single block write multiblock read */
> +#define SPI_TOKEN_SINGLE		0xfe
> +/* multiblock write */
> +#define SPI_TOKEN_MULTI_WRITE		0xfc
> +/* terminate multiblock write */
> +#define SPI_TOKEN_STOP_TRAN		0xfd
> 
>  /* MMC SPI commands start with a start bit "0" and a transmit bit "1" */
> -#define MMC_SPI_CMD(x) (0x40 | (x & 0x3f))
> +#define MMC_SPI_CMD(x) (0x40 | (x))
> 
>  /* bus capability */
> -#define MMC_SPI_VOLTAGE (MMC_VDD_32_33 | MMC_VDD_33_34)
> -#define MMC_SPI_MIN_CLOCK 400000 /* 400KHz to meet MMC spec */
> +#define MMC_SPI_VOLTAGE			(MMC_VDD_32_33 |
> MMC_VDD_33_34)
> +#define MMC_SPI_MIN_CLOCK		400000	/* 400KHz to meet MMC
> spec */
> +#define MMC_SPI_MAX_CLOCK		25000000 /* SD/MMC legacy speed */
> 
>  /* timeout value */
> -#define CTOUT 8
> -#define RTOUT 3000000 /* 1 sec */
> -#define WTOUT 3000000 /* 1 sec */
> +#define CMD_TIMEOUT			8
> +#define READ_TIMEOUT			3000000 /* 1 sec */
> +#define WRITE_TIMEOUT			3000000 /* 1 sec */
> 
> -static uint mmc_spi_sendcmd(struct mmc *mmc, ushort cmdidx, u32
> cmdarg)
> +struct mmc_spi_priv {
> +	struct spi_slave *spi;
> +	struct mmc_config cfg;
> +	struct mmc mmc;
> +};
> +
> +static int mmc_spi_sendcmd(struct udevice *dev,
> +			   ushort cmdidx, u32 cmdarg, u32 resp_type,
> +			   u8 *resp, u32 resp_size,
> +			   bool resp_match, u8 resp_match_value)
>  {
> -	struct spi_slave *spi = mmc->priv;
> -	u8 cmdo[7];
> -	u8 r1;
> -	int i;
> +	int i, rpos = 0, ret = 0;
> +	u8 cmdo[7], r;
> +
> +	debug("%s: cmd%d cmdarg=0x%x resp_type=0x%x "
> +	      "resp_size=%d resp_match=%d resp_match_value=0x%x\n",
> +	      __func__, cmdidx, cmdarg, resp_type,
> +	      resp_size, resp_match, resp_match_value);
> +
>  	cmdo[0] = 0xff;
>  	cmdo[1] = MMC_SPI_CMD(cmdidx);
>  	cmdo[2] = cmdarg >> 24;
> @@ -63,37 +84,79 @@ static uint mmc_spi_sendcmd(struct mmc *mmc,
> ushort cmdidx, u32 cmdarg)
>  	cmdo[4] = cmdarg >> 8;
>  	cmdo[5] = cmdarg;
>  	cmdo[6] = (crc7(0, &cmdo[1], 5) << 1) | 0x01;
> -	spi_xfer(spi, sizeof(cmdo) * 8, cmdo, NULL, 0);
> -	for (i = 0; i < CTOUT; i++) {
> -		spi_xfer(spi, 1 * 8, NULL, &r1, 0);
> -		if (i && (r1 & 0x80) == 0) /* r1 response */
> -			break;
> +	ret = dm_spi_xfer(dev, sizeof(cmdo) * 8, cmdo, NULL, 0);
> +	if (ret)
> +		return ret;
> +
> +	ret = dm_spi_xfer(dev, 1 * 8, NULL, &r, 0);
> +	if (ret)
> +		return ret;
> +
> +	if (!resp || !resp_size)
> +		return 0;
> +
> +	debug("%s: cmd%d", __func__, cmdidx);
> +
> +	if (resp_match) {
> +		r = ~resp_match_value;
> +		i = CMD_TIMEOUT;
> +		while (i--) {
> +			ret = dm_spi_xfer(dev, 1 * 8, NULL, &r, 0);
> +			if (ret)
> +				return ret;
> +			debug(" resp%d=0x%x", rpos, r);
> +			rpos++;
> +			if (r == resp_match_value)
> +				break;
> +		}
> +		if (!i && (r != resp_match_value))
> +			return -ETIMEDOUT;
> +	}
> +
> +	for (i = 0; i < resp_size; i++) {
> +		if (i == 0 && resp_match) {
> +			resp[i] = resp_match_value;
> +			continue;
> +		}
> +		ret = dm_spi_xfer(dev, 1 * 8, NULL, &r, 0);
> +		if (ret)
> +			return ret;
> +		debug(" resp%d=0x%x", rpos, r);
> +		rpos++;
> +		resp[i] = r;
>  	}
> -	debug("%s:cmd%d resp%d %x\n", __func__, cmdidx, i, r1);
> -	return r1;
> +
> +	debug("\n");
> +
> +	return 0;
>  }
> 
> -static uint mmc_spi_readdata(struct mmc *mmc, void *xbuf,
> -				u32 bcnt, u32 bsize)
> +static int mmc_spi_readdata(struct udevice *dev,
> +			    void *xbuf, u32 bcnt, u32 bsize)
>  {
> -	struct spi_slave *spi = mmc->priv;
> -	u8 *buf = xbuf;
> -	u8 r1;
>  	u16 crc;
> -	int i;
> +	u8 *buf = xbuf, r1;
> +	int i, ret = 0;
> +
>  	while (bcnt--) {
> -		for (i = 0; i < RTOUT; i++) {
> -			spi_xfer(spi, 1 * 8, NULL, &r1, 0);
> -			if (r1 != 0xff) /* data token */
> +		for (i = 0; i < READ_TIMEOUT; i++) {
> +			ret = dm_spi_xfer(dev, 1 * 8, NULL, &r1, 0);
> +			if (ret)
> +				return ret;
> +			if (r1 == SPI_TOKEN_SINGLE)
>  				break;
>  		}
> -		debug("%s:tok%d %x\n", __func__, i, r1);
> +		debug("%s: data tok%d 0x%x\n", __func__, i, r1);
>  		if (r1 == SPI_TOKEN_SINGLE) {
> -			spi_xfer(spi, bsize * 8, NULL, buf, 0);
> -			spi_xfer(spi, 2 * 8, NULL, &crc, 0);
> +			ret = dm_spi_xfer(dev, bsize * 8, NULL, buf, 0);
> +			if (ret)
> +				return ret;
> +			ret = dm_spi_xfer(dev, 2 * 8, NULL, &crc, 0);
> +			if (ret)
> +				return ret;
>  #ifdef CONFIG_MMC_SPI_CRC_ON
> -			if (be_to_cpu16(crc16_ccitt(0, buf, bsize)) != crc) {
> -				debug("%s: CRC error\n", mmc->cfg->name);
> +			if (be16_to_cpu(crc16_ccitt(0, buf, bsize)) != crc) {
> +				debug("%s: data crc error\n", __func__);
>  				r1 = R1_SPI_COM_CRC;
>  				break;
>  			}
> @@ -105,48 +168,56 @@ static uint mmc_spi_readdata(struct mmc *mmc,
> void *xbuf,
>  		}
>  		buf += bsize;
>  	}
> -	return r1;
> +
> +	if (r1 & R1_SPI_COM_CRC)
> +		ret = -ECOMM;
> +	else if (r1) /* other errors */
> +		ret = -ETIMEDOUT;
> +
> +	return ret;
>  }
> 
> -static uint mmc_spi_writedata(struct mmc *mmc, const void *xbuf,
> -			      u32 bcnt, u32 bsize, int multi)
> +static int mmc_spi_writedata(struct udevice *dev, const void *xbuf,
> +			     u32 bcnt, u32 bsize, int multi)
>  {
> -	struct spi_slave *spi = mmc->priv;
>  	const u8 *buf = xbuf;
> -	u8 r1;
> +	u8 r1, tok[2];
>  	u16 crc;
> -	u8 tok[2];
> -	int i;
> +	int i, ret = 0;
> +
>  	tok[0] = 0xff;
>  	tok[1] = multi ? SPI_TOKEN_MULTI_WRITE : SPI_TOKEN_SINGLE;
> +
>  	while (bcnt--) {
>  #ifdef CONFIG_MMC_SPI_CRC_ON
>  		crc = cpu_to_be16(crc16_ccitt(0, (u8 *)buf, bsize));  #endif
> -		spi_xfer(spi, 2 * 8, tok, NULL, 0);
> -		spi_xfer(spi, bsize * 8, buf, NULL, 0);
> -		spi_xfer(spi, 2 * 8, &crc, NULL, 0);
> -		for (i = 0; i < CTOUT; i++) {
> -			spi_xfer(spi, 1 * 8, NULL, &r1, 0);
> +		dm_spi_xfer(dev, 2 * 8, tok, NULL, 0);
> +		dm_spi_xfer(dev, bsize * 8, buf, NULL, 0);
> +		dm_spi_xfer(dev, 2 * 8, &crc, NULL, 0);
> +		for (i = 0; i < CMD_TIMEOUT; i++) {
> +			dm_spi_xfer(dev, 1 * 8, NULL, &r1, 0);
>  			if ((r1 & 0x10) == 0) /* response token */
>  				break;
>  		}
> -		debug("%s:tok%d %x\n", __func__, i, r1);
> +		debug("%s: data tok%d 0x%x\n", __func__, i, r1);
>  		if (SPI_MMC_RESPONSE_CODE(r1) == SPI_RESPONSE_ACCEPTED) {
> -			for (i = 0; i < WTOUT; i++) { /* wait busy */
> -				spi_xfer(spi, 1 * 8, NULL, &r1, 0);
> +			debug("%s: data accepted\n", __func__);
> +			for (i = 0; i < WRITE_TIMEOUT; i++) { /* wait busy */
> +				dm_spi_xfer(dev, 1 * 8, NULL, &r1, 0);
>  				if (i && r1 == 0xff) {
>  					r1 = 0;
>  					break;
>  				}
>  			}
> -			if (i == WTOUT) {
> -				debug("%s:wtout %x\n", __func__, r1);
> +			if (i == WRITE_TIMEOUT) {
> +				debug("%s: data write timeout 0x%x\n",
> +				      __func__, r1);
>  				r1 = R1_SPI_ERROR;
>  				break;
>  			}
>  		} else {
> -			debug("%s: err %x\n", __func__, r1);
> +			debug("%s: data error 0x%x\n", __func__, r1);
>  			r1 = R1_SPI_COM_CRC;
>  			break;
>  		}
> @@ -154,140 +225,204 @@ static uint mmc_spi_writedata(struct mmc
> *mmc, const void *xbuf,
>  	}
>  	if (multi && bcnt == -1) { /* stop multi write */
>  		tok[1] = SPI_TOKEN_STOP_TRAN;
> -		spi_xfer(spi, 2 * 8, tok, NULL, 0);
> -		for (i = 0; i < WTOUT; i++) { /* wait busy */
> -			spi_xfer(spi, 1 * 8, NULL, &r1, 0);
> +		dm_spi_xfer(dev, 2 * 8, tok, NULL, 0);
> +		for (i = 0; i < WRITE_TIMEOUT; i++) { /* wait busy */
> +			dm_spi_xfer(dev, 1 * 8, NULL, &r1, 0);
>  			if (i && r1 == 0xff) {
>  				r1 = 0;
>  				break;
>  			}
>  		}
> -		if (i == WTOUT) {
> -			debug("%s:wstop %x\n", __func__, r1);
> +		if (i == WRITE_TIMEOUT) {
> +			debug("%s: data write timeout 0x%x\n", __func__, r1);
>  			r1 = R1_SPI_ERROR;
>  		}
>  	}
> -	return r1;
> -}
> 
> -static int mmc_spi_request(struct mmc *mmc, struct mmc_cmd *cmd,
> -		struct mmc_data *data)
> -{
> -	struct spi_slave *spi = mmc->priv;
> -	u8 r1;
> -	int i;
> -	int ret = 0;
> -	debug("%s:cmd%d %x %x\n", __func__,
> -	      cmd->cmdidx, cmd->resp_type, cmd->cmdarg);
> -	spi_claim_bus(spi);
> -	spi_cs_activate(spi);
> -	r1 = mmc_spi_sendcmd(mmc, cmd->cmdidx, cmd->cmdarg);
> -	if (r1 == 0xff) { /* no response */
> -		ret = -ENOMEDIUM;
> -		goto done;
> -	} else if (r1 & R1_SPI_COM_CRC) {
> +	if (r1 & R1_SPI_COM_CRC)
>  		ret = -ECOMM;
> -		goto done;
> -	} else if (r1 & ~R1_SPI_IDLE) { /* other errors */
> +	else if (r1) /* other errors */
>  		ret = -ETIMEDOUT;
> +
> +	return ret;
> +}
> +
> +static int dm_mmc_spi_set_ios(struct udevice *dev) {
> +	return 0;
> +}
> +
> +static int dm_mmc_spi_request(struct udevice *dev, struct mmc_cmd *cmd,
> +			      struct mmc_data *data)
> +{
> +	int i, multi, ret = 0;
> +	u8 *resp = NULL;
> +	u32 resp_size = 0;
> +	bool resp_match = false;
> +	u8 resp8 = 0, resp40[5] = { 0 }, resp_match_value = 0;
> +
> +	dm_spi_claim_bus(dev);
> +
> +	for (i = 0; i < 4; i++)
> +		cmd->response[i] = 0;
> +
> +	switch (cmd->cmdidx) {
> +	case SD_CMD_APP_SEND_OP_COND:
> +	case MMC_CMD_SEND_OP_COND:
> +		resp = &resp8;
> +		resp_size = sizeof(resp8);
> +		cmd->cmdarg = 0x40000000;
> +		break;
> +	case SD_CMD_SEND_IF_COND:
> +		resp = (u8 *)&resp40[0];
> +		resp_size = sizeof(resp40);
> +		resp_match = true;
> +		resp_match_value = R1_SPI_IDLE;
> +		break;
> +	case MMC_CMD_SPI_READ_OCR:
> +		resp = (u8 *)&resp40[0];
> +		resp_size = sizeof(resp40);
> +		break;
> +	case MMC_CMD_SEND_STATUS:
> +	case MMC_CMD_SET_BLOCKLEN:
> +	case MMC_CMD_SPI_CRC_ON_OFF:
> +	case MMC_CMD_STOP_TRANSMISSION:
> +		resp = &resp8;
> +		resp_size = sizeof(resp8);
> +		resp_match = true;
> +		resp_match_value = 0x0;
> +		break;
> +	case MMC_CMD_SEND_CSD:
> +	case MMC_CMD_SEND_CID:
> +	case MMC_CMD_READ_SINGLE_BLOCK:
> +	case MMC_CMD_READ_MULTIPLE_BLOCK:
> +	case MMC_CMD_WRITE_SINGLE_BLOCK:
> +	case MMC_CMD_WRITE_MULTIPLE_BLOCK:
> +		break;
> +	default:
> +		resp = &resp8;
> +		resp_size = sizeof(resp8);
> +		resp_match = true;
> +		resp_match_value = R1_SPI_IDLE;
> +		break;
> +	};
> +
> +	ret = mmc_spi_sendcmd(dev, cmd->cmdidx, cmd->cmdarg,
> cmd->resp_type,
> +			      resp, resp_size, resp_match, resp_match_value);
> +	if (ret)
>  		goto done;
> -	} else if (cmd->resp_type == MMC_RSP_R2) {
> -		r1 = mmc_spi_readdata(mmc, cmd->response, 1, 16);
> +
> +	switch (cmd->cmdidx) {
> +	case SD_CMD_APP_SEND_OP_COND:
> +	case MMC_CMD_SEND_OP_COND:
> +		cmd->response[0] = (resp8 & R1_SPI_IDLE) ? 0 : OCR_BUSY;
> +		break;
> +	case SD_CMD_SEND_IF_COND:
> +	case MMC_CMD_SPI_READ_OCR:
> +		cmd->response[0] = resp40[4];
> +		cmd->response[0] |= (uint)resp40[3] << 8;
> +		cmd->response[0] |= (uint)resp40[2] << 16;
> +		cmd->response[0] |= (uint)resp40[1] << 24;
> +		break;
> +	case MMC_CMD_SEND_STATUS:
> +		cmd->response[0] = (resp8 & 0xff) ?
> +			MMC_STATUS_ERROR : MMC_STATUS_RDY_FOR_DATA;
> +		break;
> +	case MMC_CMD_SEND_CID:
> +	case MMC_CMD_SEND_CSD:
> +		ret = mmc_spi_readdata(dev, cmd->response, 1, 16);
> +		if (ret)
> +			return ret;
>  		for (i = 0; i < 4; i++)
> -			cmd->response[i] = be32_to_cpu(cmd->response[i]);
> -		debug("r128 %x %x %x %x\n", cmd->response[0],
> cmd->response[1],
> -		      cmd->response[2], cmd->response[3]);
> -	} else if (!data) {
> -		switch (cmd->cmdidx) {
> -		case SD_CMD_APP_SEND_OP_COND:
> -		case MMC_CMD_SEND_OP_COND:
> -			cmd->response[0] = (r1 & R1_SPI_IDLE) ? 0 : OCR_BUSY;
> -			break;
> -		case SD_CMD_SEND_IF_COND:
> -		case MMC_CMD_SPI_READ_OCR:
> -			spi_xfer(spi, 4 * 8, NULL, cmd->response, 0);
> -			cmd->response[0] = be32_to_cpu(cmd->response[0]);
> -			debug("r32 %x\n", cmd->response[0]);
> -			break;
> -		case MMC_CMD_SEND_STATUS:
> -			spi_xfer(spi, 1 * 8, NULL, cmd->response, 0);
> -			cmd->response[0] = (cmd->response[0] & 0xff) ?
> -				MMC_STATUS_ERROR : MMC_STATUS_RDY_FOR_DATA;
> -			break;
> -		}
> -	} else {
> -		debug("%s:data %x %x %x\n", __func__,
> -		      data->flags, data->blocks, data->blocksize);
> +			cmd->response[i] =
> +				cpu_to_be32(cmd->response[i]);
> +		break;
> +	default:
> +		cmd->response[0] = resp8;
> +		break;
> +	}
> +
> +	debug("%s: cmd%d resp0=0x%x resp1=0x%x resp2=0x%x
> resp3=0x%x\n",
> +	      __func__, cmd->cmdidx, cmd->response[0], cmd->response[1],
> +	      cmd->response[2], cmd->response[3]);
> +
> +	if (data) {
> +		debug("%s: data flags=0x%x blocks=%d block_size=%d\n",
> +		      __func__, data->flags, data->blocks, data->blocksize);
> +		multi = (cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK);
>  		if (data->flags == MMC_DATA_READ)
> -			r1 = mmc_spi_readdata(mmc, data->dest,
> -				data->blocks, data->blocksize);
> +			ret = mmc_spi_readdata(dev, data->dest,
> +					       data->blocks, data->blocksize);
>  		else if  (data->flags == MMC_DATA_WRITE)
> -			r1 = mmc_spi_writedata(mmc, data->src,
> -				data->blocks, data->blocksize,
> -				(cmd->cmdidx ==
> MMC_CMD_WRITE_MULTIPLE_BLOCK));
> -		if (r1 & R1_SPI_COM_CRC)
> -			ret = -ECOMM;
> -		else if (r1) /* other errors */
> -			ret = -ETIMEDOUT;
> +			ret = mmc_spi_writedata(dev, data->src,
> +						data->blocks, data->blocksize,
> +						multi);
>  	}
> +
>  done:
> -	spi_cs_deactivate(spi);
> -	spi_release_bus(spi);
> +	dm_spi_release_bus(dev);
> +
>  	return ret;
>  }
> 
> -static int mmc_spi_set_ios(struct mmc *mmc)
> +static int mmc_spi_probe(struct udevice *dev)
>  {
> -	struct spi_slave *spi = mmc->priv;
> +	struct mmc_spi_priv *priv = dev_get_priv(dev);
> +	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
> +	char *name;
> +
> +	priv->spi = dev_get_parent_priv(dev);
> +	if (!priv->spi->max_hz)
> +		priv->spi->max_hz = MMC_SPI_MAX_CLOCK;
> +	priv->spi->speed = 0;
> +	priv->spi->mode = SPI_MODE_0;
> +	priv->spi->wordlen = 8;
> +
> +	name = malloc(strlen(dev->parent->name) + strlen(dev->name) + 4);
> +	if (!name)
> +		return -ENOMEM;
> +	sprintf(name, "%s:%s", dev->parent->name, dev->name);
> +
> +	priv->cfg.name = name;
> +	priv->cfg.host_caps = MMC_MODE_SPI;
> +	priv->cfg.voltages = MMC_SPI_VOLTAGE;
> +	priv->cfg.f_min = MMC_SPI_MIN_CLOCK;
> +	priv->cfg.f_max = priv->spi->max_hz;
> +	priv->cfg.part_type = PART_TYPE_DOS;
> +	priv->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
> +
> +	priv->mmc.cfg = &priv->cfg;
> +	priv->mmc.priv = priv;
> +	priv->mmc.dev = dev;
> +
> +	upriv->mmc = &priv->mmc;
> 
> -	debug("%s: clock %u\n", __func__, mmc->clock);
> -	if (mmc->clock)
> -		spi_set_speed(spi, mmc->clock);
>  	return 0;
>  }
> 
> -static int mmc_spi_init_p(struct mmc *mmc)
> +static int mmc_spi_bind(struct udevice *dev)
>  {
> -	struct spi_slave *spi = mmc->priv;
> -	spi_set_speed(spi, MMC_SPI_MIN_CLOCK);
> -	spi_claim_bus(spi);
> -	/* cs deactivated for 100+ clock */
> -	spi_xfer(spi, 18 * 8, NULL, NULL, 0);
> -	spi_release_bus(spi);
> -	return 0;
> +	struct mmc_spi_priv *priv = dev_get_priv(dev);
> +
> +	return mmc_bind(dev, &priv->mmc, &priv->cfg);
>  }
> 
> -static const struct mmc_ops mmc_spi_ops = {
> -	.send_cmd	= mmc_spi_request,
> -	.set_ios	= mmc_spi_set_ios,
> -	.init		= mmc_spi_init_p,
> +static const struct dm_mmc_ops mmc_spi_ops = {
> +	.send_cmd	= dm_mmc_spi_request,
> +	.set_ios	= dm_mmc_spi_set_ios,
>  };
> 
> -static struct mmc_config mmc_spi_cfg = {
> -	.name		= "MMC_SPI",
> -	.ops		= &mmc_spi_ops,
> -	.host_caps	= MMC_MODE_SPI,
> -	.voltages	= MMC_SPI_VOLTAGE,
> -	.f_min		= MMC_SPI_MIN_CLOCK,
> -	.part_type	= PART_TYPE_DOS,
> -	.b_max		= CONFIG_SYS_MMC_MAX_BLK_COUNT,
> +static const struct udevice_id dm_mmc_spi_match[] = {
> +	{ .compatible = "mmc-spi-slot" },
> +	{ /* sentinel */ }
>  };
> 
> -struct mmc *mmc_spi_init(uint bus, uint cs, uint speed, uint mode) -{
> -	struct mmc *mmc;
> -	struct spi_slave *spi;
> -
> -	spi = spi_setup_slave(bus, cs, speed, mode);
> -	if (spi == NULL)
> -		return NULL;
> -
> -	mmc_spi_cfg.f_max = speed;
> -
> -	mmc = mmc_create(&mmc_spi_cfg, spi);
> -	if (mmc == NULL) {
> -		spi_free_slave(spi);
> -		return NULL;
> -	}
> -	return mmc;
> -}
> +U_BOOT_DRIVER(mmc_spi) = {
> +	.name = "mmc_spi",
> +	.id = UCLASS_MMC,
> +	.of_match = dm_mmc_spi_match,
> +	.ops = &mmc_spi_ops,
> +	.probe = mmc_spi_probe,
> +	.bind = mmc_spi_bind,
> +	.priv_auto_alloc_size = sizeof(struct mmc_spi_priv), };
> diff --git a/scripts/config_whitelist.txt b/scripts/config_whitelist.txt index
> 8651d569c5..0ce7016e84 100644
> --- a/scripts/config_whitelist.txt
> +++ b/scripts/config_whitelist.txt
> @@ -1182,12 +1182,6 @@ CONFIG_MMCBOOTCOMMAND
> CONFIG_MMCROOT  CONFIG_MMC_DEFAULT_DEV
> CONFIG_MMC_RPMB_TRACE -CONFIG_MMC_SPI -CONFIG_MMC_SPI_BUS
> -CONFIG_MMC_SPI_CRC_ON -CONFIG_MMC_SPI_CS
> -CONFIG_MMC_SPI_MODE -CONFIG_MMC_SPI_SPEED
> CONFIG_MMC_SUNXI_SLOT  CONFIG_MMU
> CONFIG_MONITOR_IS_IN_RAM
> --
> 2.17.1
Bin Meng July 11, 2019, 6:49 a.m. UTC | #2
Hi Peng,

On Thu, Jul 11, 2019 at 2:36 PM Peng Fan <peng.fan@nxp.com> wrote:
>
> Hi Anup,
>
> > Subject: [PATCH v3 3/6] mmc: mmc_spi: Re-write driver using DM framework
> >
> > From: Bhargav Shah <bhargavshah1988@gmail.com>
> >
> > This patch rewrites MMC SPI driver using U-Boot DM framework and get it's
> > working on SiFive Unleashed board.
>
> So you drop the non-DM part, I saw there are still one user
> ./include/configs/UCP1020.h:441:#define CONFIG_MMC_SPI
>
> Will this switching to DM break that?
>

This is addressed by the next patch in this series, by removing all
non-DM stuff from UCP1020 board as that board does not support DM at
all.

Regards,
Bin
Peng Fan July 11, 2019, 7:10 a.m. UTC | #3
Hi Bin

> Subject: Re: [PATCH v3 3/6] mmc: mmc_spi: Re-write driver using DM
> framework
> 
> Hi Peng,
> 
> On Thu, Jul 11, 2019 at 2:36 PM Peng Fan <peng.fan@nxp.com> wrote:
> >
> > Hi Anup,
> >
> > > Subject: [PATCH v3 3/6] mmc: mmc_spi: Re-write driver using DM
> > > framework
> > >
> > > From: Bhargav Shah <bhargavshah1988@gmail.com>
> > >
> > > This patch rewrites MMC SPI driver using U-Boot DM framework and get
> > > it's working on SiFive Unleashed board.
> >
> > So you drop the non-DM part, I saw there are still one user
> > ./include/configs/UCP1020.h:441:#define CONFIG_MMC_SPI
> >
> > Will this switching to DM break that?
> >
> 
> This is addressed by the next patch in this series, by removing all non-DM stuff
> from UCP1020 board as that board does not support DM at all.

Not related to the UCP1020 board.
But SPL_DM is not a must, so removing the non-DM support will break non DM SPL
I understand there might be users now, but is it really good to totally remove
the non-DM code?

Regards,
Peng.
> 
> Regards,
> Bin
Bin Meng July 11, 2019, 7:13 a.m. UTC | #4
Hi Peng,

On Thu, Jul 11, 2019 at 3:10 PM Peng Fan <peng.fan@nxp.com> wrote:
>
> Hi Bin
>
> > Subject: Re: [PATCH v3 3/6] mmc: mmc_spi: Re-write driver using DM
> > framework
> >
> > Hi Peng,
> >
> > On Thu, Jul 11, 2019 at 2:36 PM Peng Fan <peng.fan@nxp.com> wrote:
> > >
> > > Hi Anup,
> > >
> > > > Subject: [PATCH v3 3/6] mmc: mmc_spi: Re-write driver using DM
> > > > framework
> > > >
> > > > From: Bhargav Shah <bhargavshah1988@gmail.com>
> > > >
> > > > This patch rewrites MMC SPI driver using U-Boot DM framework and get
> > > > it's working on SiFive Unleashed board.
> > >
> > > So you drop the non-DM part, I saw there are still one user
> > > ./include/configs/UCP1020.h:441:#define CONFIG_MMC_SPI
> > >
> > > Will this switching to DM break that?
> > >
> >
> > This is addressed by the next patch in this series, by removing all non-DM stuff
> > from UCP1020 board as that board does not support DM at all.
>
> Not related to the UCP1020 board.
> But SPL_DM is not a must, so removing the non-DM support will break non DM SPL
> I understand there might be users now, but is it really good to totally remove
> the non-DM code?

I think if some board in the future that wants to support this MMC SPI
in SPL without DM, someone needs to add that support back. Keep the
codes un-maintained and un-tested in the mainline is not so good IMHO.

Regards,
Bin
Peng Fan July 11, 2019, 7:30 a.m. UTC | #5
> Subject: Re: [PATCH v3 3/6] mmc: mmc_spi: Re-write driver using DM
> framework
> 
> Hi Peng,
> 
> On Thu, Jul 11, 2019 at 3:10 PM Peng Fan <peng.fan@nxp.com> wrote:
> >
> > Hi Bin
> >
> > > Subject: Re: [PATCH v3 3/6] mmc: mmc_spi: Re-write driver using DM
> > > framework
> > >
> > > Hi Peng,
> > >
> > > On Thu, Jul 11, 2019 at 2:36 PM Peng Fan <peng.fan@nxp.com> wrote:
> > > >
> > > > Hi Anup,
> > > >
> > > > > Subject: [PATCH v3 3/6] mmc: mmc_spi: Re-write driver using DM
> > > > > framework
> > > > >
> > > > > From: Bhargav Shah <bhargavshah1988@gmail.com>
> > > > >
> > > > > This patch rewrites MMC SPI driver using U-Boot DM framework and
> > > > > get it's working on SiFive Unleashed board.
> > > >
> > > > So you drop the non-DM part, I saw there are still one user
> > > > ./include/configs/UCP1020.h:441:#define CONFIG_MMC_SPI
> > > >
> > > > Will this switching to DM break that?
> > > >
> > >
> > > This is addressed by the next patch in this series, by removing all
> > > non-DM stuff from UCP1020 board as that board does not support DM at
> all.
> >
> > Not related to the UCP1020 board.
> > But SPL_DM is not a must, so removing the non-DM support will break
> > non DM SPL I understand there might be users now, but is it really
> > good to totally remove the non-DM code?
> 
> I think if some board in the future that wants to support this MMC SPI in SPL
> without DM, someone needs to add that support back. Keep the codes
> un-maintained and un-tested in the mainline is not so good IMHO.

ok.

Anup,
I saw the patchset was assigned to me in patchwork.
But patch 1/6 is an SPI driver.
Do you expect me to take the series?

Jagan, are you ok? Or assign this 1/6 to you?

Thanks,
Peng.

> 
> Regards,
> Bin
Anup Patel July 14, 2019, 4:16 a.m. UTC | #6
Hi Peng Fan,

On Thu, Jul 11, 2019 at 1:00 PM Peng Fan <peng.fan@nxp.com> wrote:
>
>
> > Subject: Re: [PATCH v3 3/6] mmc: mmc_spi: Re-write driver using DM
> > framework
> >
> > Hi Peng,
> >
> > On Thu, Jul 11, 2019 at 3:10 PM Peng Fan <peng.fan@nxp.com> wrote:
> > >
> > > Hi Bin
> > >
> > > > Subject: Re: [PATCH v3 3/6] mmc: mmc_spi: Re-write driver using DM
> > > > framework
> > > >
> > > > Hi Peng,
> > > >
> > > > On Thu, Jul 11, 2019 at 2:36 PM Peng Fan <peng.fan@nxp.com> wrote:
> > > > >
> > > > > Hi Anup,
> > > > >
> > > > > > Subject: [PATCH v3 3/6] mmc: mmc_spi: Re-write driver using DM
> > > > > > framework
> > > > > >
> > > > > > From: Bhargav Shah <bhargavshah1988@gmail.com>
> > > > > >
> > > > > > This patch rewrites MMC SPI driver using U-Boot DM framework and
> > > > > > get it's working on SiFive Unleashed board.
> > > > >
> > > > > So you drop the non-DM part, I saw there are still one user
> > > > > ./include/configs/UCP1020.h:441:#define CONFIG_MMC_SPI
> > > > >
> > > > > Will this switching to DM break that?
> > > > >
> > > >
> > > > This is addressed by the next patch in this series, by removing all
> > > > non-DM stuff from UCP1020 board as that board does not support DM at
> > all.
> > >
> > > Not related to the UCP1020 board.
> > > But SPL_DM is not a must, so removing the non-DM support will break
> > > non DM SPL I understand there might be users now, but is it really
> > > good to totally remove the non-DM code?
> >
> > I think if some board in the future that wants to support this MMC SPI in SPL
> > without DM, someone needs to add that support back. Keep the codes
> > un-maintained and un-tested in the mainline is not so good IMHO.
>
> ok.
>
> Anup,
> I saw the patchset was assigned to me in patchwork.
> But patch 1/6 is an SPI driver.
> Do you expect me to take the series?

You can certainely pickup PATCH2, PATCH3, and PATCH4 from
this series because these patches have nothing to do with
SiFive SPI driver OR SiFive Unleashed board.

Meanwhile, I will keep following up with Jagan on PATCH1.

The PATCH5 and PATCH6 can go through U-Boot RISC-V tree
which Rick can pickup.

Regards,
Anup

>
> Jagan, are you ok? Or assign this 1/6 to you?
>
> Thanks,
> Peng.
>
> >
> > Regards,
> > Bin
Peng Fan July 15, 2019, 7:06 a.m. UTC | #7
> Subject: [PATCH v3 3/6] mmc: mmc_spi: Re-write driver using DM framework
> 
> From: Bhargav Shah <bhargavshah1988@gmail.com>
> 
> This patch rewrites MMC SPI driver using U-Boot DM framework and get it's
> working on SiFive Unleashed board.
> 
> Signed-off-by: Bhargav Shah <bhargavshah1988@gmail.com>
> Signed-off-by: Anup Patel <anup.patel@wdc.com>
> Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
> Tested-by: Bin Meng <bmeng.cn@gmail.com>
> ---
>  drivers/mmc/Kconfig          |  18 ++
>  drivers/mmc/mmc_spi.c        | 469
> ++++++++++++++++++++++-------------
>  scripts/config_whitelist.txt |   6 -
>  3 files changed, 320 insertions(+), 173 deletions(-)
> 
> diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index
> c23299ea96..f750dad00a 100644
> --- a/drivers/mmc/Kconfig
> +++ b/drivers/mmc/Kconfig
> @@ -46,6 +46,24 @@ config SPL_DM_MMC
> 
>  if MMC
> 
> +config MMC_SPI
> +	bool "Support for SPI-based MMC controller"
> +	depends on DM_MMC && DM_SPI
> +	help
> +	  This selects SPI-based MMC controllers.
> +	  If you have an MMC controller on a SPI bus, say Y here.
> +
> +	  If unsure, say N.
> +
> +config MMC_SPI_CRC_ON
> +	bool "Support CRC for SPI-based MMC controller"
> +	depends on MMC_SPI
> +	default y
> +	help
> +	  This enables CRC for SPI-based MMC controllers.
> +
> +	  If unsure, say N.
> +
>  config ARM_PL180_MMCI
>  	bool "ARM AMBA Multimedia Card Interface and compatible support"
>  	depends on DM_MMC && OF_CONTROL
> diff --git a/drivers/mmc/mmc_spi.c b/drivers/mmc/mmc_spi.c index
> 4f57990d9c..f3d687ae80 100644
> --- a/drivers/mmc/mmc_spi.c
> +++ b/drivers/mmc/mmc_spi.c
> @@ -2,6 +2,8 @@
>   * generic mmc spi driver
>   *
>   * Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw>
> + * Copyright 2019 Bhargav Shah <bhargavshah1988@gmail.com>
> + *
>   * Licensed under the GPL-2 or later.
>   */
>  #include <common.h>
> @@ -9,21 +11,23 @@
>  #include <malloc.h>
>  #include <part.h>
>  #include <mmc.h>
> -#include <spi.h>
> +#include <stdlib.h>
>  #include <u-boot/crc.h>
>  #include <linux/crc7.h>
>  #include <asm/byteorder.h>
> +#include <dm.h>
> +#include <spi.h>
> 
>  /* MMC/SD in SPI mode reports R1 status always */
> -#define R1_SPI_IDLE		(1 << 0)
> -#define R1_SPI_ERASE_RESET	(1 << 1)
> -#define R1_SPI_ILLEGAL_COMMAND	(1 << 2)
> -#define R1_SPI_COM_CRC		(1 << 3)
> -#define R1_SPI_ERASE_SEQ	(1 << 4)
> -#define R1_SPI_ADDRESS		(1 << 5)
> -#define R1_SPI_PARAMETER	(1 << 6)
> +#define R1_SPI_IDLE			BIT(0)
> +#define R1_SPI_ERASE_RESET		BIT(1)
> +#define R1_SPI_ILLEGAL_COMMAND		BIT(2)
> +#define R1_SPI_COM_CRC			BIT(3)
> +#define R1_SPI_ERASE_SEQ		BIT(4)
> +#define R1_SPI_ADDRESS			BIT(5)
> +#define R1_SPI_PARAMETER		BIT(6)
>  /* R1 bit 7 is always zero, reuse this bit for error */
> -#define R1_SPI_ERROR		(1 << 7)
> +#define R1_SPI_ERROR			BIT(7)
> 
>  /* Response tokens used to ack each block written: */
>  #define SPI_MMC_RESPONSE_CODE(x)	((x) & 0x1f)
> @@ -34,28 +38,45 @@
>  /* Read and write blocks start with these tokens and end with crc;
>   * on error, read tokens act like a subset of R2_SPI_* values.
>   */
> -#define SPI_TOKEN_SINGLE	0xfe	/* single block r/w, multiblock read */
> -#define SPI_TOKEN_MULTI_WRITE	0xfc	/* multiblock write */
> -#define SPI_TOKEN_STOP_TRAN	0xfd	/* terminate multiblock write */
> +/* single block write multiblock read */
> +#define SPI_TOKEN_SINGLE		0xfe
> +/* multiblock write */
> +#define SPI_TOKEN_MULTI_WRITE		0xfc
> +/* terminate multiblock write */
> +#define SPI_TOKEN_STOP_TRAN		0xfd
> 
>  /* MMC SPI commands start with a start bit "0" and a transmit bit "1" */
> -#define MMC_SPI_CMD(x) (0x40 | (x & 0x3f))
> +#define MMC_SPI_CMD(x) (0x40 | (x))
> 
>  /* bus capability */
> -#define MMC_SPI_VOLTAGE (MMC_VDD_32_33 | MMC_VDD_33_34)
> -#define MMC_SPI_MIN_CLOCK 400000 /* 400KHz to meet MMC spec */
> +#define MMC_SPI_VOLTAGE			(MMC_VDD_32_33 |
> MMC_VDD_33_34)
> +#define MMC_SPI_MIN_CLOCK		400000	/* 400KHz to meet MMC
> spec */
> +#define MMC_SPI_MAX_CLOCK		25000000 /* SD/MMC legacy speed */
> 
>  /* timeout value */
> -#define CTOUT 8
> -#define RTOUT 3000000 /* 1 sec */
> -#define WTOUT 3000000 /* 1 sec */
> +#define CMD_TIMEOUT			8
> +#define READ_TIMEOUT			3000000 /* 1 sec */
> +#define WRITE_TIMEOUT			3000000 /* 1 sec */
> 
> -static uint mmc_spi_sendcmd(struct mmc *mmc, ushort cmdidx, u32
> cmdarg)
> +struct mmc_spi_priv {
> +	struct spi_slave *spi;
> +	struct mmc_config cfg;
> +	struct mmc mmc;
> +};
> +
> +static int mmc_spi_sendcmd(struct udevice *dev,
> +			   ushort cmdidx, u32 cmdarg, u32 resp_type,
> +			   u8 *resp, u32 resp_size,
> +			   bool resp_match, u8 resp_match_value)
>  {
> -	struct spi_slave *spi = mmc->priv;
> -	u8 cmdo[7];
> -	u8 r1;
> -	int i;
> +	int i, rpos = 0, ret = 0;
> +	u8 cmdo[7], r;
> +
> +	debug("%s: cmd%d cmdarg=0x%x resp_type=0x%x "
> +	      "resp_size=%d resp_match=%d resp_match_value=0x%x\n",
> +	      __func__, cmdidx, cmdarg, resp_type,
> +	      resp_size, resp_match, resp_match_value);
> +
>  	cmdo[0] = 0xff;
>  	cmdo[1] = MMC_SPI_CMD(cmdidx);
>  	cmdo[2] = cmdarg >> 24;
> @@ -63,37 +84,79 @@ static uint mmc_spi_sendcmd(struct mmc *mmc,
> ushort cmdidx, u32 cmdarg)
>  	cmdo[4] = cmdarg >> 8;
>  	cmdo[5] = cmdarg;
>  	cmdo[6] = (crc7(0, &cmdo[1], 5) << 1) | 0x01;
> -	spi_xfer(spi, sizeof(cmdo) * 8, cmdo, NULL, 0);
> -	for (i = 0; i < CTOUT; i++) {
> -		spi_xfer(spi, 1 * 8, NULL, &r1, 0);
> -		if (i && (r1 & 0x80) == 0) /* r1 response */
> -			break;
> +	ret = dm_spi_xfer(dev, sizeof(cmdo) * 8, cmdo, NULL, 0);
> +	if (ret)
> +		return ret;
> +
> +	ret = dm_spi_xfer(dev, 1 * 8, NULL, &r, 0);
> +	if (ret)
> +		return ret;
> +
> +	if (!resp || !resp_size)
> +		return 0;
> +
> +	debug("%s: cmd%d", __func__, cmdidx);
> +
> +	if (resp_match) {
> +		r = ~resp_match_value;
> +		i = CMD_TIMEOUT;
> +		while (i--) {
> +			ret = dm_spi_xfer(dev, 1 * 8, NULL, &r, 0);
> +			if (ret)
> +				return ret;
> +			debug(" resp%d=0x%x", rpos, r);
> +			rpos++;
> +			if (r == resp_match_value)
> +				break;
> +		}
> +		if (!i && (r != resp_match_value))
> +			return -ETIMEDOUT;
> +	}
> +
> +	for (i = 0; i < resp_size; i++) {
> +		if (i == 0 && resp_match) {
> +			resp[i] = resp_match_value;
> +			continue;
> +		}
> +		ret = dm_spi_xfer(dev, 1 * 8, NULL, &r, 0);
> +		if (ret)
> +			return ret;
> +		debug(" resp%d=0x%x", rpos, r);
> +		rpos++;
> +		resp[i] = r;
>  	}
> -	debug("%s:cmd%d resp%d %x\n", __func__, cmdidx, i, r1);
> -	return r1;
> +
> +	debug("\n");
> +
> +	return 0;
>  }
> 
> -static uint mmc_spi_readdata(struct mmc *mmc, void *xbuf,
> -				u32 bcnt, u32 bsize)
> +static int mmc_spi_readdata(struct udevice *dev,
> +			    void *xbuf, u32 bcnt, u32 bsize)
>  {
> -	struct spi_slave *spi = mmc->priv;
> -	u8 *buf = xbuf;
> -	u8 r1;
>  	u16 crc;
> -	int i;
> +	u8 *buf = xbuf, r1;
> +	int i, ret = 0;
> +
>  	while (bcnt--) {
> -		for (i = 0; i < RTOUT; i++) {
> -			spi_xfer(spi, 1 * 8, NULL, &r1, 0);
> -			if (r1 != 0xff) /* data token */
> +		for (i = 0; i < READ_TIMEOUT; i++) {
> +			ret = dm_spi_xfer(dev, 1 * 8, NULL, &r1, 0);
> +			if (ret)
> +				return ret;
> +			if (r1 == SPI_TOKEN_SINGLE)
>  				break;
>  		}
> -		debug("%s:tok%d %x\n", __func__, i, r1);
> +		debug("%s: data tok%d 0x%x\n", __func__, i, r1);
>  		if (r1 == SPI_TOKEN_SINGLE) {
> -			spi_xfer(spi, bsize * 8, NULL, buf, 0);
> -			spi_xfer(spi, 2 * 8, NULL, &crc, 0);
> +			ret = dm_spi_xfer(dev, bsize * 8, NULL, buf, 0);
> +			if (ret)
> +				return ret;
> +			ret = dm_spi_xfer(dev, 2 * 8, NULL, &crc, 0);
> +			if (ret)
> +				return ret;
>  #ifdef CONFIG_MMC_SPI_CRC_ON
> -			if (be_to_cpu16(crc16_ccitt(0, buf, bsize)) != crc) {
> -				debug("%s: CRC error\n", mmc->cfg->name);
> +			if (be16_to_cpu(crc16_ccitt(0, buf, bsize)) != crc) {
> +				debug("%s: data crc error\n", __func__);
>  				r1 = R1_SPI_COM_CRC;
>  				break;
>  			}
> @@ -105,48 +168,56 @@ static uint mmc_spi_readdata(struct mmc *mmc,
> void *xbuf,
>  		}
>  		buf += bsize;
>  	}
> -	return r1;
> +
> +	if (r1 & R1_SPI_COM_CRC)
> +		ret = -ECOMM;
> +	else if (r1) /* other errors */
> +		ret = -ETIMEDOUT;
> +
> +	return ret;
>  }
> 
> -static uint mmc_spi_writedata(struct mmc *mmc, const void *xbuf,
> -			      u32 bcnt, u32 bsize, int multi)
> +static int mmc_spi_writedata(struct udevice *dev, const void *xbuf,
> +			     u32 bcnt, u32 bsize, int multi)
>  {
> -	struct spi_slave *spi = mmc->priv;
>  	const u8 *buf = xbuf;
> -	u8 r1;
> +	u8 r1, tok[2];
>  	u16 crc;
> -	u8 tok[2];
> -	int i;
> +	int i, ret = 0;
> +
>  	tok[0] = 0xff;
>  	tok[1] = multi ? SPI_TOKEN_MULTI_WRITE : SPI_TOKEN_SINGLE;
> +
>  	while (bcnt--) {
>  #ifdef CONFIG_MMC_SPI_CRC_ON
>  		crc = cpu_to_be16(crc16_ccitt(0, (u8 *)buf, bsize));  #endif
> -		spi_xfer(spi, 2 * 8, tok, NULL, 0);
> -		spi_xfer(spi, bsize * 8, buf, NULL, 0);
> -		spi_xfer(spi, 2 * 8, &crc, NULL, 0);
> -		for (i = 0; i < CTOUT; i++) {
> -			spi_xfer(spi, 1 * 8, NULL, &r1, 0);
> +		dm_spi_xfer(dev, 2 * 8, tok, NULL, 0);
> +		dm_spi_xfer(dev, bsize * 8, buf, NULL, 0);
> +		dm_spi_xfer(dev, 2 * 8, &crc, NULL, 0);
> +		for (i = 0; i < CMD_TIMEOUT; i++) {
> +			dm_spi_xfer(dev, 1 * 8, NULL, &r1, 0);
>  			if ((r1 & 0x10) == 0) /* response token */
>  				break;
>  		}
> -		debug("%s:tok%d %x\n", __func__, i, r1);
> +		debug("%s: data tok%d 0x%x\n", __func__, i, r1);
>  		if (SPI_MMC_RESPONSE_CODE(r1) == SPI_RESPONSE_ACCEPTED) {
> -			for (i = 0; i < WTOUT; i++) { /* wait busy */
> -				spi_xfer(spi, 1 * 8, NULL, &r1, 0);
> +			debug("%s: data accepted\n", __func__);
> +			for (i = 0; i < WRITE_TIMEOUT; i++) { /* wait busy */
> +				dm_spi_xfer(dev, 1 * 8, NULL, &r1, 0);
>  				if (i && r1 == 0xff) {
>  					r1 = 0;
>  					break;
>  				}
>  			}
> -			if (i == WTOUT) {
> -				debug("%s:wtout %x\n", __func__, r1);
> +			if (i == WRITE_TIMEOUT) {
> +				debug("%s: data write timeout 0x%x\n",
> +				      __func__, r1);
>  				r1 = R1_SPI_ERROR;
>  				break;
>  			}
>  		} else {
> -			debug("%s: err %x\n", __func__, r1);
> +			debug("%s: data error 0x%x\n", __func__, r1);
>  			r1 = R1_SPI_COM_CRC;
>  			break;
>  		}
> @@ -154,140 +225,204 @@ static uint mmc_spi_writedata(struct mmc
> *mmc, const void *xbuf,
>  	}
>  	if (multi && bcnt == -1) { /* stop multi write */
>  		tok[1] = SPI_TOKEN_STOP_TRAN;
> -		spi_xfer(spi, 2 * 8, tok, NULL, 0);
> -		for (i = 0; i < WTOUT; i++) { /* wait busy */
> -			spi_xfer(spi, 1 * 8, NULL, &r1, 0);
> +		dm_spi_xfer(dev, 2 * 8, tok, NULL, 0);
> +		for (i = 0; i < WRITE_TIMEOUT; i++) { /* wait busy */
> +			dm_spi_xfer(dev, 1 * 8, NULL, &r1, 0);
>  			if (i && r1 == 0xff) {
>  				r1 = 0;
>  				break;
>  			}
>  		}
> -		if (i == WTOUT) {
> -			debug("%s:wstop %x\n", __func__, r1);
> +		if (i == WRITE_TIMEOUT) {
> +			debug("%s: data write timeout 0x%x\n", __func__, r1);
>  			r1 = R1_SPI_ERROR;
>  		}
>  	}
> -	return r1;
> -}
> 
> -static int mmc_spi_request(struct mmc *mmc, struct mmc_cmd *cmd,
> -		struct mmc_data *data)
> -{
> -	struct spi_slave *spi = mmc->priv;
> -	u8 r1;
> -	int i;
> -	int ret = 0;
> -	debug("%s:cmd%d %x %x\n", __func__,
> -	      cmd->cmdidx, cmd->resp_type, cmd->cmdarg);
> -	spi_claim_bus(spi);
> -	spi_cs_activate(spi);
> -	r1 = mmc_spi_sendcmd(mmc, cmd->cmdidx, cmd->cmdarg);
> -	if (r1 == 0xff) { /* no response */
> -		ret = -ENOMEDIUM;
> -		goto done;
> -	} else if (r1 & R1_SPI_COM_CRC) {
> +	if (r1 & R1_SPI_COM_CRC)
>  		ret = -ECOMM;
> -		goto done;
> -	} else if (r1 & ~R1_SPI_IDLE) { /* other errors */
> +	else if (r1) /* other errors */
>  		ret = -ETIMEDOUT;
> +
> +	return ret;
> +}
> +
> +static int dm_mmc_spi_set_ios(struct udevice *dev) {
> +	return 0;
> +}
> +
> +static int dm_mmc_spi_request(struct udevice *dev, struct mmc_cmd *cmd,
> +			      struct mmc_data *data)
> +{
> +	int i, multi, ret = 0;
> +	u8 *resp = NULL;
> +	u32 resp_size = 0;
> +	bool resp_match = false;
> +	u8 resp8 = 0, resp40[5] = { 0 }, resp_match_value = 0;
> +
> +	dm_spi_claim_bus(dev);
> +
> +	for (i = 0; i < 4; i++)
> +		cmd->response[i] = 0;
> +
> +	switch (cmd->cmdidx) {
> +	case SD_CMD_APP_SEND_OP_COND:
> +	case MMC_CMD_SEND_OP_COND:
> +		resp = &resp8;
> +		resp_size = sizeof(resp8);
> +		cmd->cmdarg = 0x40000000;
> +		break;
> +	case SD_CMD_SEND_IF_COND:
> +		resp = (u8 *)&resp40[0];
> +		resp_size = sizeof(resp40);
> +		resp_match = true;
> +		resp_match_value = R1_SPI_IDLE;
> +		break;
> +	case MMC_CMD_SPI_READ_OCR:
> +		resp = (u8 *)&resp40[0];
> +		resp_size = sizeof(resp40);
> +		break;
> +	case MMC_CMD_SEND_STATUS:
> +	case MMC_CMD_SET_BLOCKLEN:
> +	case MMC_CMD_SPI_CRC_ON_OFF:
> +	case MMC_CMD_STOP_TRANSMISSION:
> +		resp = &resp8;
> +		resp_size = sizeof(resp8);
> +		resp_match = true;
> +		resp_match_value = 0x0;
> +		break;
> +	case MMC_CMD_SEND_CSD:
> +	case MMC_CMD_SEND_CID:
> +	case MMC_CMD_READ_SINGLE_BLOCK:
> +	case MMC_CMD_READ_MULTIPLE_BLOCK:
> +	case MMC_CMD_WRITE_SINGLE_BLOCK:
> +	case MMC_CMD_WRITE_MULTIPLE_BLOCK:
> +		break;
> +	default:
> +		resp = &resp8;
> +		resp_size = sizeof(resp8);
> +		resp_match = true;
> +		resp_match_value = R1_SPI_IDLE;
> +		break;
> +	};
> +
> +	ret = mmc_spi_sendcmd(dev, cmd->cmdidx, cmd->cmdarg,
> cmd->resp_type,
> +			      resp, resp_size, resp_match, resp_match_value);
> +	if (ret)
>  		goto done;
> -	} else if (cmd->resp_type == MMC_RSP_R2) {
> -		r1 = mmc_spi_readdata(mmc, cmd->response, 1, 16);
> +
> +	switch (cmd->cmdidx) {
> +	case SD_CMD_APP_SEND_OP_COND:
> +	case MMC_CMD_SEND_OP_COND:
> +		cmd->response[0] = (resp8 & R1_SPI_IDLE) ? 0 : OCR_BUSY;
> +		break;
> +	case SD_CMD_SEND_IF_COND:
> +	case MMC_CMD_SPI_READ_OCR:
> +		cmd->response[0] = resp40[4];
> +		cmd->response[0] |= (uint)resp40[3] << 8;
> +		cmd->response[0] |= (uint)resp40[2] << 16;
> +		cmd->response[0] |= (uint)resp40[1] << 24;
> +		break;
> +	case MMC_CMD_SEND_STATUS:
> +		cmd->response[0] = (resp8 & 0xff) ?
> +			MMC_STATUS_ERROR : MMC_STATUS_RDY_FOR_DATA;
> +		break;
> +	case MMC_CMD_SEND_CID:
> +	case MMC_CMD_SEND_CSD:
> +		ret = mmc_spi_readdata(dev, cmd->response, 1, 16);
> +		if (ret)
> +			return ret;
>  		for (i = 0; i < 4; i++)
> -			cmd->response[i] = be32_to_cpu(cmd->response[i]);
> -		debug("r128 %x %x %x %x\n", cmd->response[0],
> cmd->response[1],
> -		      cmd->response[2], cmd->response[3]);
> -	} else if (!data) {
> -		switch (cmd->cmdidx) {
> -		case SD_CMD_APP_SEND_OP_COND:
> -		case MMC_CMD_SEND_OP_COND:
> -			cmd->response[0] = (r1 & R1_SPI_IDLE) ? 0 : OCR_BUSY;
> -			break;
> -		case SD_CMD_SEND_IF_COND:
> -		case MMC_CMD_SPI_READ_OCR:
> -			spi_xfer(spi, 4 * 8, NULL, cmd->response, 0);
> -			cmd->response[0] = be32_to_cpu(cmd->response[0]);
> -			debug("r32 %x\n", cmd->response[0]);
> -			break;
> -		case MMC_CMD_SEND_STATUS:
> -			spi_xfer(spi, 1 * 8, NULL, cmd->response, 0);
> -			cmd->response[0] = (cmd->response[0] & 0xff) ?
> -				MMC_STATUS_ERROR : MMC_STATUS_RDY_FOR_DATA;
> -			break;
> -		}
> -	} else {
> -		debug("%s:data %x %x %x\n", __func__,
> -		      data->flags, data->blocks, data->blocksize);
> +			cmd->response[i] =
> +				cpu_to_be32(cmd->response[i]);
> +		break;
> +	default:
> +		cmd->response[0] = resp8;
> +		break;
> +	}
> +
> +	debug("%s: cmd%d resp0=0x%x resp1=0x%x resp2=0x%x
> resp3=0x%x\n",
> +	      __func__, cmd->cmdidx, cmd->response[0], cmd->response[1],
> +	      cmd->response[2], cmd->response[3]);
> +
> +	if (data) {
> +		debug("%s: data flags=0x%x blocks=%d block_size=%d\n",
> +		      __func__, data->flags, data->blocks, data->blocksize);
> +		multi = (cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK);
>  		if (data->flags == MMC_DATA_READ)
> -			r1 = mmc_spi_readdata(mmc, data->dest,
> -				data->blocks, data->blocksize);
> +			ret = mmc_spi_readdata(dev, data->dest,
> +					       data->blocks, data->blocksize);
>  		else if  (data->flags == MMC_DATA_WRITE)
> -			r1 = mmc_spi_writedata(mmc, data->src,
> -				data->blocks, data->blocksize,
> -				(cmd->cmdidx ==
> MMC_CMD_WRITE_MULTIPLE_BLOCK));
> -		if (r1 & R1_SPI_COM_CRC)
> -			ret = -ECOMM;
> -		else if (r1) /* other errors */
> -			ret = -ETIMEDOUT;
> +			ret = mmc_spi_writedata(dev, data->src,
> +						data->blocks, data->blocksize,
> +						multi);
>  	}
> +
>  done:
> -	spi_cs_deactivate(spi);
> -	spi_release_bus(spi);
> +	dm_spi_release_bus(dev);
> +
>  	return ret;
>  }
> 
> -static int mmc_spi_set_ios(struct mmc *mmc)
> +static int mmc_spi_probe(struct udevice *dev)
>  {
> -	struct spi_slave *spi = mmc->priv;
> +	struct mmc_spi_priv *priv = dev_get_priv(dev);
> +	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
> +	char *name;
> +
> +	priv->spi = dev_get_parent_priv(dev);
> +	if (!priv->spi->max_hz)
> +		priv->spi->max_hz = MMC_SPI_MAX_CLOCK;
> +	priv->spi->speed = 0;
> +	priv->spi->mode = SPI_MODE_0;
> +	priv->spi->wordlen = 8;
> +
> +	name = malloc(strlen(dev->parent->name) + strlen(dev->name) + 4);
> +	if (!name)
> +		return -ENOMEM;
> +	sprintf(name, "%s:%s", dev->parent->name, dev->name);
> +
> +	priv->cfg.name = name;
> +	priv->cfg.host_caps = MMC_MODE_SPI;
> +	priv->cfg.voltages = MMC_SPI_VOLTAGE;
> +	priv->cfg.f_min = MMC_SPI_MIN_CLOCK;
> +	priv->cfg.f_max = priv->spi->max_hz;
> +	priv->cfg.part_type = PART_TYPE_DOS;
> +	priv->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
> +
> +	priv->mmc.cfg = &priv->cfg;
> +	priv->mmc.priv = priv;
> +	priv->mmc.dev = dev;
> +
> +	upriv->mmc = &priv->mmc;
> 
> -	debug("%s: clock %u\n", __func__, mmc->clock);
> -	if (mmc->clock)
> -		spi_set_speed(spi, mmc->clock);
>  	return 0;
>  }
> 
> -static int mmc_spi_init_p(struct mmc *mmc)
> +static int mmc_spi_bind(struct udevice *dev)
>  {
> -	struct spi_slave *spi = mmc->priv;
> -	spi_set_speed(spi, MMC_SPI_MIN_CLOCK);
> -	spi_claim_bus(spi);
> -	/* cs deactivated for 100+ clock */
> -	spi_xfer(spi, 18 * 8, NULL, NULL, 0);
> -	spi_release_bus(spi);
> -	return 0;
> +	struct mmc_spi_priv *priv = dev_get_priv(dev);
> +
> +	return mmc_bind(dev, &priv->mmc, &priv->cfg);
>  }
> 
> -static const struct mmc_ops mmc_spi_ops = {
> -	.send_cmd	= mmc_spi_request,
> -	.set_ios	= mmc_spi_set_ios,
> -	.init		= mmc_spi_init_p,
> +static const struct dm_mmc_ops mmc_spi_ops = {
> +	.send_cmd	= dm_mmc_spi_request,
> +	.set_ios	= dm_mmc_spi_set_ios,
>  };
> 
> -static struct mmc_config mmc_spi_cfg = {
> -	.name		= "MMC_SPI",
> -	.ops		= &mmc_spi_ops,
> -	.host_caps	= MMC_MODE_SPI,
> -	.voltages	= MMC_SPI_VOLTAGE,
> -	.f_min		= MMC_SPI_MIN_CLOCK,
> -	.part_type	= PART_TYPE_DOS,
> -	.b_max		= CONFIG_SYS_MMC_MAX_BLK_COUNT,
> +static const struct udevice_id dm_mmc_spi_match[] = {
> +	{ .compatible = "mmc-spi-slot" },
> +	{ /* sentinel */ }
>  };
> 
> -struct mmc *mmc_spi_init(uint bus, uint cs, uint speed, uint mode) -{
> -	struct mmc *mmc;
> -	struct spi_slave *spi;
> -
> -	spi = spi_setup_slave(bus, cs, speed, mode);
> -	if (spi == NULL)
> -		return NULL;
> -
> -	mmc_spi_cfg.f_max = speed;
> -
> -	mmc = mmc_create(&mmc_spi_cfg, spi);
> -	if (mmc == NULL) {
> -		spi_free_slave(spi);
> -		return NULL;
> -	}
> -	return mmc;
> -}
> +U_BOOT_DRIVER(mmc_spi) = {
> +	.name = "mmc_spi",
> +	.id = UCLASS_MMC,
> +	.of_match = dm_mmc_spi_match,
> +	.ops = &mmc_spi_ops,
> +	.probe = mmc_spi_probe,
> +	.bind = mmc_spi_bind,
> +	.priv_auto_alloc_size = sizeof(struct mmc_spi_priv), };
> diff --git a/scripts/config_whitelist.txt b/scripts/config_whitelist.txt index
> 8651d569c5..0ce7016e84 100644
> --- a/scripts/config_whitelist.txt
> +++ b/scripts/config_whitelist.txt
> @@ -1182,12 +1182,6 @@ CONFIG_MMCBOOTCOMMAND
> CONFIG_MMCROOT  CONFIG_MMC_DEFAULT_DEV
> CONFIG_MMC_RPMB_TRACE -CONFIG_MMC_SPI -CONFIG_MMC_SPI_BUS
> -CONFIG_MMC_SPI_CRC_ON -CONFIG_MMC_SPI_CS
> -CONFIG_MMC_SPI_MODE -CONFIG_MMC_SPI_SPEED
> CONFIG_MMC_SUNXI_SLOT  CONFIG_MMU
> CONFIG_MONITOR_IS_IN_RAM

Applied to mmc/master.

Thanks,
Peng.

> --
> 2.17.1
diff mbox series

Patch

diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index c23299ea96..f750dad00a 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -46,6 +46,24 @@  config SPL_DM_MMC
 
 if MMC
 
+config MMC_SPI
+	bool "Support for SPI-based MMC controller"
+	depends on DM_MMC && DM_SPI
+	help
+	  This selects SPI-based MMC controllers.
+	  If you have an MMC controller on a SPI bus, say Y here.
+
+	  If unsure, say N.
+
+config MMC_SPI_CRC_ON
+	bool "Support CRC for SPI-based MMC controller"
+	depends on MMC_SPI
+	default y
+	help
+	  This enables CRC for SPI-based MMC controllers.
+
+	  If unsure, say N.
+
 config ARM_PL180_MMCI
 	bool "ARM AMBA Multimedia Card Interface and compatible support"
 	depends on DM_MMC && OF_CONTROL
diff --git a/drivers/mmc/mmc_spi.c b/drivers/mmc/mmc_spi.c
index 4f57990d9c..f3d687ae80 100644
--- a/drivers/mmc/mmc_spi.c
+++ b/drivers/mmc/mmc_spi.c
@@ -2,6 +2,8 @@ 
  * generic mmc spi driver
  *
  * Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw>
+ * Copyright 2019 Bhargav Shah <bhargavshah1988@gmail.com>
+ *
  * Licensed under the GPL-2 or later.
  */
 #include <common.h>
@@ -9,21 +11,23 @@ 
 #include <malloc.h>
 #include <part.h>
 #include <mmc.h>
-#include <spi.h>
+#include <stdlib.h>
 #include <u-boot/crc.h>
 #include <linux/crc7.h>
 #include <asm/byteorder.h>
+#include <dm.h>
+#include <spi.h>
 
 /* MMC/SD in SPI mode reports R1 status always */
-#define R1_SPI_IDLE		(1 << 0)
-#define R1_SPI_ERASE_RESET	(1 << 1)
-#define R1_SPI_ILLEGAL_COMMAND	(1 << 2)
-#define R1_SPI_COM_CRC		(1 << 3)
-#define R1_SPI_ERASE_SEQ	(1 << 4)
-#define R1_SPI_ADDRESS		(1 << 5)
-#define R1_SPI_PARAMETER	(1 << 6)
+#define R1_SPI_IDLE			BIT(0)
+#define R1_SPI_ERASE_RESET		BIT(1)
+#define R1_SPI_ILLEGAL_COMMAND		BIT(2)
+#define R1_SPI_COM_CRC			BIT(3)
+#define R1_SPI_ERASE_SEQ		BIT(4)
+#define R1_SPI_ADDRESS			BIT(5)
+#define R1_SPI_PARAMETER		BIT(6)
 /* R1 bit 7 is always zero, reuse this bit for error */
-#define R1_SPI_ERROR		(1 << 7)
+#define R1_SPI_ERROR			BIT(7)
 
 /* Response tokens used to ack each block written: */
 #define SPI_MMC_RESPONSE_CODE(x)	((x) & 0x1f)
@@ -34,28 +38,45 @@ 
 /* Read and write blocks start with these tokens and end with crc;
  * on error, read tokens act like a subset of R2_SPI_* values.
  */
-#define SPI_TOKEN_SINGLE	0xfe	/* single block r/w, multiblock read */
-#define SPI_TOKEN_MULTI_WRITE	0xfc	/* multiblock write */
-#define SPI_TOKEN_STOP_TRAN	0xfd	/* terminate multiblock write */
+/* single block write multiblock read */
+#define SPI_TOKEN_SINGLE		0xfe
+/* multiblock write */
+#define SPI_TOKEN_MULTI_WRITE		0xfc
+/* terminate multiblock write */
+#define SPI_TOKEN_STOP_TRAN		0xfd
 
 /* MMC SPI commands start with a start bit "0" and a transmit bit "1" */
-#define MMC_SPI_CMD(x) (0x40 | (x & 0x3f))
+#define MMC_SPI_CMD(x) (0x40 | (x))
 
 /* bus capability */
-#define MMC_SPI_VOLTAGE (MMC_VDD_32_33 | MMC_VDD_33_34)
-#define MMC_SPI_MIN_CLOCK 400000 /* 400KHz to meet MMC spec */
+#define MMC_SPI_VOLTAGE			(MMC_VDD_32_33 | MMC_VDD_33_34)
+#define MMC_SPI_MIN_CLOCK		400000	/* 400KHz to meet MMC spec */
+#define MMC_SPI_MAX_CLOCK		25000000 /* SD/MMC legacy speed */
 
 /* timeout value */
-#define CTOUT 8
-#define RTOUT 3000000 /* 1 sec */
-#define WTOUT 3000000 /* 1 sec */
+#define CMD_TIMEOUT			8
+#define READ_TIMEOUT			3000000 /* 1 sec */
+#define WRITE_TIMEOUT			3000000 /* 1 sec */
 
-static uint mmc_spi_sendcmd(struct mmc *mmc, ushort cmdidx, u32 cmdarg)
+struct mmc_spi_priv {
+	struct spi_slave *spi;
+	struct mmc_config cfg;
+	struct mmc mmc;
+};
+
+static int mmc_spi_sendcmd(struct udevice *dev,
+			   ushort cmdidx, u32 cmdarg, u32 resp_type,
+			   u8 *resp, u32 resp_size,
+			   bool resp_match, u8 resp_match_value)
 {
-	struct spi_slave *spi = mmc->priv;
-	u8 cmdo[7];
-	u8 r1;
-	int i;
+	int i, rpos = 0, ret = 0;
+	u8 cmdo[7], r;
+
+	debug("%s: cmd%d cmdarg=0x%x resp_type=0x%x "
+	      "resp_size=%d resp_match=%d resp_match_value=0x%x\n",
+	      __func__, cmdidx, cmdarg, resp_type,
+	      resp_size, resp_match, resp_match_value);
+
 	cmdo[0] = 0xff;
 	cmdo[1] = MMC_SPI_CMD(cmdidx);
 	cmdo[2] = cmdarg >> 24;
@@ -63,37 +84,79 @@  static uint mmc_spi_sendcmd(struct mmc *mmc, ushort cmdidx, u32 cmdarg)
 	cmdo[4] = cmdarg >> 8;
 	cmdo[5] = cmdarg;
 	cmdo[6] = (crc7(0, &cmdo[1], 5) << 1) | 0x01;
-	spi_xfer(spi, sizeof(cmdo) * 8, cmdo, NULL, 0);
-	for (i = 0; i < CTOUT; i++) {
-		spi_xfer(spi, 1 * 8, NULL, &r1, 0);
-		if (i && (r1 & 0x80) == 0) /* r1 response */
-			break;
+	ret = dm_spi_xfer(dev, sizeof(cmdo) * 8, cmdo, NULL, 0);
+	if (ret)
+		return ret;
+
+	ret = dm_spi_xfer(dev, 1 * 8, NULL, &r, 0);
+	if (ret)
+		return ret;
+
+	if (!resp || !resp_size)
+		return 0;
+
+	debug("%s: cmd%d", __func__, cmdidx);
+
+	if (resp_match) {
+		r = ~resp_match_value;
+		i = CMD_TIMEOUT;
+		while (i--) {
+			ret = dm_spi_xfer(dev, 1 * 8, NULL, &r, 0);
+			if (ret)
+				return ret;
+			debug(" resp%d=0x%x", rpos, r);
+			rpos++;
+			if (r == resp_match_value)
+				break;
+		}
+		if (!i && (r != resp_match_value))
+			return -ETIMEDOUT;
+	}
+
+	for (i = 0; i < resp_size; i++) {
+		if (i == 0 && resp_match) {
+			resp[i] = resp_match_value;
+			continue;
+		}
+		ret = dm_spi_xfer(dev, 1 * 8, NULL, &r, 0);
+		if (ret)
+			return ret;
+		debug(" resp%d=0x%x", rpos, r);
+		rpos++;
+		resp[i] = r;
 	}
-	debug("%s:cmd%d resp%d %x\n", __func__, cmdidx, i, r1);
-	return r1;
+
+	debug("\n");
+
+	return 0;
 }
 
-static uint mmc_spi_readdata(struct mmc *mmc, void *xbuf,
-				u32 bcnt, u32 bsize)
+static int mmc_spi_readdata(struct udevice *dev,
+			    void *xbuf, u32 bcnt, u32 bsize)
 {
-	struct spi_slave *spi = mmc->priv;
-	u8 *buf = xbuf;
-	u8 r1;
 	u16 crc;
-	int i;
+	u8 *buf = xbuf, r1;
+	int i, ret = 0;
+
 	while (bcnt--) {
-		for (i = 0; i < RTOUT; i++) {
-			spi_xfer(spi, 1 * 8, NULL, &r1, 0);
-			if (r1 != 0xff) /* data token */
+		for (i = 0; i < READ_TIMEOUT; i++) {
+			ret = dm_spi_xfer(dev, 1 * 8, NULL, &r1, 0);
+			if (ret)
+				return ret;
+			if (r1 == SPI_TOKEN_SINGLE)
 				break;
 		}
-		debug("%s:tok%d %x\n", __func__, i, r1);
+		debug("%s: data tok%d 0x%x\n", __func__, i, r1);
 		if (r1 == SPI_TOKEN_SINGLE) {
-			spi_xfer(spi, bsize * 8, NULL, buf, 0);
-			spi_xfer(spi, 2 * 8, NULL, &crc, 0);
+			ret = dm_spi_xfer(dev, bsize * 8, NULL, buf, 0);
+			if (ret)
+				return ret;
+			ret = dm_spi_xfer(dev, 2 * 8, NULL, &crc, 0);
+			if (ret)
+				return ret;
 #ifdef CONFIG_MMC_SPI_CRC_ON
-			if (be_to_cpu16(crc16_ccitt(0, buf, bsize)) != crc) {
-				debug("%s: CRC error\n", mmc->cfg->name);
+			if (be16_to_cpu(crc16_ccitt(0, buf, bsize)) != crc) {
+				debug("%s: data crc error\n", __func__);
 				r1 = R1_SPI_COM_CRC;
 				break;
 			}
@@ -105,48 +168,56 @@  static uint mmc_spi_readdata(struct mmc *mmc, void *xbuf,
 		}
 		buf += bsize;
 	}
-	return r1;
+
+	if (r1 & R1_SPI_COM_CRC)
+		ret = -ECOMM;
+	else if (r1) /* other errors */
+		ret = -ETIMEDOUT;
+
+	return ret;
 }
 
-static uint mmc_spi_writedata(struct mmc *mmc, const void *xbuf,
-			      u32 bcnt, u32 bsize, int multi)
+static int mmc_spi_writedata(struct udevice *dev, const void *xbuf,
+			     u32 bcnt, u32 bsize, int multi)
 {
-	struct spi_slave *spi = mmc->priv;
 	const u8 *buf = xbuf;
-	u8 r1;
+	u8 r1, tok[2];
 	u16 crc;
-	u8 tok[2];
-	int i;
+	int i, ret = 0;
+
 	tok[0] = 0xff;
 	tok[1] = multi ? SPI_TOKEN_MULTI_WRITE : SPI_TOKEN_SINGLE;
+
 	while (bcnt--) {
 #ifdef CONFIG_MMC_SPI_CRC_ON
 		crc = cpu_to_be16(crc16_ccitt(0, (u8 *)buf, bsize));
 #endif
-		spi_xfer(spi, 2 * 8, tok, NULL, 0);
-		spi_xfer(spi, bsize * 8, buf, NULL, 0);
-		spi_xfer(spi, 2 * 8, &crc, NULL, 0);
-		for (i = 0; i < CTOUT; i++) {
-			spi_xfer(spi, 1 * 8, NULL, &r1, 0);
+		dm_spi_xfer(dev, 2 * 8, tok, NULL, 0);
+		dm_spi_xfer(dev, bsize * 8, buf, NULL, 0);
+		dm_spi_xfer(dev, 2 * 8, &crc, NULL, 0);
+		for (i = 0; i < CMD_TIMEOUT; i++) {
+			dm_spi_xfer(dev, 1 * 8, NULL, &r1, 0);
 			if ((r1 & 0x10) == 0) /* response token */
 				break;
 		}
-		debug("%s:tok%d %x\n", __func__, i, r1);
+		debug("%s: data tok%d 0x%x\n", __func__, i, r1);
 		if (SPI_MMC_RESPONSE_CODE(r1) == SPI_RESPONSE_ACCEPTED) {
-			for (i = 0; i < WTOUT; i++) { /* wait busy */
-				spi_xfer(spi, 1 * 8, NULL, &r1, 0);
+			debug("%s: data accepted\n", __func__);
+			for (i = 0; i < WRITE_TIMEOUT; i++) { /* wait busy */
+				dm_spi_xfer(dev, 1 * 8, NULL, &r1, 0);
 				if (i && r1 == 0xff) {
 					r1 = 0;
 					break;
 				}
 			}
-			if (i == WTOUT) {
-				debug("%s:wtout %x\n", __func__, r1);
+			if (i == WRITE_TIMEOUT) {
+				debug("%s: data write timeout 0x%x\n",
+				      __func__, r1);
 				r1 = R1_SPI_ERROR;
 				break;
 			}
 		} else {
-			debug("%s: err %x\n", __func__, r1);
+			debug("%s: data error 0x%x\n", __func__, r1);
 			r1 = R1_SPI_COM_CRC;
 			break;
 		}
@@ -154,140 +225,204 @@  static uint mmc_spi_writedata(struct mmc *mmc, const void *xbuf,
 	}
 	if (multi && bcnt == -1) { /* stop multi write */
 		tok[1] = SPI_TOKEN_STOP_TRAN;
-		spi_xfer(spi, 2 * 8, tok, NULL, 0);
-		for (i = 0; i < WTOUT; i++) { /* wait busy */
-			spi_xfer(spi, 1 * 8, NULL, &r1, 0);
+		dm_spi_xfer(dev, 2 * 8, tok, NULL, 0);
+		for (i = 0; i < WRITE_TIMEOUT; i++) { /* wait busy */
+			dm_spi_xfer(dev, 1 * 8, NULL, &r1, 0);
 			if (i && r1 == 0xff) {
 				r1 = 0;
 				break;
 			}
 		}
-		if (i == WTOUT) {
-			debug("%s:wstop %x\n", __func__, r1);
+		if (i == WRITE_TIMEOUT) {
+			debug("%s: data write timeout 0x%x\n", __func__, r1);
 			r1 = R1_SPI_ERROR;
 		}
 	}
-	return r1;
-}
 
-static int mmc_spi_request(struct mmc *mmc, struct mmc_cmd *cmd,
-		struct mmc_data *data)
-{
-	struct spi_slave *spi = mmc->priv;
-	u8 r1;
-	int i;
-	int ret = 0;
-	debug("%s:cmd%d %x %x\n", __func__,
-	      cmd->cmdidx, cmd->resp_type, cmd->cmdarg);
-	spi_claim_bus(spi);
-	spi_cs_activate(spi);
-	r1 = mmc_spi_sendcmd(mmc, cmd->cmdidx, cmd->cmdarg);
-	if (r1 == 0xff) { /* no response */
-		ret = -ENOMEDIUM;
-		goto done;
-	} else if (r1 & R1_SPI_COM_CRC) {
+	if (r1 & R1_SPI_COM_CRC)
 		ret = -ECOMM;
-		goto done;
-	} else if (r1 & ~R1_SPI_IDLE) { /* other errors */
+	else if (r1) /* other errors */
 		ret = -ETIMEDOUT;
+
+	return ret;
+}
+
+static int dm_mmc_spi_set_ios(struct udevice *dev)
+{
+	return 0;
+}
+
+static int dm_mmc_spi_request(struct udevice *dev, struct mmc_cmd *cmd,
+			      struct mmc_data *data)
+{
+	int i, multi, ret = 0;
+	u8 *resp = NULL;
+	u32 resp_size = 0;
+	bool resp_match = false;
+	u8 resp8 = 0, resp40[5] = { 0 }, resp_match_value = 0;
+
+	dm_spi_claim_bus(dev);
+
+	for (i = 0; i < 4; i++)
+		cmd->response[i] = 0;
+
+	switch (cmd->cmdidx) {
+	case SD_CMD_APP_SEND_OP_COND:
+	case MMC_CMD_SEND_OP_COND:
+		resp = &resp8;
+		resp_size = sizeof(resp8);
+		cmd->cmdarg = 0x40000000;
+		break;
+	case SD_CMD_SEND_IF_COND:
+		resp = (u8 *)&resp40[0];
+		resp_size = sizeof(resp40);
+		resp_match = true;
+		resp_match_value = R1_SPI_IDLE;
+		break;
+	case MMC_CMD_SPI_READ_OCR:
+		resp = (u8 *)&resp40[0];
+		resp_size = sizeof(resp40);
+		break;
+	case MMC_CMD_SEND_STATUS:
+	case MMC_CMD_SET_BLOCKLEN:
+	case MMC_CMD_SPI_CRC_ON_OFF:
+	case MMC_CMD_STOP_TRANSMISSION:
+		resp = &resp8;
+		resp_size = sizeof(resp8);
+		resp_match = true;
+		resp_match_value = 0x0;
+		break;
+	case MMC_CMD_SEND_CSD:
+	case MMC_CMD_SEND_CID:
+	case MMC_CMD_READ_SINGLE_BLOCK:
+	case MMC_CMD_READ_MULTIPLE_BLOCK:
+	case MMC_CMD_WRITE_SINGLE_BLOCK:
+	case MMC_CMD_WRITE_MULTIPLE_BLOCK:
+		break;
+	default:
+		resp = &resp8;
+		resp_size = sizeof(resp8);
+		resp_match = true;
+		resp_match_value = R1_SPI_IDLE;
+		break;
+	};
+
+	ret = mmc_spi_sendcmd(dev, cmd->cmdidx, cmd->cmdarg, cmd->resp_type,
+			      resp, resp_size, resp_match, resp_match_value);
+	if (ret)
 		goto done;
-	} else if (cmd->resp_type == MMC_RSP_R2) {
-		r1 = mmc_spi_readdata(mmc, cmd->response, 1, 16);
+
+	switch (cmd->cmdidx) {
+	case SD_CMD_APP_SEND_OP_COND:
+	case MMC_CMD_SEND_OP_COND:
+		cmd->response[0] = (resp8 & R1_SPI_IDLE) ? 0 : OCR_BUSY;
+		break;
+	case SD_CMD_SEND_IF_COND:
+	case MMC_CMD_SPI_READ_OCR:
+		cmd->response[0] = resp40[4];
+		cmd->response[0] |= (uint)resp40[3] << 8;
+		cmd->response[0] |= (uint)resp40[2] << 16;
+		cmd->response[0] |= (uint)resp40[1] << 24;
+		break;
+	case MMC_CMD_SEND_STATUS:
+		cmd->response[0] = (resp8 & 0xff) ?
+			MMC_STATUS_ERROR : MMC_STATUS_RDY_FOR_DATA;
+		break;
+	case MMC_CMD_SEND_CID:
+	case MMC_CMD_SEND_CSD:
+		ret = mmc_spi_readdata(dev, cmd->response, 1, 16);
+		if (ret)
+			return ret;
 		for (i = 0; i < 4; i++)
-			cmd->response[i] = be32_to_cpu(cmd->response[i]);
-		debug("r128 %x %x %x %x\n", cmd->response[0], cmd->response[1],
-		      cmd->response[2], cmd->response[3]);
-	} else if (!data) {
-		switch (cmd->cmdidx) {
-		case SD_CMD_APP_SEND_OP_COND:
-		case MMC_CMD_SEND_OP_COND:
-			cmd->response[0] = (r1 & R1_SPI_IDLE) ? 0 : OCR_BUSY;
-			break;
-		case SD_CMD_SEND_IF_COND:
-		case MMC_CMD_SPI_READ_OCR:
-			spi_xfer(spi, 4 * 8, NULL, cmd->response, 0);
-			cmd->response[0] = be32_to_cpu(cmd->response[0]);
-			debug("r32 %x\n", cmd->response[0]);
-			break;
-		case MMC_CMD_SEND_STATUS:
-			spi_xfer(spi, 1 * 8, NULL, cmd->response, 0);
-			cmd->response[0] = (cmd->response[0] & 0xff) ?
-				MMC_STATUS_ERROR : MMC_STATUS_RDY_FOR_DATA;
-			break;
-		}
-	} else {
-		debug("%s:data %x %x %x\n", __func__,
-		      data->flags, data->blocks, data->blocksize);
+			cmd->response[i] =
+				cpu_to_be32(cmd->response[i]);
+		break;
+	default:
+		cmd->response[0] = resp8;
+		break;
+	}
+
+	debug("%s: cmd%d resp0=0x%x resp1=0x%x resp2=0x%x resp3=0x%x\n",
+	      __func__, cmd->cmdidx, cmd->response[0], cmd->response[1],
+	      cmd->response[2], cmd->response[3]);
+
+	if (data) {
+		debug("%s: data flags=0x%x blocks=%d block_size=%d\n",
+		      __func__, data->flags, data->blocks, data->blocksize);
+		multi = (cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK);
 		if (data->flags == MMC_DATA_READ)
-			r1 = mmc_spi_readdata(mmc, data->dest,
-				data->blocks, data->blocksize);
+			ret = mmc_spi_readdata(dev, data->dest,
+					       data->blocks, data->blocksize);
 		else if  (data->flags == MMC_DATA_WRITE)
-			r1 = mmc_spi_writedata(mmc, data->src,
-				data->blocks, data->blocksize,
-				(cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK));
-		if (r1 & R1_SPI_COM_CRC)
-			ret = -ECOMM;
-		else if (r1) /* other errors */
-			ret = -ETIMEDOUT;
+			ret = mmc_spi_writedata(dev, data->src,
+						data->blocks, data->blocksize,
+						multi);
 	}
+
 done:
-	spi_cs_deactivate(spi);
-	spi_release_bus(spi);
+	dm_spi_release_bus(dev);
+
 	return ret;
 }
 
-static int mmc_spi_set_ios(struct mmc *mmc)
+static int mmc_spi_probe(struct udevice *dev)
 {
-	struct spi_slave *spi = mmc->priv;
+	struct mmc_spi_priv *priv = dev_get_priv(dev);
+	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
+	char *name;
+
+	priv->spi = dev_get_parent_priv(dev);
+	if (!priv->spi->max_hz)
+		priv->spi->max_hz = MMC_SPI_MAX_CLOCK;
+	priv->spi->speed = 0;
+	priv->spi->mode = SPI_MODE_0;
+	priv->spi->wordlen = 8;
+
+	name = malloc(strlen(dev->parent->name) + strlen(dev->name) + 4);
+	if (!name)
+		return -ENOMEM;
+	sprintf(name, "%s:%s", dev->parent->name, dev->name);
+
+	priv->cfg.name = name;
+	priv->cfg.host_caps = MMC_MODE_SPI;
+	priv->cfg.voltages = MMC_SPI_VOLTAGE;
+	priv->cfg.f_min = MMC_SPI_MIN_CLOCK;
+	priv->cfg.f_max = priv->spi->max_hz;
+	priv->cfg.part_type = PART_TYPE_DOS;
+	priv->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
+
+	priv->mmc.cfg = &priv->cfg;
+	priv->mmc.priv = priv;
+	priv->mmc.dev = dev;
+
+	upriv->mmc = &priv->mmc;
 
-	debug("%s: clock %u\n", __func__, mmc->clock);
-	if (mmc->clock)
-		spi_set_speed(spi, mmc->clock);
 	return 0;
 }
 
-static int mmc_spi_init_p(struct mmc *mmc)
+static int mmc_spi_bind(struct udevice *dev)
 {
-	struct spi_slave *spi = mmc->priv;
-	spi_set_speed(spi, MMC_SPI_MIN_CLOCK);
-	spi_claim_bus(spi);
-	/* cs deactivated for 100+ clock */
-	spi_xfer(spi, 18 * 8, NULL, NULL, 0);
-	spi_release_bus(spi);
-	return 0;
+	struct mmc_spi_priv *priv = dev_get_priv(dev);
+
+	return mmc_bind(dev, &priv->mmc, &priv->cfg);
 }
 
-static const struct mmc_ops mmc_spi_ops = {
-	.send_cmd	= mmc_spi_request,
-	.set_ios	= mmc_spi_set_ios,
-	.init		= mmc_spi_init_p,
+static const struct dm_mmc_ops mmc_spi_ops = {
+	.send_cmd	= dm_mmc_spi_request,
+	.set_ios	= dm_mmc_spi_set_ios,
 };
 
-static struct mmc_config mmc_spi_cfg = {
-	.name		= "MMC_SPI",
-	.ops		= &mmc_spi_ops,
-	.host_caps	= MMC_MODE_SPI,
-	.voltages	= MMC_SPI_VOLTAGE,
-	.f_min		= MMC_SPI_MIN_CLOCK,
-	.part_type	= PART_TYPE_DOS,
-	.b_max		= CONFIG_SYS_MMC_MAX_BLK_COUNT,
+static const struct udevice_id dm_mmc_spi_match[] = {
+	{ .compatible = "mmc-spi-slot" },
+	{ /* sentinel */ }
 };
 
-struct mmc *mmc_spi_init(uint bus, uint cs, uint speed, uint mode)
-{
-	struct mmc *mmc;
-	struct spi_slave *spi;
-
-	spi = spi_setup_slave(bus, cs, speed, mode);
-	if (spi == NULL)
-		return NULL;
-
-	mmc_spi_cfg.f_max = speed;
-
-	mmc = mmc_create(&mmc_spi_cfg, spi);
-	if (mmc == NULL) {
-		spi_free_slave(spi);
-		return NULL;
-	}
-	return mmc;
-}
+U_BOOT_DRIVER(mmc_spi) = {
+	.name = "mmc_spi",
+	.id = UCLASS_MMC,
+	.of_match = dm_mmc_spi_match,
+	.ops = &mmc_spi_ops,
+	.probe = mmc_spi_probe,
+	.bind = mmc_spi_bind,
+	.priv_auto_alloc_size = sizeof(struct mmc_spi_priv),
+};
diff --git a/scripts/config_whitelist.txt b/scripts/config_whitelist.txt
index 8651d569c5..0ce7016e84 100644
--- a/scripts/config_whitelist.txt
+++ b/scripts/config_whitelist.txt
@@ -1182,12 +1182,6 @@  CONFIG_MMCBOOTCOMMAND
 CONFIG_MMCROOT
 CONFIG_MMC_DEFAULT_DEV
 CONFIG_MMC_RPMB_TRACE
-CONFIG_MMC_SPI
-CONFIG_MMC_SPI_BUS
-CONFIG_MMC_SPI_CRC_ON
-CONFIG_MMC_SPI_CS
-CONFIG_MMC_SPI_MODE
-CONFIG_MMC_SPI_SPEED
 CONFIG_MMC_SUNXI_SLOT
 CONFIG_MMU
 CONFIG_MONITOR_IS_IN_RAM