diff options
Diffstat (limited to 'drivers/mmc/host/atmel-mci.c')
| -rw-r--r-- | drivers/mmc/host/atmel-mci.c | 1532 | 
1 files changed, 1101 insertions, 431 deletions
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 301351a5d83..bb585d94090 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -19,63 +19,96 @@  #include <linux/interrupt.h>  #include <linux/ioport.h>  #include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/of_gpio.h>  #include <linux/platform_device.h>  #include <linux/scatterlist.h>  #include <linux/seq_file.h>  #include <linux/slab.h>  #include <linux/stat.h> +#include <linux/types.h> +#include <linux/platform_data/atmel.h>  #include <linux/mmc/host.h> +#include <linux/mmc/sdio.h>  #include <mach/atmel-mci.h>  #include <linux/atmel-mci.h> +#include <linux/atmel_pdc.h> +#include <asm/cacheflush.h>  #include <asm/io.h>  #include <asm/unaligned.h> -#include <mach/cpu.h> -#include <mach/board.h> -  #include "atmel-mci-regs.h" -#define ATMCI_DATA_ERROR_FLAGS	(MCI_DCRCE | MCI_DTOE | MCI_OVRE | MCI_UNRE) +#define ATMCI_DATA_ERROR_FLAGS	(ATMCI_DCRCE | ATMCI_DTOE | ATMCI_OVRE | ATMCI_UNRE)  #define ATMCI_DMA_THRESHOLD	16  enum { -	EVENT_CMD_COMPLETE = 0, +	EVENT_CMD_RDY = 0,  	EVENT_XFER_COMPLETE, -	EVENT_DATA_COMPLETE, +	EVENT_NOTBUSY,  	EVENT_DATA_ERROR,  };  enum atmel_mci_state {  	STATE_IDLE = 0,  	STATE_SENDING_CMD, -	STATE_SENDING_DATA, -	STATE_DATA_BUSY, +	STATE_DATA_XFER, +	STATE_WAITING_NOTBUSY,  	STATE_SENDING_STOP, -	STATE_DATA_ERROR, +	STATE_END_REQUEST, +}; + +enum atmci_xfer_dir { +	XFER_RECEIVE = 0, +	XFER_TRANSMIT, +}; + +enum atmci_pdc_buf { +	PDC_FIRST_BUF = 0, +	PDC_SECOND_BUF, +}; + +struct atmel_mci_caps { +	bool    has_dma_conf_reg; +	bool    has_pdc; +	bool    has_cfg_reg; +	bool    has_cstor_reg; +	bool    has_highspeed; +	bool    has_rwproof; +	bool	has_odd_clk_div; +	bool	has_bad_data_ordering; +	bool	need_reset_after_xfer; +	bool	need_blksz_mul_4; +	bool	need_notbusy_for_read_ops;  };  struct atmel_mci_dma { -#ifdef CONFIG_MMC_ATMELMCI_DMA  	struct dma_chan			*chan;  	struct dma_async_tx_descriptor	*data_desc; -#endif  };  /**   * struct atmel_mci - MMC controller state shared between all slots   * @lock: Spinlock protecting the queue and associated data.   * @regs: Pointer to MMIO registers. - * @sg: Scatterlist entry currently being processed by PIO code, if any. + * @sg: Scatterlist entry currently being processed by PIO or PDC code.   * @pio_offset: Offset into the current scatterlist entry. + * @buffer: Buffer used if we don't have the r/w proof capability. We + *      don't have the time to switch pdc buffers so we have to use only + *      one buffer for the full transaction. + * @buf_size: size of the buffer. + * @phys_buf_addr: buffer address needed for pdc.   * @cur_slot: The slot which is currently using the controller.   * @mrq: The request currently being processed on @cur_slot,   *	or NULL if the controller is idle.   * @cmd: The command currently being sent to the card, or NULL.   * @data: The data currently being transferred, or NULL if no data   *	transfer is in progress. + * @data_size: just data->blocks * data->blksz.   * @dma: DMA client state.   * @data_chan: DMA channel being used for the current data transfer.   * @cmd_status: Snapshot of SR taken upon completion of the current @@ -94,6 +127,7 @@ struct atmel_mci_dma {   * @queue: List of slots waiting for access to the controller.   * @need_clock_update: Update the clock rate before the next request.   * @need_reset: Reset controller before next request. + * @timer: Timer to balance the data timeout error flag which cannot rise.   * @mode_reg: Value of the MR register.   * @cfg_reg: Value of the CFG register.   * @bus_hz: The rate of @mck in Hz. This forms the basis for MMC bus @@ -102,6 +136,13 @@ struct atmel_mci_dma {   * @mck: The peripheral bus clock hooked up to the MMC controller.   * @pdev: Platform device associated with the MMC controller.   * @slot: Slots sharing this MMC controller. + * @caps: MCI capabilities depending on MCI version. + * @prepare_data: function to setup MCI before data transfer which + * depends on MCI capabilities. + * @submit_data: function to start data transfer which depends on MCI + * capabilities. + * @stop_transfer: function to stop data transfer which depends on MCI + * capabilities.   *   * Locking   * ======= @@ -126,7 +167,7 @@ struct atmel_mci_dma {   * EVENT_DATA_COMPLETE is set in @pending_events, all data-related   * interrupts must be disabled and @data_status updated with a   * snapshot of SR. Similarly, before EVENT_CMD_COMPLETE is set, the - * CMDRDY interupt must be disabled and @cmd_status updated with a + * CMDRDY interrupt must be disabled and @cmd_status updated with a   * snapshot of SR, and before EVENT_XFER_COMPLETE can be set, the   * bytes_xfered field of @data must be written. This is ensured by   * using barriers. @@ -136,15 +177,21 @@ struct atmel_mci {  	void __iomem		*regs;  	struct scatterlist	*sg; +	unsigned int		sg_len;  	unsigned int		pio_offset; +	unsigned int		*buffer; +	unsigned int		buf_size; +	dma_addr_t		buf_phys_addr;  	struct atmel_mci_slot	*cur_slot;  	struct mmc_request	*mrq;  	struct mmc_command	*cmd;  	struct mmc_data		*data; +	unsigned int		data_size;  	struct atmel_mci_dma	dma;  	struct dma_chan		*data_chan; +	struct dma_slave_config	dma_conf;  	u32			cmd_status;  	u32			data_status; @@ -158,6 +205,7 @@ struct atmel_mci {  	bool			need_clock_update;  	bool			need_reset; +	struct timer_list	timer;  	u32			mode_reg;  	u32			cfg_reg;  	unsigned long		bus_hz; @@ -165,7 +213,13 @@ struct atmel_mci {  	struct clk		*mck;  	struct platform_device	*pdev; -	struct atmel_mci_slot	*slot[ATMEL_MCI_MAX_NR_SLOTS]; +	struct atmel_mci_slot	*slot[ATMCI_MAX_NR_SLOTS]; + +	struct atmel_mci_caps   caps; + +	u32 (*prepare_data)(struct atmel_mci *host, struct mmc_data *data); +	void (*submit_data)(struct atmel_mci *host, struct mmc_data *data); +	void (*stop_transfer)(struct atmel_mci *host);  };  /** @@ -218,31 +272,6 @@ struct atmel_mci_slot {  	set_bit(event, &host->pending_events)  /* - * Enable or disable features/registers based on - * whether the processor supports them - */ -static bool mci_has_rwproof(void) -{ -	if (cpu_is_at91sam9261() || cpu_is_at91rm9200()) -		return false; -	else -		return true; -} - -/* - * The new MCI2 module isn't 100% compatible with the old MCI module, - * and it has a few nice features which we want to use... - */ -static inline bool atmci_is_mci2(void) -{ -	if (cpu_is_at91sam9g45()) -		return true; - -	return false; -} - - -/*   * The debugfs stuff below is mostly optimized away when   * CONFIG_DEBUG_FS is not set.   */ @@ -349,8 +378,10 @@ static int atmci_regs_show(struct seq_file *s, void *v)  {  	struct atmel_mci	*host = s->private;  	u32			*buf; +	int			ret = 0; + -	buf = kmalloc(MCI_REGS_SIZE, GFP_KERNEL); +	buf = kmalloc(ATMCI_REGS_SIZE, GFP_KERNEL);  	if (!buf)  		return -ENOMEM; @@ -359,54 +390,68 @@ static int atmci_regs_show(struct seq_file *s, void *v)  	 * not disabling interrupts, so IMR and SR may not be  	 * consistent.  	 */ +	ret = clk_prepare_enable(host->mck); +	if (ret) +		goto out; +  	spin_lock_bh(&host->lock); -	clk_enable(host->mck); -	memcpy_fromio(buf, host->regs, MCI_REGS_SIZE); -	clk_disable(host->mck); +	memcpy_fromio(buf, host->regs, ATMCI_REGS_SIZE);  	spin_unlock_bh(&host->lock); -	seq_printf(s, "MR:\t0x%08x%s%s CLKDIV=%u\n", -			buf[MCI_MR / 4], -			buf[MCI_MR / 4] & MCI_MR_RDPROOF ? " RDPROOF" : "", -			buf[MCI_MR / 4] & MCI_MR_WRPROOF ? " WRPROOF" : "", -			buf[MCI_MR / 4] & 0xff); -	seq_printf(s, "DTOR:\t0x%08x\n", buf[MCI_DTOR / 4]); -	seq_printf(s, "SDCR:\t0x%08x\n", buf[MCI_SDCR / 4]); -	seq_printf(s, "ARGR:\t0x%08x\n", buf[MCI_ARGR / 4]); +	clk_disable_unprepare(host->mck); + +	seq_printf(s, "MR:\t0x%08x%s%s ", +			buf[ATMCI_MR / 4], +			buf[ATMCI_MR / 4] & ATMCI_MR_RDPROOF ? " RDPROOF" : "", +			buf[ATMCI_MR / 4] & ATMCI_MR_WRPROOF ? " WRPROOF" : ""); +	if (host->caps.has_odd_clk_div) +		seq_printf(s, "{CLKDIV,CLKODD}=%u\n", +				((buf[ATMCI_MR / 4] & 0xff) << 1) +				| ((buf[ATMCI_MR / 4] >> 16) & 1)); +	else +		seq_printf(s, "CLKDIV=%u\n", +				(buf[ATMCI_MR / 4] & 0xff)); +	seq_printf(s, "DTOR:\t0x%08x\n", buf[ATMCI_DTOR / 4]); +	seq_printf(s, "SDCR:\t0x%08x\n", buf[ATMCI_SDCR / 4]); +	seq_printf(s, "ARGR:\t0x%08x\n", buf[ATMCI_ARGR / 4]);  	seq_printf(s, "BLKR:\t0x%08x BCNT=%u BLKLEN=%u\n", -			buf[MCI_BLKR / 4], -			buf[MCI_BLKR / 4] & 0xffff, -			(buf[MCI_BLKR / 4] >> 16) & 0xffff); -	if (atmci_is_mci2()) -		seq_printf(s, "CSTOR:\t0x%08x\n", buf[MCI_CSTOR / 4]); +			buf[ATMCI_BLKR / 4], +			buf[ATMCI_BLKR / 4] & 0xffff, +			(buf[ATMCI_BLKR / 4] >> 16) & 0xffff); +	if (host->caps.has_cstor_reg) +		seq_printf(s, "CSTOR:\t0x%08x\n", buf[ATMCI_CSTOR / 4]);  	/* Don't read RSPR and RDR; it will consume the data there */ -	atmci_show_status_reg(s, "SR", buf[MCI_SR / 4]); -	atmci_show_status_reg(s, "IMR", buf[MCI_IMR / 4]); +	atmci_show_status_reg(s, "SR", buf[ATMCI_SR / 4]); +	atmci_show_status_reg(s, "IMR", buf[ATMCI_IMR / 4]); -	if (atmci_is_mci2()) { +	if (host->caps.has_dma_conf_reg) {  		u32 val; -		val = buf[MCI_DMA / 4]; +		val = buf[ATMCI_DMA / 4];  		seq_printf(s, "DMA:\t0x%08x OFFSET=%u CHKSIZE=%u%s\n",  				val, val & 3,  				((val >> 4) & 3) ?  					1 << (((val >> 4) & 3) + 1) : 1, -				val & MCI_DMAEN ? " DMAEN" : ""); +				val & ATMCI_DMAEN ? " DMAEN" : ""); +	} +	if (host->caps.has_cfg_reg) { +		u32 val; -		val = buf[MCI_CFG / 4]; +		val = buf[ATMCI_CFG / 4];  		seq_printf(s, "CFG:\t0x%08x%s%s%s%s\n",  				val, -				val & MCI_CFG_FIFOMODE_1DATA ? " FIFOMODE_ONE_DATA" : "", -				val & MCI_CFG_FERRCTRL_COR ? " FERRCTRL_CLEAR_ON_READ" : "", -				val & MCI_CFG_HSMODE ? " HSMODE" : "", -				val & MCI_CFG_LSYNC ? " LSYNC" : ""); +				val & ATMCI_CFG_FIFOMODE_1DATA ? " FIFOMODE_ONE_DATA" : "", +				val & ATMCI_CFG_FERRCTRL_COR ? " FERRCTRL_CLEAR_ON_READ" : "", +				val & ATMCI_CFG_HSMODE ? " HSMODE" : "", +				val & ATMCI_CFG_LSYNC ? " LSYNC" : "");  	} +out:  	kfree(buf); -	return 0; +	return ret;  }  static int atmci_regs_open(struct inode *inode, struct file *file) @@ -464,10 +509,114 @@ err:  	dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n");  } -static inline unsigned int ns_to_clocks(struct atmel_mci *host, +#if defined(CONFIG_OF) +static const struct of_device_id atmci_dt_ids[] = { +	{ .compatible = "atmel,hsmci" }, +	{ /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, atmci_dt_ids); + +static struct mci_platform_data* +atmci_of_init(struct platform_device *pdev) +{ +	struct device_node *np = pdev->dev.of_node; +	struct device_node *cnp; +	struct mci_platform_data *pdata; +	u32 slot_id; + +	if (!np) { +		dev_err(&pdev->dev, "device node not found\n"); +		return ERR_PTR(-EINVAL); +	} + +	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); +	if (!pdata) { +		dev_err(&pdev->dev, "could not allocate memory for pdata\n"); +		return ERR_PTR(-ENOMEM); +	} + +	for_each_child_of_node(np, cnp) { +		if (of_property_read_u32(cnp, "reg", &slot_id)) { +			dev_warn(&pdev->dev, "reg property is missing for %s\n", +				 cnp->full_name); +			continue; +		} + +		if (slot_id >= ATMCI_MAX_NR_SLOTS) { +			dev_warn(&pdev->dev, "can't have more than %d slots\n", +			         ATMCI_MAX_NR_SLOTS); +			break; +		} + +		if (of_property_read_u32(cnp, "bus-width", +		                         &pdata->slot[slot_id].bus_width)) +			pdata->slot[slot_id].bus_width = 1; + +		pdata->slot[slot_id].detect_pin = +			of_get_named_gpio(cnp, "cd-gpios", 0); + +		pdata->slot[slot_id].detect_is_active_high = +			of_property_read_bool(cnp, "cd-inverted"); + +		pdata->slot[slot_id].wp_pin = +			of_get_named_gpio(cnp, "wp-gpios", 0); +	} + +	return pdata; +} +#else /* CONFIG_OF */ +static inline struct mci_platform_data* +atmci_of_init(struct platform_device *dev) +{ +	return ERR_PTR(-EINVAL); +} +#endif + +static inline unsigned int atmci_get_version(struct atmel_mci *host) +{ +	return atmci_readl(host, ATMCI_VERSION) & 0x00000fff; +} + +static void atmci_timeout_timer(unsigned long data) +{ +	struct atmel_mci *host; + +	host = (struct atmel_mci *)data; + +	dev_dbg(&host->pdev->dev, "software timeout\n"); + +	if (host->mrq->cmd->data) { +		host->mrq->cmd->data->error = -ETIMEDOUT; +		host->data = NULL; +		/* +		 * With some SDIO modules, sometimes DMA transfer hangs. If +		 * stop_transfer() is not called then the DMA request is not +		 * removed, following ones are queued and never computed. +		 */ +		if (host->state == STATE_DATA_XFER) +			host->stop_transfer(host); +	} else { +		host->mrq->cmd->error = -ETIMEDOUT; +		host->cmd = NULL; +	} +	host->need_reset = 1; +	host->state = STATE_END_REQUEST; +	smp_wmb(); +	tasklet_schedule(&host->tasklet); +} + +static inline unsigned int atmci_ns_to_clocks(struct atmel_mci *host,  					unsigned int ns)  { -	return (ns * (host->bus_hz / 1000000) + 999) / 1000; +	/* +	 * It is easier here to use us instead of ns for the timeout, +	 * it prevents from overflows during calculation. +	 */ +	unsigned int us = DIV_ROUND_UP(ns, 1000); + +	/* Maximum clock frequency is host->bus_hz/2 */ +	return us * (DIV_ROUND_UP(host->bus_hz, 2000000));  }  static void atmci_set_timeout(struct atmel_mci *host, @@ -480,7 +629,8 @@ static void atmci_set_timeout(struct atmel_mci *host,  	unsigned	dtocyc;  	unsigned	dtomul; -	timeout = ns_to_clocks(host, data->timeout_ns) + data->timeout_clks; +	timeout = atmci_ns_to_clocks(host, data->timeout_ns) +		+ data->timeout_clks;  	for (dtomul = 0; dtomul < 8; dtomul++) {  		unsigned shift = dtomul_to_shift[dtomul]; @@ -496,7 +646,7 @@ static void atmci_set_timeout(struct atmel_mci *host,  	dev_vdbg(&slot->mmc->class_dev, "setting timeout to %u cycles\n",  			dtocyc << dtomul_to_shift[dtomul]); -	mci_writel(host, DTOR, (MCI_DTOMUL(dtomul) | MCI_DTOCYC(dtocyc))); +	atmci_writel(host, ATMCI_DTOR, (ATMCI_DTOMUL(dtomul) | ATMCI_DTOCYC(dtocyc)));  }  /* @@ -510,13 +660,13 @@ static u32 atmci_prepare_command(struct mmc_host *mmc,  	cmd->error = -EINPROGRESS; -	cmdr = MCI_CMDR_CMDNB(cmd->opcode); +	cmdr = ATMCI_CMDR_CMDNB(cmd->opcode);  	if (cmd->flags & MMC_RSP_PRESENT) {  		if (cmd->flags & MMC_RSP_136) -			cmdr |= MCI_CMDR_RSPTYP_136BIT; +			cmdr |= ATMCI_CMDR_RSPTYP_136BIT;  		else -			cmdr |= MCI_CMDR_RSPTYP_48BIT; +			cmdr |= ATMCI_CMDR_RSPTYP_48BIT;  	}  	/* @@ -524,29 +674,34 @@ static u32 atmci_prepare_command(struct mmc_host *mmc,  	 * it's too difficult to determine whether this is an ACMD or  	 * not. Better make it 64.  	 */ -	cmdr |= MCI_CMDR_MAXLAT_64CYC; +	cmdr |= ATMCI_CMDR_MAXLAT_64CYC;  	if (mmc->ios.bus_mode == MMC_BUSMODE_OPENDRAIN) -		cmdr |= MCI_CMDR_OPDCMD; +		cmdr |= ATMCI_CMDR_OPDCMD;  	data = cmd->data;  	if (data) { -		cmdr |= MCI_CMDR_START_XFER; -		if (data->flags & MMC_DATA_STREAM) -			cmdr |= MCI_CMDR_STREAM; -		else if (data->blocks > 1) -			cmdr |= MCI_CMDR_MULTI_BLOCK; -		else -			cmdr |= MCI_CMDR_BLOCK; +		cmdr |= ATMCI_CMDR_START_XFER; + +		if (cmd->opcode == SD_IO_RW_EXTENDED) { +			cmdr |= ATMCI_CMDR_SDIO_BLOCK; +		} else { +			if (data->flags & MMC_DATA_STREAM) +				cmdr |= ATMCI_CMDR_STREAM; +			else if (data->blocks > 1) +				cmdr |= ATMCI_CMDR_MULTI_BLOCK; +			else +				cmdr |= ATMCI_CMDR_BLOCK; +		}  		if (data->flags & MMC_DATA_READ) -			cmdr |= MCI_CMDR_TRDIR_READ; +			cmdr |= ATMCI_CMDR_TRDIR_READ;  	}  	return cmdr;  } -static void atmci_start_command(struct atmel_mci *host, +static void atmci_send_command(struct atmel_mci *host,  		struct mmc_command *cmd, u32 cmd_flags)  {  	WARN_ON(host->cmd); @@ -556,42 +711,135 @@ static void atmci_start_command(struct atmel_mci *host,  			"start command: ARGR=0x%08x CMDR=0x%08x\n",  			cmd->arg, cmd_flags); -	mci_writel(host, ARGR, cmd->arg); -	mci_writel(host, CMDR, cmd_flags); +	atmci_writel(host, ATMCI_ARGR, cmd->arg); +	atmci_writel(host, ATMCI_CMDR, cmd_flags);  } -static void send_stop_cmd(struct atmel_mci *host, struct mmc_data *data) +static void atmci_send_stop_cmd(struct atmel_mci *host, struct mmc_data *data)  { -	atmci_start_command(host, data->stop, host->stop_cmdr); -	mci_writel(host, IER, MCI_CMDRDY); +	dev_dbg(&host->pdev->dev, "send stop command\n"); +	atmci_send_command(host, data->stop, host->stop_cmdr); +	atmci_writel(host, ATMCI_IER, ATMCI_CMDRDY);  } -#ifdef CONFIG_MMC_ATMELMCI_DMA -static void atmci_dma_cleanup(struct atmel_mci *host) +/* + * Configure given PDC buffer taking care of alignement issues. + * Update host->data_size and host->sg. + */ +static void atmci_pdc_set_single_buf(struct atmel_mci *host, +	enum atmci_xfer_dir dir, enum atmci_pdc_buf buf_nb)  { -	struct mmc_data			*data = host->data; +	u32 pointer_reg, counter_reg; +	unsigned int buf_size; -	if (data) -		dma_unmap_sg(&host->pdev->dev, data->sg, data->sg_len, -			     ((data->flags & MMC_DATA_WRITE) -			      ? DMA_TO_DEVICE : DMA_FROM_DEVICE)); +	if (dir == XFER_RECEIVE) { +		pointer_reg = ATMEL_PDC_RPR; +		counter_reg = ATMEL_PDC_RCR; +	} else { +		pointer_reg = ATMEL_PDC_TPR; +		counter_reg = ATMEL_PDC_TCR; +	} + +	if (buf_nb == PDC_SECOND_BUF) { +		pointer_reg += ATMEL_PDC_SCND_BUF_OFF; +		counter_reg += ATMEL_PDC_SCND_BUF_OFF; +	} + +	if (!host->caps.has_rwproof) { +		buf_size = host->buf_size; +		atmci_writel(host, pointer_reg, host->buf_phys_addr); +	} else { +		buf_size = sg_dma_len(host->sg); +		atmci_writel(host, pointer_reg, sg_dma_address(host->sg)); +	} + +	if (host->data_size <= buf_size) { +		if (host->data_size & 0x3) { +			/* If size is different from modulo 4, transfer bytes */ +			atmci_writel(host, counter_reg, host->data_size); +			atmci_writel(host, ATMCI_MR, host->mode_reg | ATMCI_MR_PDCFBYTE); +		} else { +			/* Else transfer 32-bits words */ +			atmci_writel(host, counter_reg, host->data_size / 4); +		} +		host->data_size = 0; +	} else { +		/* We assume the size of a page is 32-bits aligned */ +		atmci_writel(host, counter_reg, sg_dma_len(host->sg) / 4); +		host->data_size -= sg_dma_len(host->sg); +		if (host->data_size) +			host->sg = sg_next(host->sg); +	}  } -static void atmci_stop_dma(struct atmel_mci *host) +/* + * Configure PDC buffer according to the data size ie configuring one or two + * buffers. Don't use this function if you want to configure only the second + * buffer. In this case, use atmci_pdc_set_single_buf. + */ +static void atmci_pdc_set_both_buf(struct atmel_mci *host, int dir)  { -	struct dma_chan *chan = host->data_chan; +	atmci_pdc_set_single_buf(host, dir, PDC_FIRST_BUF); +	if (host->data_size) +		atmci_pdc_set_single_buf(host, dir, PDC_SECOND_BUF); +} -	if (chan) { -	  chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); -		atmci_dma_cleanup(host); -	} else { -		/* Data transfer was stopped by the interrupt handler */ -		atmci_set_pending(host, EVENT_XFER_COMPLETE); -		mci_writel(host, IER, MCI_NOTBUSY); +/* + * Unmap sg lists, called when transfer is finished. + */ +static void atmci_pdc_cleanup(struct atmel_mci *host) +{ +	struct mmc_data         *data = host->data; + +	if (data) +		dma_unmap_sg(&host->pdev->dev, +				data->sg, data->sg_len, +				((data->flags & MMC_DATA_WRITE) +				 ? DMA_TO_DEVICE : DMA_FROM_DEVICE)); +} + +/* + * Disable PDC transfers. Update pending flags to EVENT_XFER_COMPLETE after + * having received ATMCI_TXBUFE or ATMCI_RXBUFF interrupt. Enable ATMCI_NOTBUSY + * interrupt needed for both transfer directions. + */ +static void atmci_pdc_complete(struct atmel_mci *host) +{ +	int transfer_size = host->data->blocks * host->data->blksz; +	int i; + +	atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); + +	if ((!host->caps.has_rwproof) +	    && (host->data->flags & MMC_DATA_READ)) { +		if (host->caps.has_bad_data_ordering) +			for (i = 0; i < transfer_size; i++) +				host->buffer[i] = swab32(host->buffer[i]); +		sg_copy_from_buffer(host->data->sg, host->data->sg_len, +		                    host->buffer, transfer_size);  	} + +	atmci_pdc_cleanup(host); + +	dev_dbg(&host->pdev->dev, "(%s) set pending xfer complete\n", __func__); +	atmci_set_pending(host, EVENT_XFER_COMPLETE); +	tasklet_schedule(&host->tasklet); +} + +static void atmci_dma_cleanup(struct atmel_mci *host) +{ +	struct mmc_data                 *data = host->data; + +	if (data) +		dma_unmap_sg(host->dma.chan->device->dev, +				data->sg, data->sg_len, +				((data->flags & MMC_DATA_WRITE) +				 ? DMA_TO_DEVICE : DMA_FROM_DEVICE));  } -/* This function is called by the DMA driver from tasklet context. */ +/* + * This function is called by the DMA driver from tasklet context. + */  static void atmci_dma_complete(void *arg)  {  	struct atmel_mci	*host = arg; @@ -599,9 +847,9 @@ static void atmci_dma_complete(void *arg)  	dev_vdbg(&host->pdev->dev, "DMA complete\n"); -	if (atmci_is_mci2()) +	if (host->caps.has_dma_conf_reg)  		/* Disable DMA hardware handshaking on MCI */ -		mci_writel(host, DMA, mci_readl(host, DMA) & ~MCI_DMAEN); +		atmci_writel(host, ATMCI_DMA, atmci_readl(host, ATMCI_DMA) & ~ATMCI_DMAEN);  	atmci_dma_cleanup(host); @@ -610,6 +858,8 @@ static void atmci_dma_complete(void *arg)  	 * to send the stop command or waiting for NBUSY in this case.  	 */  	if (data) { +		dev_dbg(&host->pdev->dev, +		        "(%s) set pending xfer complete\n", __func__);  		atmci_set_pending(host, EVENT_XFER_COMPLETE);  		tasklet_schedule(&host->tasklet); @@ -633,11 +883,105 @@ static void atmci_dma_complete(void *arg)  		 * completion callback" rule of the dma engine  		 * framework.  		 */ -		mci_writel(host, IER, MCI_NOTBUSY); +		atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); +	} +} + +/* + * Returns a mask of interrupt flags to be enabled after the whole + * request has been prepared. + */ +static u32 atmci_prepare_data(struct atmel_mci *host, struct mmc_data *data) +{ +	u32 iflags; + +	data->error = -EINPROGRESS; + +	host->sg = data->sg; +	host->sg_len = data->sg_len; +	host->data = data; +	host->data_chan = NULL; + +	iflags = ATMCI_DATA_ERROR_FLAGS; + +	/* +	 * Errata: MMC data write operation with less than 12 +	 * bytes is impossible. +	 * +	 * Errata: MCI Transmit Data Register (TDR) FIFO +	 * corruption when length is not multiple of 4. +	 */ +	if (data->blocks * data->blksz < 12 +			|| (data->blocks * data->blksz) & 3) +		host->need_reset = true; + +	host->pio_offset = 0; +	if (data->flags & MMC_DATA_READ) +		iflags |= ATMCI_RXRDY; +	else +		iflags |= ATMCI_TXRDY; + +	return iflags; +} + +/* + * Set interrupt flags and set block length into the MCI mode register even + * if this value is also accessible in the MCI block register. It seems to be + * necessary before the High Speed MCI version. It also map sg and configure + * PDC registers. + */ +static u32 +atmci_prepare_data_pdc(struct atmel_mci *host, struct mmc_data *data) +{ +	u32 iflags, tmp; +	unsigned int sg_len; +	enum dma_data_direction dir; +	int i; + +	data->error = -EINPROGRESS; + +	host->data = data; +	host->sg = data->sg; +	iflags = ATMCI_DATA_ERROR_FLAGS; + +	/* Enable pdc mode */ +	atmci_writel(host, ATMCI_MR, host->mode_reg | ATMCI_MR_PDCMODE); + +	if (data->flags & MMC_DATA_READ) { +		dir = DMA_FROM_DEVICE; +		iflags |= ATMCI_ENDRX | ATMCI_RXBUFF; +	} else { +		dir = DMA_TO_DEVICE; +		iflags |= ATMCI_ENDTX | ATMCI_TXBUFE | ATMCI_BLKE; +	} + +	/* Set BLKLEN */ +	tmp = atmci_readl(host, ATMCI_MR); +	tmp &= 0x0000ffff; +	tmp |= ATMCI_BLKLEN(data->blksz); +	atmci_writel(host, ATMCI_MR, tmp); + +	/* Configure PDC */ +	host->data_size = data->blocks * data->blksz; +	sg_len = dma_map_sg(&host->pdev->dev, data->sg, data->sg_len, dir); + +	if ((!host->caps.has_rwproof) +	    && (host->data->flags & MMC_DATA_WRITE)) { +		sg_copy_to_buffer(host->data->sg, host->data->sg_len, +		                  host->buffer, host->data_size); +		if (host->caps.has_bad_data_ordering) +			for (i = 0; i < host->data_size; i++) +				host->buffer[i] = swab32(host->buffer[i]);  	} + +	if (host->data_size) +		atmci_pdc_set_both_buf(host, +			((dir == DMA_FROM_DEVICE) ? XFER_RECEIVE : XFER_TRANSMIT)); + +	return iflags;  } -static int +static u32  atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data)  {  	struct dma_chan			*chan; @@ -645,7 +989,18 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data)  	struct scatterlist		*sg;  	unsigned int			i;  	enum dma_data_direction		direction; +	enum dma_transfer_direction	slave_dirn;  	unsigned int			sglen; +	u32				maxburst; +	u32 iflags; + +	data->error = -EINPROGRESS; + +	WARN_ON(host->data); +	host->sg = NULL; +	host->data = data; + +	iflags = ATMCI_DATA_ERROR_FLAGS;  	/*  	 * We don't do DMA on "complex" transfers, i.e. with @@ -653,13 +1008,13 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data)  	 * with all the DMA setup overhead for short transfers.  	 */  	if (data->blocks * data->blksz < ATMCI_DMA_THRESHOLD) -		return -EINVAL; +		return atmci_prepare_data(host, data);  	if (data->blksz & 3) -		return -EINVAL; +		return atmci_prepare_data(host, data);  	for_each_sg(data->sg, sg, data->sg_len, i) {  		if (sg->offset & 3 || sg->length & 3) -			return -EINVAL; +			return atmci_prepare_data(host, data);  	}  	/* If we don't have a channel, we can't do DMA */ @@ -670,19 +1025,26 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data)  	if (!chan)  		return -ENODEV; -	if (atmci_is_mci2()) -		mci_writel(host, DMA, MCI_DMA_CHKSIZE(3) | MCI_DMAEN); - -	if (data->flags & MMC_DATA_READ) +	if (data->flags & MMC_DATA_READ) {  		direction = DMA_FROM_DEVICE; -	else +		host->dma_conf.direction = slave_dirn = DMA_DEV_TO_MEM; +		maxburst = atmci_convert_chksize(host->dma_conf.src_maxburst); +	} else {  		direction = DMA_TO_DEVICE; +		host->dma_conf.direction = slave_dirn = DMA_MEM_TO_DEV; +		maxburst = atmci_convert_chksize(host->dma_conf.dst_maxburst); +	} -	sglen = dma_map_sg(&host->pdev->dev, data->sg, data->sg_len, direction); -	if (sglen != data->sg_len) -		goto unmap_exit; -	desc = chan->device->device_prep_slave_sg(chan, -			data->sg, data->sg_len, direction, +	if (host->caps.has_dma_conf_reg) +		atmci_writel(host, ATMCI_DMA, ATMCI_DMA_CHKSIZE(maxburst) | +			ATMCI_DMAEN); + +	sglen = dma_map_sg(chan->device->dev, data->sg, +			data->sg_len, direction); + +	dmaengine_slave_config(chan, &host->dma_conf); +	desc = dmaengine_prep_slave_sg(chan, +			data->sg, sglen, slave_dirn,  			DMA_PREP_INTERRUPT | DMA_CTRL_ACK);  	if (!desc)  		goto unmap_exit; @@ -691,81 +1053,78 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data)  	desc->callback = atmci_dma_complete;  	desc->callback_param = host; -	return 0; +	return iflags;  unmap_exit: -	dma_unmap_sg(&host->pdev->dev, data->sg, sglen, direction); +	dma_unmap_sg(chan->device->dev, data->sg, data->sg_len, direction);  	return -ENOMEM;  } -static void atmci_submit_data(struct atmel_mci *host) +static void +atmci_submit_data(struct atmel_mci *host, struct mmc_data *data) +{ +	return; +} + +/* + * Start PDC according to transfer direction. + */ +static void +atmci_submit_data_pdc(struct atmel_mci *host, struct mmc_data *data) +{ +	if (data->flags & MMC_DATA_READ) +		atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN); +	else +		atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN); +} + +static void +atmci_submit_data_dma(struct atmel_mci *host, struct mmc_data *data)  {  	struct dma_chan			*chan = host->data_chan;  	struct dma_async_tx_descriptor	*desc = host->dma.data_desc;  	if (chan) { -		desc->tx_submit(desc); -		chan->device->device_issue_pending(chan); +		dmaengine_submit(desc); +		dma_async_issue_pending(chan);  	}  } -#else /* CONFIG_MMC_ATMELMCI_DMA */ - -static int atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data) -{ -	return -ENOSYS; -} - -static void atmci_submit_data(struct atmel_mci *host) {} - -static void atmci_stop_dma(struct atmel_mci *host) +static void atmci_stop_transfer(struct atmel_mci *host)  { -	/* Data transfer was stopped by the interrupt handler */ +	dev_dbg(&host->pdev->dev, +	        "(%s) set pending xfer complete\n", __func__);  	atmci_set_pending(host, EVENT_XFER_COMPLETE); -	mci_writel(host, IER, MCI_NOTBUSY); +	atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);  } -#endif /* CONFIG_MMC_ATMELMCI_DMA */ -  /* - * Returns a mask of interrupt flags to be enabled after the whole - * request has been prepared. + * Stop data transfer because error(s) occurred.   */ -static u32 atmci_prepare_data(struct atmel_mci *host, struct mmc_data *data) +static void atmci_stop_transfer_pdc(struct atmel_mci *host)  { -	u32 iflags; - -	data->error = -EINPROGRESS; - -	WARN_ON(host->data); -	host->sg = NULL; -	host->data = data; - -	iflags = ATMCI_DATA_ERROR_FLAGS; -	if (atmci_prepare_data_dma(host, data)) { -		host->data_chan = NULL; +	atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); +} -		/* -		 * Errata: MMC data write operation with less than 12 -		 * bytes is impossible. -		 * -		 * Errata: MCI Transmit Data Register (TDR) FIFO -		 * corruption when length is not multiple of 4. -		 */ -		if (data->blocks * data->blksz < 12 -				|| (data->blocks * data->blksz) & 3) -			host->need_reset = true; +static void atmci_stop_transfer_dma(struct atmel_mci *host) +{ +	struct dma_chan *chan = host->data_chan; -		host->sg = data->sg; -		host->pio_offset = 0; -		if (data->flags & MMC_DATA_READ) -			iflags |= MCI_RXRDY; -		else -			iflags |= MCI_TXRDY; +	if (chan) { +		dmaengine_terminate_all(chan); +		atmci_dma_cleanup(host); +	} else { +		/* Data transfer was stopped by the interrupt handler */ +		dev_dbg(&host->pdev->dev, +		        "(%s) set pending xfer complete\n", __func__); +		atmci_set_pending(host, EVENT_XFER_COMPLETE); +		atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);  	} - -	return iflags;  } +/* + * Start a request: prepare data if needed, prepare the command and activate + * interrupts. + */  static void atmci_start_request(struct atmel_mci *host,  		struct atmel_mci_slot *slot)  { @@ -781,27 +1140,33 @@ static void atmci_start_request(struct atmel_mci *host,  	host->pending_events = 0;  	host->completed_events = 0; +	host->cmd_status = 0;  	host->data_status = 0; -	if (host->need_reset) { -		mci_writel(host, CR, MCI_CR_SWRST); -		mci_writel(host, CR, MCI_CR_MCIEN); -		mci_writel(host, MR, host->mode_reg); -		if (atmci_is_mci2()) -			mci_writel(host, CFG, host->cfg_reg); +	dev_dbg(&host->pdev->dev, "start request: cmd %u\n", mrq->cmd->opcode); + +	if (host->need_reset || host->caps.need_reset_after_xfer) { +		iflags = atmci_readl(host, ATMCI_IMR); +		iflags &= (ATMCI_SDIOIRQA | ATMCI_SDIOIRQB); +		atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST); +		atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIEN); +		atmci_writel(host, ATMCI_MR, host->mode_reg); +		if (host->caps.has_cfg_reg) +			atmci_writel(host, ATMCI_CFG, host->cfg_reg); +		atmci_writel(host, ATMCI_IER, iflags);  		host->need_reset = false;  	} -	mci_writel(host, SDCR, slot->sdc_reg); +	atmci_writel(host, ATMCI_SDCR, slot->sdc_reg); -	iflags = mci_readl(host, IMR); -	if (iflags & ~(MCI_SDIOIRQA | MCI_SDIOIRQB)) -		dev_warn(&slot->mmc->class_dev, "WARNING: IMR=0x%08x\n", +	iflags = atmci_readl(host, ATMCI_IMR); +	if (iflags & ~(ATMCI_SDIOIRQA | ATMCI_SDIOIRQB)) +		dev_dbg(&slot->mmc->class_dev, "WARNING: IMR=0x%08x\n",  				iflags);  	if (unlikely(test_and_clear_bit(ATMCI_CARD_NEED_INIT, &slot->flags))) {  		/* Send init sequence (74 clock cycles) */ -		mci_writel(host, CMDR, MCI_CMDR_SPCMD_INIT); -		while (!(mci_readl(host, SR) & MCI_CMDRDY)) +		atmci_writel(host, ATMCI_CMDR, ATMCI_CMDR_SPCMD_INIT); +		while (!(atmci_readl(host, ATMCI_SR) & ATMCI_CMDRDY))  			cpu_relax();  	}  	iflags = 0; @@ -810,31 +1175,42 @@ static void atmci_start_request(struct atmel_mci *host,  		atmci_set_timeout(host, slot, data);  		/* Must set block count/size before sending command */ -		mci_writel(host, BLKR, MCI_BCNT(data->blocks) -				| MCI_BLKLEN(data->blksz)); +		atmci_writel(host, ATMCI_BLKR, ATMCI_BCNT(data->blocks) +				| ATMCI_BLKLEN(data->blksz));  		dev_vdbg(&slot->mmc->class_dev, "BLKR=0x%08x\n", -			MCI_BCNT(data->blocks) | MCI_BLKLEN(data->blksz)); +			ATMCI_BCNT(data->blocks) | ATMCI_BLKLEN(data->blksz)); -		iflags |= atmci_prepare_data(host, data); +		iflags |= host->prepare_data(host, data);  	} -	iflags |= MCI_CMDRDY; +	iflags |= ATMCI_CMDRDY;  	cmd = mrq->cmd;  	cmdflags = atmci_prepare_command(slot->mmc, cmd); -	atmci_start_command(host, cmd, cmdflags); + +	/* +	 * DMA transfer should be started before sending the command to avoid +	 * unexpected errors especially for read operations in SDIO mode. +	 * Unfortunately, in PDC mode, command has to be sent before starting +	 * the transfer. +	 */ +	if (host->submit_data != &atmci_submit_data_dma) +		atmci_send_command(host, cmd, cmdflags);  	if (data) -		atmci_submit_data(host); +		host->submit_data(host, data); + +	if (host->submit_data == &atmci_submit_data_dma) +		atmci_send_command(host, cmd, cmdflags);  	if (mrq->stop) {  		host->stop_cmdr = atmci_prepare_command(slot->mmc, mrq->stop); -		host->stop_cmdr |= MCI_CMDR_STOP_XFER; +		host->stop_cmdr |= ATMCI_CMDR_STOP_XFER;  		if (!(data->flags & MMC_DATA_WRITE)) -			host->stop_cmdr |= MCI_CMDR_TRDIR_READ; +			host->stop_cmdr |= ATMCI_CMDR_TRDIR_READ;  		if (data->flags & MMC_DATA_STREAM) -			host->stop_cmdr |= MCI_CMDR_STREAM; +			host->stop_cmdr |= ATMCI_CMDR_STREAM;  		else -			host->stop_cmdr |= MCI_CMDR_MULTI_BLOCK; +			host->stop_cmdr |= ATMCI_CMDR_MULTI_BLOCK;  	}  	/* @@ -843,7 +1219,9 @@ static void atmci_start_request(struct atmel_mci *host,  	 * conditions (e.g. command and data complete, but stop not  	 * prepared yet.)  	 */ -	mci_writel(host, IER, iflags); +	atmci_writel(host, ATMCI_IER, iflags); + +	mod_timer(&host->timer, jiffies +  msecs_to_jiffies(2000));  }  static void atmci_queue_request(struct atmel_mci *host, @@ -858,6 +1236,7 @@ static void atmci_queue_request(struct atmel_mci *host,  		host->state = STATE_SENDING_CMD;  		atmci_start_request(host, slot);  	} else { +		dev_dbg(&host->pdev->dev, "queue request\n");  		list_add_tail(&slot->queue_node, &host->queue);  	}  	spin_unlock_bh(&host->lock); @@ -870,6 +1249,7 @@ static void atmci_request(struct mmc_host *mmc, struct mmc_request *mrq)  	struct mmc_data		*data;  	WARN_ON(slot->mrq); +	dev_dbg(&host->pdev->dev, "MRQ: cmd %u\n", mrq->cmd->opcode);  	/*  	 * We may "know" the card is gone even though there's still an @@ -900,14 +1280,15 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)  	struct atmel_mci_slot	*slot = mmc_priv(mmc);  	struct atmel_mci	*host = slot->host;  	unsigned int		i; +	bool			unprepare_clk; -	slot->sdc_reg &= ~MCI_SDCBUS_MASK; +	slot->sdc_reg &= ~ATMCI_SDCBUS_MASK;  	switch (ios->bus_width) {  	case MMC_BUS_WIDTH_1: -		slot->sdc_reg |= MCI_SDCBUS_1BIT; +		slot->sdc_reg |= ATMCI_SDCBUS_1BIT;  		break;  	case MMC_BUS_WIDTH_4: -		slot->sdc_reg |= MCI_SDCBUS_4BIT; +		slot->sdc_reg |= ATMCI_SDCBUS_4BIT;  		break;  	} @@ -915,13 +1296,17 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)  		unsigned int clock_min = ~0U;  		u32 clkdiv; +		clk_prepare(host->mck); +		unprepare_clk = true; +  		spin_lock_bh(&host->lock);  		if (!host->mode_reg) {  			clk_enable(host->mck); -			mci_writel(host, CR, MCI_CR_SWRST); -			mci_writel(host, CR, MCI_CR_MCIEN); -			if (atmci_is_mci2()) -				mci_writel(host, CFG, host->cfg_reg); +			unprepare_clk = false; +			atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST); +			atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIEN); +			if (host->caps.has_cfg_reg) +				atmci_writel(host, ATMCI_CFG, host->cfg_reg);  		}  		/* @@ -929,43 +1314,54 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)  		 * core ios update when finding the minimum.  		 */  		slot->clock = ios->clock; -		for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) { +		for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) {  			if (host->slot[i] && host->slot[i]->clock  					&& host->slot[i]->clock < clock_min)  				clock_min = host->slot[i]->clock;  		}  		/* Calculate clock divider */ -		clkdiv = DIV_ROUND_UP(host->bus_hz, 2 * clock_min) - 1; -		if (clkdiv > 255) { -			dev_warn(&mmc->class_dev, -				"clock %u too slow; using %lu\n", -				clock_min, host->bus_hz / (2 * 256)); -			clkdiv = 255; +		if (host->caps.has_odd_clk_div) { +			clkdiv = DIV_ROUND_UP(host->bus_hz, clock_min) - 2; +			if (clkdiv > 511) { +				dev_warn(&mmc->class_dev, +				         "clock %u too slow; using %lu\n", +				         clock_min, host->bus_hz / (511 + 2)); +				clkdiv = 511; +			} +			host->mode_reg = ATMCI_MR_CLKDIV(clkdiv >> 1) +			                 | ATMCI_MR_CLKODD(clkdiv & 1); +		} else { +			clkdiv = DIV_ROUND_UP(host->bus_hz, 2 * clock_min) - 1; +			if (clkdiv > 255) { +				dev_warn(&mmc->class_dev, +				         "clock %u too slow; using %lu\n", +				         clock_min, host->bus_hz / (2 * 256)); +				clkdiv = 255; +			} +			host->mode_reg = ATMCI_MR_CLKDIV(clkdiv);  		} -		host->mode_reg = MCI_MR_CLKDIV(clkdiv); -  		/*  		 * WRPROOF and RDPROOF prevent overruns/underruns by  		 * stopping the clock when the FIFO is full/empty.  		 * This state is not expected to last for long.  		 */ -		if (mci_has_rwproof()) -			host->mode_reg |= (MCI_MR_WRPROOF | MCI_MR_RDPROOF); +		if (host->caps.has_rwproof) +			host->mode_reg |= (ATMCI_MR_WRPROOF | ATMCI_MR_RDPROOF); -		if (atmci_is_mci2()) { +		if (host->caps.has_cfg_reg) {  			/* setup High Speed mode in relation with card capacity */  			if (ios->timing == MMC_TIMING_SD_HS) -				host->cfg_reg |= MCI_CFG_HSMODE; +				host->cfg_reg |= ATMCI_CFG_HSMODE;  			else -				host->cfg_reg &= ~MCI_CFG_HSMODE; +				host->cfg_reg &= ~ATMCI_CFG_HSMODE;  		}  		if (list_empty(&host->queue)) { -			mci_writel(host, MR, host->mode_reg); -			if (atmci_is_mci2()) -				mci_writel(host, CFG, host->cfg_reg); +			atmci_writel(host, ATMCI_MR, host->mode_reg); +			if (host->caps.has_cfg_reg) +				atmci_writel(host, ATMCI_CFG, host->cfg_reg);  		} else {  			host->need_clock_update = true;  		} @@ -974,28 +1370,40 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)  	} else {  		bool any_slot_active = false; +		unprepare_clk = false; +  		spin_lock_bh(&host->lock);  		slot->clock = 0; -		for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) { +		for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) {  			if (host->slot[i] && host->slot[i]->clock) {  				any_slot_active = true;  				break;  			}  		}  		if (!any_slot_active) { -			mci_writel(host, CR, MCI_CR_MCIDIS); +			atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIDIS);  			if (host->mode_reg) { -				mci_readl(host, MR); +				atmci_readl(host, ATMCI_MR);  				clk_disable(host->mck); +				unprepare_clk = true;  			}  			host->mode_reg = 0;  		}  		spin_unlock_bh(&host->lock);  	} +	if (unprepare_clk) +		clk_unprepare(host->mck); +  	switch (ios->power_mode) { +	case MMC_POWER_OFF: +		if (!IS_ERR(mmc->supply.vmmc)) +			mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); +		break;  	case MMC_POWER_UP:  		set_bit(ATMCI_CARD_NEED_INIT, &slot->flags); +		if (!IS_ERR(mmc->supply.vmmc)) +			mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd);  		break;  	default:  		/* @@ -1049,9 +1457,9 @@ static void atmci_enable_sdio_irq(struct mmc_host *mmc, int enable)  	struct atmel_mci	*host = slot->host;  	if (enable) -		mci_writel(host, IER, slot->sdio_irq); +		atmci_writel(host, ATMCI_IER, slot->sdio_irq);  	else -		mci_writel(host, IDR, slot->sdio_irq); +		atmci_writel(host, ATMCI_IDR, slot->sdio_irq);  }  static const struct mmc_host_ops atmci_ops = { @@ -1075,12 +1483,12 @@ static void atmci_request_end(struct atmel_mci *host, struct mmc_request *mrq)  	/*  	 * Update the MMC clock rate if necessary. This may be  	 * necessary if set_ios() is called when a different slot is -	 * busy transfering data. +	 * busy transferring data.  	 */  	if (host->need_clock_update) { -		mci_writel(host, MR, host->mode_reg); -		if (atmci_is_mci2()) -			mci_writel(host, CFG, host->cfg_reg); +		atmci_writel(host, ATMCI_MR, host->mode_reg); +		if (host->caps.has_cfg_reg) +			atmci_writel(host, ATMCI_CFG, host->cfg_reg);  	}  	host->cur_slot->mrq = NULL; @@ -1098,6 +1506,8 @@ static void atmci_request_end(struct atmel_mci *host, struct mmc_request *mrq)  		host->state = STATE_IDLE;  	} +	del_timer(&host->timer); +  	spin_unlock(&host->lock);  	mmc_request_done(prev_mmc, mrq);  	spin_lock(&host->lock); @@ -1109,32 +1519,24 @@ static void atmci_command_complete(struct atmel_mci *host,  	u32		status = host->cmd_status;  	/* Read the response from the card (up to 16 bytes) */ -	cmd->resp[0] = mci_readl(host, RSPR); -	cmd->resp[1] = mci_readl(host, RSPR); -	cmd->resp[2] = mci_readl(host, RSPR); -	cmd->resp[3] = mci_readl(host, RSPR); +	cmd->resp[0] = atmci_readl(host, ATMCI_RSPR); +	cmd->resp[1] = atmci_readl(host, ATMCI_RSPR); +	cmd->resp[2] = atmci_readl(host, ATMCI_RSPR); +	cmd->resp[3] = atmci_readl(host, ATMCI_RSPR); -	if (status & MCI_RTOE) +	if (status & ATMCI_RTOE)  		cmd->error = -ETIMEDOUT; -	else if ((cmd->flags & MMC_RSP_CRC) && (status & MCI_RCRCE)) +	else if ((cmd->flags & MMC_RSP_CRC) && (status & ATMCI_RCRCE))  		cmd->error = -EILSEQ; -	else if (status & (MCI_RINDE | MCI_RDIRE | MCI_RENDE)) +	else if (status & (ATMCI_RINDE | ATMCI_RDIRE | ATMCI_RENDE))  		cmd->error = -EIO; -	else -		cmd->error = 0; - -	if (cmd->error) { -		dev_dbg(&host->pdev->dev, -			"command error: status=0x%08x\n", status); - -		if (cmd->data) { -			atmci_stop_dma(host); -			host->data = NULL; -			mci_writel(host, IDR, MCI_NOTBUSY -					| MCI_TXRDY | MCI_RXRDY -					| ATMCI_DATA_ERROR_FLAGS); +	else if (host->mrq->data && (host->mrq->data->blksz & 3)) { +		if (host->caps.need_blksz_mul_4) { +			cmd->error = -EINVAL; +			host->need_reset = 1;  		} -	} +	} else +		cmd->error = 0;  }  static void atmci_detect_change(unsigned long data) @@ -1183,11 +1585,11 @@ static void atmci_detect_change(unsigned long data)  				 * Reset controller to terminate any ongoing  				 * commands or data transfers.  				 */ -				mci_writel(host, CR, MCI_CR_SWRST); -				mci_writel(host, CR, MCI_CR_MCIEN); -				mci_writel(host, MR, host->mode_reg); -				if (atmci_is_mci2()) -					mci_writel(host, CFG, host->cfg_reg); +				atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST); +				atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIEN); +				atmci_writel(host, ATMCI_MR, host->mode_reg); +				if (host->caps.has_cfg_reg) +					atmci_writel(host, ATMCI_CFG, host->cfg_reg);  				host->data = NULL;  				host->cmd = NULL; @@ -1197,23 +1599,21 @@ static void atmci_detect_change(unsigned long data)  					break;  				case STATE_SENDING_CMD:  					mrq->cmd->error = -ENOMEDIUM; -					if (!mrq->data) -						break; -					/* fall through */ -				case STATE_SENDING_DATA: +					if (mrq->data) +						host->stop_transfer(host); +					break; +				case STATE_DATA_XFER: +					mrq->data->error = -ENOMEDIUM; +					host->stop_transfer(host); +					break; +				case STATE_WAITING_NOTBUSY:  					mrq->data->error = -ENOMEDIUM; -					atmci_stop_dma(host);  					break; -				case STATE_DATA_BUSY: -				case STATE_DATA_ERROR: -					if (mrq->data->error == -EINPROGRESS) -						mrq->data->error = -ENOMEDIUM; -					if (!mrq->stop) -						break; -					/* fall through */  				case STATE_SENDING_STOP:  					mrq->stop->error = -ENOMEDIUM;  					break; +				case STATE_END_REQUEST: +					break;  				}  				atmci_request_end(host, mrq); @@ -1241,7 +1641,6 @@ static void atmci_tasklet_func(unsigned long priv)  	struct atmel_mci	*host = (struct atmel_mci *)priv;  	struct mmc_request	*mrq = host->mrq;  	struct mmc_data		*data = host->data; -	struct mmc_command	*cmd = host->cmd;  	enum atmel_mci_state	state = host->state;  	enum atmel_mci_state	prev_state;  	u32			status; @@ -1253,111 +1652,193 @@ static void atmci_tasklet_func(unsigned long priv)  	dev_vdbg(&host->pdev->dev,  		"tasklet: state %u pending/completed/mask %lx/%lx/%x\n",  		state, host->pending_events, host->completed_events, -		mci_readl(host, IMR)); +		atmci_readl(host, ATMCI_IMR));  	do {  		prev_state = state; +		dev_dbg(&host->pdev->dev, "FSM: state=%d\n", state);  		switch (state) {  		case STATE_IDLE:  			break;  		case STATE_SENDING_CMD: +			/* +			 * Command has been sent, we are waiting for command +			 * ready. Then we have three next states possible: +			 * END_REQUEST by default, WAITING_NOTBUSY if it's a +			 * command needing it or DATA_XFER if there is data. +			 */ +			dev_dbg(&host->pdev->dev, "FSM: cmd ready?\n");  			if (!atmci_test_and_clear_pending(host, -						EVENT_CMD_COMPLETE)) +						EVENT_CMD_RDY))  				break; +			dev_dbg(&host->pdev->dev, "set completed cmd ready\n");  			host->cmd = NULL; -			atmci_set_completed(host, EVENT_CMD_COMPLETE); +			atmci_set_completed(host, EVENT_CMD_RDY);  			atmci_command_complete(host, mrq->cmd); -			if (!mrq->data || cmd->error) { -				atmci_request_end(host, host->mrq); -				goto unlock; -			} +			if (mrq->data) { +				dev_dbg(&host->pdev->dev, +				        "command with data transfer"); +				/* +				 * If there is a command error don't start +				 * data transfer. +				 */ +				if (mrq->cmd->error) { +					host->stop_transfer(host); +					host->data = NULL; +					atmci_writel(host, ATMCI_IDR, +					             ATMCI_TXRDY | ATMCI_RXRDY +					             | ATMCI_DATA_ERROR_FLAGS); +					state = STATE_END_REQUEST; +				} else +					state = STATE_DATA_XFER; +			} else if ((!mrq->data) && (mrq->cmd->flags & MMC_RSP_BUSY)) { +				dev_dbg(&host->pdev->dev, +				        "command response need waiting notbusy"); +				atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); +				state = STATE_WAITING_NOTBUSY; +			} else +				state = STATE_END_REQUEST; -			prev_state = state = STATE_SENDING_DATA; -			/* fall through */ +			break; -		case STATE_SENDING_DATA: +		case STATE_DATA_XFER:  			if (atmci_test_and_clear_pending(host,  						EVENT_DATA_ERROR)) { -				atmci_stop_dma(host); -				if (data->stop) -					send_stop_cmd(host, data); -				state = STATE_DATA_ERROR; +				dev_dbg(&host->pdev->dev, "set completed data error\n"); +				atmci_set_completed(host, EVENT_DATA_ERROR); +				state = STATE_END_REQUEST;  				break;  			} +			/* +			 * A data transfer is in progress. The event expected +			 * to move to the next state depends of data transfer +			 * type (PDC or DMA). Once transfer done we can move +			 * to the next step which is WAITING_NOTBUSY in write +			 * case and directly SENDING_STOP in read case. +			 */ +			dev_dbg(&host->pdev->dev, "FSM: xfer complete?\n");  			if (!atmci_test_and_clear_pending(host,  						EVENT_XFER_COMPLETE))  				break; +			dev_dbg(&host->pdev->dev, +			        "(%s) set completed xfer complete\n", +				__func__);  			atmci_set_completed(host, EVENT_XFER_COMPLETE); -			prev_state = state = STATE_DATA_BUSY; -			/* fall through */ - -		case STATE_DATA_BUSY: -			if (!atmci_test_and_clear_pending(host, -						EVENT_DATA_COMPLETE)) -				break; -			host->data = NULL; -			atmci_set_completed(host, EVENT_DATA_COMPLETE); -			status = host->data_status; -			if (unlikely(status & ATMCI_DATA_ERROR_FLAGS)) { -				if (status & MCI_DTOE) { -					dev_dbg(&host->pdev->dev, -							"data timeout error\n"); -					data->error = -ETIMEDOUT; -				} else if (status & MCI_DCRCE) { -					dev_dbg(&host->pdev->dev, -							"data CRC error\n"); -					data->error = -EILSEQ; -				} else { -					dev_dbg(&host->pdev->dev, -						"data FIFO error (status=%08x)\n", -						status); -					data->error = -EIO; -				} +			if (host->caps.need_notbusy_for_read_ops || +			   (host->data->flags & MMC_DATA_WRITE)) { +				atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); +				state = STATE_WAITING_NOTBUSY; +			} else if (host->mrq->stop) { +				atmci_writel(host, ATMCI_IER, ATMCI_CMDRDY); +				atmci_send_stop_cmd(host, data); +				state = STATE_SENDING_STOP;  			} else { +				host->data = NULL;  				data->bytes_xfered = data->blocks * data->blksz;  				data->error = 0; -				mci_writel(host, IDR, ATMCI_DATA_ERROR_FLAGS); +				state = STATE_END_REQUEST;  			} +			break; -			if (!data->stop) { -				atmci_request_end(host, host->mrq); -				goto unlock; -			} +		case STATE_WAITING_NOTBUSY: +			/* +			 * We can be in the state for two reasons: a command +			 * requiring waiting not busy signal (stop command +			 * included) or a write operation. In the latest case, +			 * we need to send a stop command. +			 */ +			dev_dbg(&host->pdev->dev, "FSM: not busy?\n"); +			if (!atmci_test_and_clear_pending(host, +						EVENT_NOTBUSY)) +				break; -			prev_state = state = STATE_SENDING_STOP; -			if (!data->error) -				send_stop_cmd(host, data); -			/* fall through */ +			dev_dbg(&host->pdev->dev, "set completed not busy\n"); +			atmci_set_completed(host, EVENT_NOTBUSY); + +			if (host->data) { +				/* +				 * For some commands such as CMD53, even if +				 * there is data transfer, there is no stop +				 * command to send. +				 */ +				if (host->mrq->stop) { +					atmci_writel(host, ATMCI_IER, +					             ATMCI_CMDRDY); +					atmci_send_stop_cmd(host, data); +					state = STATE_SENDING_STOP; +				} else { +					host->data = NULL; +					data->bytes_xfered = data->blocks +					                     * data->blksz; +					data->error = 0; +					state = STATE_END_REQUEST; +				} +			} else +				state = STATE_END_REQUEST; +			break;  		case STATE_SENDING_STOP: +			/* +			 * In this state, it is important to set host->data to +			 * NULL (which is tested in the waiting notbusy state) +			 * in order to go to the end request state instead of +			 * sending stop again. +			 */ +			dev_dbg(&host->pdev->dev, "FSM: cmd ready?\n");  			if (!atmci_test_and_clear_pending(host, -						EVENT_CMD_COMPLETE)) +						EVENT_CMD_RDY))  				break; +			dev_dbg(&host->pdev->dev, "FSM: cmd ready\n");  			host->cmd = NULL; +			data->bytes_xfered = data->blocks * data->blksz; +			data->error = 0;  			atmci_command_complete(host, mrq->stop); -			atmci_request_end(host, host->mrq); -			goto unlock; +			if (mrq->stop->error) { +				host->stop_transfer(host); +				atmci_writel(host, ATMCI_IDR, +				             ATMCI_TXRDY | ATMCI_RXRDY +				             | ATMCI_DATA_ERROR_FLAGS); +				state = STATE_END_REQUEST; +			} else { +				atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); +				state = STATE_WAITING_NOTBUSY; +			} +			host->data = NULL; +			break; -		case STATE_DATA_ERROR: -			if (!atmci_test_and_clear_pending(host, -						EVENT_XFER_COMPLETE)) -				break; +		case STATE_END_REQUEST: +			atmci_writel(host, ATMCI_IDR, ATMCI_TXRDY | ATMCI_RXRDY +			                   | ATMCI_DATA_ERROR_FLAGS); +			status = host->data_status; +			if (unlikely(status)) { +				host->stop_transfer(host); +				host->data = NULL; +				if (data) { +					if (status & ATMCI_DTOE) { +						data->error = -ETIMEDOUT; +					} else if (status & ATMCI_DCRCE) { +						data->error = -EILSEQ; +					} else { +						data->error = -EIO; +					} +				} +			} -			state = STATE_DATA_BUSY; +			atmci_request_end(host, host->mrq); +			state = STATE_IDLE;  			break;  		}  	} while (state != prev_state);  	host->state = state; -unlock:  	spin_unlock(&host->lock);  } @@ -1372,7 +1853,7 @@ static void atmci_read_data_pio(struct atmel_mci *host)  	unsigned int		nbytes = 0;  	do { -		value = mci_readl(host, RDR); +		value = atmci_readl(host, ATMCI_RDR);  		if (likely(offset + 4 <= sg->length)) {  			put_unaligned(value, (u32 *)(buf + offset)); @@ -1382,7 +1863,8 @@ static void atmci_read_data_pio(struct atmel_mci *host)  			if (offset == sg->length) {  				flush_dcache_page(sg_page(sg));  				host->sg = sg = sg_next(sg); -				if (!sg) +				host->sg_len--; +				if (!sg || !host->sg_len)  					goto done;  				offset = 0; @@ -1395,7 +1877,8 @@ static void atmci_read_data_pio(struct atmel_mci *host)  			flush_dcache_page(sg_page(sg));  			host->sg = sg = sg_next(sg); -			if (!sg) +			host->sg_len--; +			if (!sg || !host->sg_len)  				goto done;  			offset = 4 - remaining; @@ -1404,18 +1887,15 @@ static void atmci_read_data_pio(struct atmel_mci *host)  			nbytes += offset;  		} -		status = mci_readl(host, SR); +		status = atmci_readl(host, ATMCI_SR);  		if (status & ATMCI_DATA_ERROR_FLAGS) { -			mci_writel(host, IDR, (MCI_NOTBUSY | MCI_RXRDY +			atmci_writel(host, ATMCI_IDR, (ATMCI_NOTBUSY | ATMCI_RXRDY  						| ATMCI_DATA_ERROR_FLAGS));  			host->data_status = status;  			data->bytes_xfered += nbytes; -			smp_wmb(); -			atmci_set_pending(host, EVENT_DATA_ERROR); -			tasklet_schedule(&host->tasklet);  			return;  		} -	} while (status & MCI_RXRDY); +	} while (status & ATMCI_RXRDY);  	host->pio_offset = offset;  	data->bytes_xfered += nbytes; @@ -1423,8 +1903,8 @@ static void atmci_read_data_pio(struct atmel_mci *host)  	return;  done: -	mci_writel(host, IDR, MCI_RXRDY); -	mci_writel(host, IER, MCI_NOTBUSY); +	atmci_writel(host, ATMCI_IDR, ATMCI_RXRDY); +	atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);  	data->bytes_xfered += nbytes;  	smp_wmb();  	atmci_set_pending(host, EVENT_XFER_COMPLETE); @@ -1443,13 +1923,14 @@ static void atmci_write_data_pio(struct atmel_mci *host)  	do {  		if (likely(offset + 4 <= sg->length)) {  			value = get_unaligned((u32 *)(buf + offset)); -			mci_writel(host, TDR, value); +			atmci_writel(host, ATMCI_TDR, value);  			offset += 4;  			nbytes += 4;  			if (offset == sg->length) {  				host->sg = sg = sg_next(sg); -				if (!sg) +				host->sg_len--; +				if (!sg || !host->sg_len)  					goto done;  				offset = 0; @@ -1463,30 +1944,28 @@ static void atmci_write_data_pio(struct atmel_mci *host)  			nbytes += remaining;  			host->sg = sg = sg_next(sg); -			if (!sg) { -				mci_writel(host, TDR, value); +			host->sg_len--; +			if (!sg || !host->sg_len) { +				atmci_writel(host, ATMCI_TDR, value);  				goto done;  			}  			offset = 4 - remaining;  			buf = sg_virt(sg);  			memcpy((u8 *)&value + remaining, buf, offset); -			mci_writel(host, TDR, value); +			atmci_writel(host, ATMCI_TDR, value);  			nbytes += offset;  		} -		status = mci_readl(host, SR); +		status = atmci_readl(host, ATMCI_SR);  		if (status & ATMCI_DATA_ERROR_FLAGS) { -			mci_writel(host, IDR, (MCI_NOTBUSY | MCI_TXRDY +			atmci_writel(host, ATMCI_IDR, (ATMCI_NOTBUSY | ATMCI_TXRDY  						| ATMCI_DATA_ERROR_FLAGS));  			host->data_status = status;  			data->bytes_xfered += nbytes; -			smp_wmb(); -			atmci_set_pending(host, EVENT_DATA_ERROR); -			tasklet_schedule(&host->tasklet);  			return;  		} -	} while (status & MCI_TXRDY); +	} while (status & ATMCI_TXRDY);  	host->pio_offset = offset;  	data->bytes_xfered += nbytes; @@ -1494,28 +1973,18 @@ static void atmci_write_data_pio(struct atmel_mci *host)  	return;  done: -	mci_writel(host, IDR, MCI_TXRDY); -	mci_writel(host, IER, MCI_NOTBUSY); +	atmci_writel(host, ATMCI_IDR, ATMCI_TXRDY); +	atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);  	data->bytes_xfered += nbytes;  	smp_wmb();  	atmci_set_pending(host, EVENT_XFER_COMPLETE);  } -static void atmci_cmd_interrupt(struct atmel_mci *host, u32 status) -{ -	mci_writel(host, IDR, MCI_CMDRDY); - -	host->cmd_status = status; -	smp_wmb(); -	atmci_set_pending(host, EVENT_CMD_COMPLETE); -	tasklet_schedule(&host->tasklet); -} -  static void atmci_sdio_interrupt(struct atmel_mci *host, u32 status)  {  	int	i; -	for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) { +	for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) {  		struct atmel_mci_slot *slot = host->slot[i];  		if (slot && (status & slot->sdio_irq)) {  			mmc_signal_sdio_irq(slot->mmc); @@ -1531,40 +2000,120 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)  	unsigned int		pass_count = 0;  	do { -		status = mci_readl(host, SR); -		mask = mci_readl(host, IMR); +		status = atmci_readl(host, ATMCI_SR); +		mask = atmci_readl(host, ATMCI_IMR);  		pending = status & mask;  		if (!pending)  			break;  		if (pending & ATMCI_DATA_ERROR_FLAGS) { -			mci_writel(host, IDR, ATMCI_DATA_ERROR_FLAGS -					| MCI_RXRDY | MCI_TXRDY); -			pending &= mci_readl(host, IMR); +			dev_dbg(&host->pdev->dev, "IRQ: data error\n"); +			atmci_writel(host, ATMCI_IDR, ATMCI_DATA_ERROR_FLAGS +					| ATMCI_RXRDY | ATMCI_TXRDY +					| ATMCI_ENDRX | ATMCI_ENDTX +					| ATMCI_RXBUFF | ATMCI_TXBUFE);  			host->data_status = status; +			dev_dbg(&host->pdev->dev, "set pending data error\n");  			smp_wmb();  			atmci_set_pending(host, EVENT_DATA_ERROR);  			tasklet_schedule(&host->tasklet);  		} -		if (pending & MCI_NOTBUSY) { -			mci_writel(host, IDR, -					ATMCI_DATA_ERROR_FLAGS | MCI_NOTBUSY); -			if (!host->data_status) -				host->data_status = status; + +		if (pending & ATMCI_TXBUFE) { +			dev_dbg(&host->pdev->dev, "IRQ: tx buffer empty\n"); +			atmci_writel(host, ATMCI_IDR, ATMCI_TXBUFE); +			atmci_writel(host, ATMCI_IDR, ATMCI_ENDTX); +			/* +			 * We can receive this interruption before having configured +			 * the second pdc buffer, so we need to reconfigure first and +			 * second buffers again +			 */ +			if (host->data_size) { +				atmci_pdc_set_both_buf(host, XFER_TRANSMIT); +				atmci_writel(host, ATMCI_IER, ATMCI_ENDTX); +				atmci_writel(host, ATMCI_IER, ATMCI_TXBUFE); +			} else { +				atmci_pdc_complete(host); +			} +		} else if (pending & ATMCI_ENDTX) { +			dev_dbg(&host->pdev->dev, "IRQ: end of tx buffer\n"); +			atmci_writel(host, ATMCI_IDR, ATMCI_ENDTX); + +			if (host->data_size) { +				atmci_pdc_set_single_buf(host, +						XFER_TRANSMIT, PDC_SECOND_BUF); +				atmci_writel(host, ATMCI_IER, ATMCI_ENDTX); +			} +		} + +		if (pending & ATMCI_RXBUFF) { +			dev_dbg(&host->pdev->dev, "IRQ: rx buffer full\n"); +			atmci_writel(host, ATMCI_IDR, ATMCI_RXBUFF); +			atmci_writel(host, ATMCI_IDR, ATMCI_ENDRX); +			/* +			 * We can receive this interruption before having configured +			 * the second pdc buffer, so we need to reconfigure first and +			 * second buffers again +			 */ +			if (host->data_size) { +				atmci_pdc_set_both_buf(host, XFER_RECEIVE); +				atmci_writel(host, ATMCI_IER, ATMCI_ENDRX); +				atmci_writel(host, ATMCI_IER, ATMCI_RXBUFF); +			} else { +				atmci_pdc_complete(host); +			} +		} else if (pending & ATMCI_ENDRX) { +			dev_dbg(&host->pdev->dev, "IRQ: end of rx buffer\n"); +			atmci_writel(host, ATMCI_IDR, ATMCI_ENDRX); + +			if (host->data_size) { +				atmci_pdc_set_single_buf(host, +						XFER_RECEIVE, PDC_SECOND_BUF); +				atmci_writel(host, ATMCI_IER, ATMCI_ENDRX); +			} +		} + +		/* +		 * First mci IPs, so mainly the ones having pdc, have some +		 * issues with the notbusy signal. You can't get it after +		 * data transmission if you have not sent a stop command. +		 * The appropriate workaround is to use the BLKE signal. +		 */ +		if (pending & ATMCI_BLKE) { +			dev_dbg(&host->pdev->dev, "IRQ: blke\n"); +			atmci_writel(host, ATMCI_IDR, ATMCI_BLKE);  			smp_wmb(); -			atmci_set_pending(host, EVENT_DATA_COMPLETE); +			dev_dbg(&host->pdev->dev, "set pending notbusy\n"); +			atmci_set_pending(host, EVENT_NOTBUSY);  			tasklet_schedule(&host->tasklet);  		} -		if (pending & MCI_RXRDY) + +		if (pending & ATMCI_NOTBUSY) { +			dev_dbg(&host->pdev->dev, "IRQ: not_busy\n"); +			atmci_writel(host, ATMCI_IDR, ATMCI_NOTBUSY); +			smp_wmb(); +			dev_dbg(&host->pdev->dev, "set pending notbusy\n"); +			atmci_set_pending(host, EVENT_NOTBUSY); +			tasklet_schedule(&host->tasklet); +		} + +		if (pending & ATMCI_RXRDY)  			atmci_read_data_pio(host); -		if (pending & MCI_TXRDY) +		if (pending & ATMCI_TXRDY)  			atmci_write_data_pio(host); -		if (pending & MCI_CMDRDY) -			atmci_cmd_interrupt(host, status); +		if (pending & ATMCI_CMDRDY) { +			dev_dbg(&host->pdev->dev, "IRQ: cmd ready\n"); +			atmci_writel(host, ATMCI_IDR, ATMCI_CMDRDY); +			host->cmd_status = status; +			smp_wmb(); +			dev_dbg(&host->pdev->dev, "set pending cmd rdy\n"); +			atmci_set_pending(host, EVENT_CMD_RDY); +			tasklet_schedule(&host->tasklet); +		} -		if (pending & (MCI_SDIOIRQA | MCI_SDIOIRQB)) +		if (pending & (ATMCI_SDIOIRQA | ATMCI_SDIOIRQB))  			atmci_sdio_interrupt(host, status);  	} while (pass_count++ < 5); @@ -1607,21 +2156,41 @@ static int __init atmci_init_slot(struct atmel_mci *host,  	slot->sdc_reg = sdc_reg;  	slot->sdio_irq = sdio_irq; +	dev_dbg(&mmc->class_dev, +	        "slot[%u]: bus_width=%u, detect_pin=%d, " +		"detect_is_active_high=%s, wp_pin=%d\n", +		id, slot_data->bus_width, slot_data->detect_pin, +		slot_data->detect_is_active_high ? "true" : "false", +		slot_data->wp_pin); +  	mmc->ops = &atmci_ops;  	mmc->f_min = DIV_ROUND_UP(host->bus_hz, 512);  	mmc->f_max = host->bus_hz / 2;  	mmc->ocr_avail	= MMC_VDD_32_33 | MMC_VDD_33_34;  	if (sdio_irq)  		mmc->caps |= MMC_CAP_SDIO_IRQ; -	if (atmci_is_mci2()) +	if (host->caps.has_highspeed)  		mmc->caps |= MMC_CAP_SD_HIGHSPEED; -	if (slot_data->bus_width >= 4) +	/* +	 * Without the read/write proof capability, it is strongly suggested to +	 * use only one bit for data to prevent fifo underruns and overruns +	 * which will corrupt data. +	 */ +	if ((slot_data->bus_width >= 4) && host->caps.has_rwproof)  		mmc->caps |= MMC_CAP_4_BIT_DATA; -	mmc->max_segs = 64; -	mmc->max_req_size = 32768 * 512; -	mmc->max_blk_size = 32768; -	mmc->max_blk_count = 512; +	if (atmci_get_version(host) < 0x200) { +		mmc->max_segs = 256; +		mmc->max_blk_size = 4095; +		mmc->max_blk_count = 256; +		mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; +		mmc->max_seg_size = mmc->max_blk_size * mmc->max_segs; +	} else { +		mmc->max_segs = 64; +		mmc->max_req_size = 32768 * 512; +		mmc->max_blk_size = 32768; +		mmc->max_blk_count = 512; +	}  	/* Assume card is present initially */  	set_bit(ATMCI_CARD_PRESENT, &slot->flags); @@ -1646,6 +2215,7 @@ static int __init atmci_init_slot(struct atmel_mci *host,  	}  	host->slot[id] = slot; +	mmc_regulator_get_supply(mmc);  	mmc_add_host(mmc);  	if (gpio_is_valid(slot->detect_pin)) { @@ -1696,11 +2266,15 @@ static void __exit atmci_cleanup_slot(struct atmel_mci_slot *slot,  	mmc_free_host(slot->mmc);  } -#ifdef CONFIG_MMC_ATMELMCI_DMA -static bool filter(struct dma_chan *chan, void *slave) +static bool atmci_filter(struct dma_chan *chan, void *pdata)  { -	struct mci_dma_data	*sl = slave; +	struct mci_platform_data *sl_pdata = pdata; +	struct mci_dma_data *sl; + +	if (!sl_pdata) +		return false; +	sl = sl_pdata->dma_slave;  	if (sl && find_slave_dev(sl) == chan->device->dev) {  		chan->private = slave_data_ptr(sl);  		return true; @@ -1709,38 +2283,92 @@ static bool filter(struct dma_chan *chan, void *slave)  	}  } -static void atmci_configure_dma(struct atmel_mci *host) +static bool atmci_configure_dma(struct atmel_mci *host)  {  	struct mci_platform_data	*pdata; +	dma_cap_mask_t mask;  	if (host == NULL) -		return; +		return false;  	pdata = host->pdev->dev.platform_data; -	if (pdata && find_slave_dev(pdata->dma_slave)) { -		dma_cap_mask_t mask; +	dma_cap_zero(mask); +	dma_cap_set(DMA_SLAVE, mask); -		setup_dma_addr(pdata->dma_slave, -			       host->mapbase + MCI_TDR, -			       host->mapbase + MCI_RDR); - -		/* Try to grab a DMA channel */ -		dma_cap_zero(mask); -		dma_cap_set(DMA_SLAVE, mask); -		host->dma.chan = -			dma_request_channel(mask, filter, pdata->dma_slave); -	} -	if (!host->dma.chan) -		dev_notice(&host->pdev->dev, "DMA not available, using PIO\n"); -	else +	host->dma.chan = dma_request_slave_channel_compat(mask, atmci_filter, pdata, +							  &host->pdev->dev, "rxtx"); +	if (!host->dma.chan) { +		dev_warn(&host->pdev->dev, "no DMA channel available\n"); +		return false; +	} else {  		dev_info(&host->pdev->dev, -					"Using %s for DMA transfers\n", +					"using %s for DMA transfers\n",  					dma_chan_name(host->dma.chan)); + +		host->dma_conf.src_addr = host->mapbase + ATMCI_RDR; +		host->dma_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; +		host->dma_conf.src_maxburst = 1; +		host->dma_conf.dst_addr = host->mapbase + ATMCI_TDR; +		host->dma_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; +		host->dma_conf.dst_maxburst = 1; +		host->dma_conf.device_fc = false; +		return true; +	} +} + +/* + * HSMCI (High Speed MCI) module is not fully compatible with MCI module. + * HSMCI provides DMA support and a new config register but no more supports + * PDC. + */ +static void __init atmci_get_cap(struct atmel_mci *host) +{ +	unsigned int version; + +	version = atmci_get_version(host); +	dev_info(&host->pdev->dev, +			"version: 0x%x\n", version); + +	host->caps.has_dma_conf_reg = 0; +	host->caps.has_pdc = ATMCI_PDC_CONNECTED; +	host->caps.has_cfg_reg = 0; +	host->caps.has_cstor_reg = 0; +	host->caps.has_highspeed = 0; +	host->caps.has_rwproof = 0; +	host->caps.has_odd_clk_div = 0; +	host->caps.has_bad_data_ordering = 1; +	host->caps.need_reset_after_xfer = 1; +	host->caps.need_blksz_mul_4 = 1; +	host->caps.need_notbusy_for_read_ops = 0; + +	/* keep only major version number */ +	switch (version & 0xf00) { +	case 0x500: +		host->caps.has_odd_clk_div = 1; +	case 0x400: +	case 0x300: +		host->caps.has_dma_conf_reg = 1; +		host->caps.has_pdc = 0; +		host->caps.has_cfg_reg = 1; +		host->caps.has_cstor_reg = 1; +		host->caps.has_highspeed = 1; +	case 0x200: +		host->caps.has_rwproof = 1; +		host->caps.need_blksz_mul_4 = 0; +		host->caps.need_notbusy_for_read_ops = 1; +	case 0x100: +		host->caps.has_bad_data_ordering = 0; +		host->caps.need_reset_after_xfer = 0; +	case 0x0: +		break; +	default: +		host->caps.has_pdc = 0; +		dev_warn(&host->pdev->dev, +				"Unmanaged mci version, set minimum capabilities\n"); +		break; +	}  } -#else -static void atmci_configure_dma(struct atmel_mci *host) {} -#endif  static int __init atmci_probe(struct platform_device *pdev)  { @@ -1755,8 +2383,14 @@ static int __init atmci_probe(struct platform_device *pdev)  	if (!regs)  		return -ENXIO;  	pdata = pdev->dev.platform_data; -	if (!pdata) -		return -ENXIO; +	if (!pdata) { +		pdata = atmci_of_init(pdev); +		if (IS_ERR(pdata)) { +			dev_err(&pdev->dev, "platform data not available\n"); +			return PTR_ERR(pdata); +		} +	} +  	irq = platform_get_irq(pdev, 0);  	if (irq < 0)  		return irq; @@ -1780,10 +2414,12 @@ static int __init atmci_probe(struct platform_device *pdev)  	if (!host->regs)  		goto err_ioremap; -	clk_enable(host->mck); -	mci_writel(host, CR, MCI_CR_SWRST); +	ret = clk_prepare_enable(host->mck); +	if (ret) +		goto err_request_irq; +	atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST);  	host->bus_hz = clk_get_rate(host->mck); -	clk_disable(host->mck); +	clk_disable_unprepare(host->mck);  	host->mapbase = regs->start; @@ -1793,24 +2429,48 @@ static int __init atmci_probe(struct platform_device *pdev)  	if (ret)  		goto err_request_irq; -	atmci_configure_dma(host); +	/* Get MCI capabilities and set operations according to it */ +	atmci_get_cap(host); +	if (atmci_configure_dma(host)) { +		host->prepare_data = &atmci_prepare_data_dma; +		host->submit_data = &atmci_submit_data_dma; +		host->stop_transfer = &atmci_stop_transfer_dma; +	} else if (host->caps.has_pdc) { +		dev_info(&pdev->dev, "using PDC\n"); +		host->prepare_data = &atmci_prepare_data_pdc; +		host->submit_data = &atmci_submit_data_pdc; +		host->stop_transfer = &atmci_stop_transfer_pdc; +	} else { +		dev_info(&pdev->dev, "using PIO\n"); +		host->prepare_data = &atmci_prepare_data; +		host->submit_data = &atmci_submit_data; +		host->stop_transfer = &atmci_stop_transfer; +	}  	platform_set_drvdata(pdev, host); +	setup_timer(&host->timer, atmci_timeout_timer, (unsigned long)host); +  	/* We need at least one slot to succeed */  	nr_slots = 0;  	ret = -ENODEV;  	if (pdata->slot[0].bus_width) {  		ret = atmci_init_slot(host, &pdata->slot[0], -				0, MCI_SDCSEL_SLOT_A, MCI_SDIOIRQA); -		if (!ret) +				0, ATMCI_SDCSEL_SLOT_A, ATMCI_SDIOIRQA); +		if (!ret) {  			nr_slots++; +			host->buf_size = host->slot[0]->mmc->max_req_size; +		}  	}  	if (pdata->slot[1].bus_width) {  		ret = atmci_init_slot(host, &pdata->slot[1], -				1, MCI_SDCSEL_SLOT_B, MCI_SDIOIRQB); -		if (!ret) +				1, ATMCI_SDCSEL_SLOT_B, ATMCI_SDIOIRQB); +		if (!ret) {  			nr_slots++; +			if (host->slot[1]->mmc->max_req_size > host->buf_size) +				host->buf_size = +					host->slot[1]->mmc->max_req_size; +		}  	}  	if (!nr_slots) { @@ -1818,6 +2478,17 @@ static int __init atmci_probe(struct platform_device *pdev)  		goto err_init_slot;  	} +	if (!host->caps.has_rwproof) { +		host->buffer = dma_alloc_coherent(&pdev->dev, host->buf_size, +		                                  &host->buf_phys_addr, +						  GFP_KERNEL); +		if (!host->buffer) { +			ret = -ENOMEM; +			dev_err(&pdev->dev, "buffer allocation failed\n"); +			goto err_init_slot; +		} +	} +  	dev_info(&pdev->dev,  			"Atmel MCI controller at 0x%08lx irq %d, %u slots\n",  			host->mapbase, irq, nr_slots); @@ -1825,10 +2496,8 @@ static int __init atmci_probe(struct platform_device *pdev)  	return 0;  err_init_slot: -#ifdef CONFIG_MMC_ATMELMCI_DMA  	if (host->dma.chan)  		dma_release_channel(host->dma.chan); -#endif  	free_irq(irq, host);  err_request_irq:  	iounmap(host->regs); @@ -1844,23 +2513,23 @@ static int __exit atmci_remove(struct platform_device *pdev)  	struct atmel_mci	*host = platform_get_drvdata(pdev);  	unsigned int		i; -	platform_set_drvdata(pdev, NULL); +	if (host->buffer) +		dma_free_coherent(&pdev->dev, host->buf_size, +		                  host->buffer, host->buf_phys_addr); -	for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) { +	for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) {  		if (host->slot[i])  			atmci_cleanup_slot(host->slot[i], i);  	} -	clk_enable(host->mck); -	mci_writel(host, IDR, ~0UL); -	mci_writel(host, CR, MCI_CR_MCIDIS); -	mci_readl(host, SR); -	clk_disable(host->mck); +	clk_prepare_enable(host->mck); +	atmci_writel(host, ATMCI_IDR, ~0UL); +	atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIDIS); +	atmci_readl(host, ATMCI_SR); +	clk_disable_unprepare(host->mck); -#ifdef CONFIG_MMC_ATMELMCI_DMA  	if (host->dma.chan)  		dma_release_channel(host->dma.chan); -#endif  	free_irq(platform_get_irq(pdev, 0), host);  	iounmap(host->regs); @@ -1875,6 +2544,7 @@ static struct platform_driver atmci_driver = {  	.remove		= __exit_p(atmci_remove),  	.driver		= {  		.name		= "atmel_mci", +		.of_match_table	= of_match_ptr(atmci_dt_ids),  	},  }; @@ -1892,5 +2562,5 @@ late_initcall(atmci_init); /* try to load after dma driver when built-in */  module_exit(atmci_exit);  MODULE_DESCRIPTION("Atmel Multimedia Card Interface driver"); -MODULE_AUTHOR("Haavard Skinnemoen <haavard.skinnemoen@atmel.com>"); +MODULE_AUTHOR("Haavard Skinnemoen (Atmel)");  MODULE_LICENSE("GPL v2");  | 
