Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit aa312be1 authored by Russell King's avatar Russell King
Browse files

Merge branches 'mmci' and 'pl011-dma' into devel

Loading
Loading
Loading
Loading
+177 −30
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include <linux/highmem.h>
#include <linux/log2.h>
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
#include <linux/amba/bus.h>
#include <linux/clk.h>
#include <linux/scatterlist.h>
@@ -45,6 +46,12 @@ static unsigned int fmax = 515633;
 *	      is asserted (likewise for RX)
 * @fifohalfsize: number of bytes that can be written when MCI_TXFIFOHALFEMPTY
 *		  is asserted (likewise for RX)
 * @broken_blockend: the MCI_DATABLOCKEND is broken on the hardware
 *		and will not work at all.
 * @broken_blockend_dma: the MCI_DATABLOCKEND is broken on the hardware when
 *		using DMA.
 * @sdio: variant supports SDIO
 * @st_clkdiv: true if using a ST-specific clock divider algorithm
 */
struct variant_data {
	unsigned int		clkreg;
@@ -52,6 +59,10 @@ struct variant_data {
	unsigned int		datalength_bits;
	unsigned int		fifosize;
	unsigned int		fifohalfsize;
	bool			broken_blockend;
	bool			broken_blockend_dma;
	bool			sdio;
	bool			st_clkdiv;
};

static struct variant_data variant_arm = {
@@ -65,6 +76,8 @@ static struct variant_data variant_u300 = {
	.fifohalfsize		= 8 * 4,
	.clkreg_enable		= 1 << 13, /* HWFCEN */
	.datalength_bits	= 16,
	.broken_blockend_dma	= true,
	.sdio			= true,
};

static struct variant_data variant_ux500 = {
@@ -73,7 +86,11 @@ static struct variant_data variant_ux500 = {
	.clkreg			= MCI_CLK_ENABLE,
	.clkreg_enable		= 1 << 14, /* HWFCEN */
	.datalength_bits	= 24,
	.broken_blockend	= true,
	.sdio			= true,
	.st_clkdiv		= true,
};

/*
 * This must be called with host->lock held
 */
@@ -86,7 +103,22 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired)
		if (desired >= host->mclk) {
			clk = MCI_CLK_BYPASS;
			host->cclk = host->mclk;
		} else if (variant->st_clkdiv) {
			/*
			 * DB8500 TRM says f = mclk / (clkdiv + 2)
			 * => clkdiv = (mclk / f) - 2
			 * Round the divider up so we don't exceed the max
			 * frequency
			 */
			clk = DIV_ROUND_UP(host->mclk, desired) - 2;
			if (clk >= 256)
				clk = 255;
			host->cclk = host->mclk / (clk + 2);
		} else {
			/*
			 * PL180 TRM says f = mclk / (2 * (clkdiv + 1))
			 * => clkdiv = mclk / (2 * f) - 1
			 */
			clk = host->mclk / (2 * desired) - 1;
			if (clk >= 256)
				clk = 255;
@@ -129,10 +161,26 @@ mmci_request_end(struct mmci_host *host, struct mmc_request *mrq)
	spin_lock(&host->lock);
}

static void mmci_set_mask1(struct mmci_host *host, unsigned int mask)
{
	void __iomem *base = host->base;

	if (host->singleirq) {
		unsigned int mask0 = readl(base + MMCIMASK0);

		mask0 &= ~MCI_IRQ1MASK;
		mask0 |= mask;

		writel(mask0, base + MMCIMASK0);
	}

	writel(mask, base + MMCIMASK1);
}

static void mmci_stop_data(struct mmci_host *host)
{
	writel(0, host->base + MMCIDATACTRL);
	writel(0, host->base + MMCIMASK1);
	mmci_set_mask1(host, 0);
	host->data = NULL;
}

@@ -162,6 +210,8 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
	host->data = data;
	host->size = data->blksz * data->blocks;
	host->data_xfered = 0;
	host->blockend = false;
	host->dataend = false;

	mmci_init_sg(host, data);

@@ -196,9 +246,14 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
		irqmask = MCI_TXFIFOHALFEMPTYMASK;
	}

	/* The ST Micro variants has a special bit to enable SDIO */
	if (variant->sdio && host->mmc->card)
		if (mmc_card_sdio(host->mmc->card))
			datactrl |= MCI_ST_DPSM_SDIOEN;

	writel(datactrl, base + MMCIDATACTRL);
	writel(readl(base + MMCIMASK0) & ~MCI_DATAENDMASK, base + MMCIMASK0);
	writel(irqmask, base + MMCIMASK1);
	mmci_set_mask1(host, irqmask);
}

static void
@@ -233,20 +288,9 @@ static void
mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
	      unsigned int status)
{
	if (status & MCI_DATABLOCKEND) {
		host->data_xfered += data->blksz;
#ifdef CONFIG_ARCH_U300
		/*
		 * On the U300 some signal or other is
		 * badly routed so that a data write does
		 * not properly terminate with a MCI_DATAEND
		 * status flag. This quirk will make writes
		 * work again.
		 */
		if (data->flags & MMC_DATA_WRITE)
			status |= MCI_DATAEND;
#endif
	}
	struct variant_data *variant = host->variant;

	/* First check for errors */
	if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
		dev_dbg(mmc_dev(host->mmc), "MCI ERROR IRQ (status %08x)\n", status);
		if (status & MCI_DATACRCFAIL)
@@ -255,7 +299,10 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
			data->error = -ETIMEDOUT;
		else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN))
			data->error = -EIO;
		status |= MCI_DATAEND;

		/* Force-complete the transaction */
		host->blockend = true;
		host->dataend = true;

		/*
		 * We hit an error condition.  Ensure that any data
@@ -273,9 +320,64 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
			local_irq_restore(flags);
		}
	}
	if (status & MCI_DATAEND) {

	/*
	 * On ARM variants in PIO mode, MCI_DATABLOCKEND
	 * is always sent first, and we increase the
	 * transfered number of bytes for that IRQ. Then
	 * MCI_DATAEND follows and we conclude the transaction.
	 *
	 * On the Ux500 single-IRQ variant MCI_DATABLOCKEND
	 * doesn't seem to immediately clear from the status,
	 * so we can't use it keep count when only one irq is
	 * used because the irq will hit for other reasons, and
	 * then the flag is still up. So we use the MCI_DATAEND
	 * IRQ at the end of the entire transfer because
	 * MCI_DATABLOCKEND is broken.
	 *
	 * In the U300, the IRQs can arrive out-of-order,
	 * e.g. MCI_DATABLOCKEND sometimes arrives after MCI_DATAEND,
	 * so for this case we use the flags "blockend" and
	 * "dataend" to make sure both IRQs have arrived before
	 * concluding the transaction. (This does not apply
	 * to the Ux500 which doesn't fire MCI_DATABLOCKEND
	 * at all.) In DMA mode it suffers from the same problem
	 * as the Ux500.
	 */
	if (status & MCI_DATABLOCKEND) {
		/*
		 * Just being a little over-cautious, we do not
		 * use this progressive update if the hardware blockend
		 * flag is unreliable: since it can stay high between
		 * IRQs it will corrupt the transfer counter.
		 */
		if (!variant->broken_blockend)
			host->data_xfered += data->blksz;
		host->blockend = true;
	}

	if (status & MCI_DATAEND)
		host->dataend = true;

	/*
	 * On variants with broken blockend we shall only wait for dataend,
	 * on others we must sync with the blockend signal since they can
	 * appear out-of-order.
	 */
	if (host->dataend && (host->blockend || variant->broken_blockend)) {
		mmci_stop_data(host);

		/* Reset these flags */
		host->blockend = false;
		host->dataend = false;

		/*
		 * Variants with broken blockend flags need to handle the
		 * end of the entire transfer here.
		 */
		if (variant->broken_blockend && !data->error)
			host->data_xfered += data->blksz * data->blocks;

		if (!data->stop) {
			mmci_request_end(host, data->mrq);
		} else {
@@ -356,7 +458,32 @@ static int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int rem
			 variant->fifosize : variant->fifohalfsize;
		count = min(remain, maxcnt);

		writesl(base + MMCIFIFO, ptr, count >> 2);
		/*
		 * The ST Micro variant for SDIO transfer sizes
		 * less then 8 bytes should have clock H/W flow
		 * control disabled.
		 */
		if (variant->sdio &&
		    mmc_card_sdio(host->mmc->card)) {
			if (count < 8)
				writel(readl(host->base + MMCICLOCK) &
					~variant->clkreg_enable,
					host->base + MMCICLOCK);
			else
				writel(readl(host->base + MMCICLOCK) |
					variant->clkreg_enable,
					host->base + MMCICLOCK);
		}

		/*
		 * SDIO especially may want to send something that is
		 * not divisible by 4 (as opposed to card sectors
		 * etc), and the FIFO only accept full 32-bit writes.
		 * So compensate by adding +3 on the count, a single
		 * byte become a 32bit write, 7 bytes will be two
		 * 32bit writes etc.
		 */
		writesl(base + MMCIFIFO, ptr, (count + 3) >> 2);

		ptr += count;
		remain -= count;
@@ -437,7 +564,7 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id)
	 * "any data available" mode.
	 */
	if (status & MCI_RXACTIVE && host->size < variant->fifosize)
		writel(MCI_RXDATAAVLBLMASK, base + MMCIMASK1);
		mmci_set_mask1(host, MCI_RXDATAAVLBLMASK);

	/*
	 * If we run out of data, disable the data IRQs; this
@@ -446,7 +573,7 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id)
	 * stops us racing with our data end IRQ.
	 */
	if (host->size == 0) {
		writel(0, base + MMCIMASK1);
		mmci_set_mask1(host, 0);
		writel(readl(base + MMCIMASK0) | MCI_DATAENDMASK, base + MMCIMASK0);
	}

@@ -469,6 +596,14 @@ static irqreturn_t mmci_irq(int irq, void *dev_id)
		struct mmc_data *data;

		status = readl(host->base + MMCISTATUS);

		if (host->singleirq) {
			if (status & readl(host->base + MMCIMASK1))
				mmci_pio_irq(irq, dev_id);

			status &= ~MCI_IRQ1MASK;
		}

		status &= readl(host->base + MMCIMASK0);
		writel(status, host->base + MMCICLEAR);

@@ -635,6 +770,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
	struct variant_data *variant = id->data;
	struct mmci_host *host;
	struct mmc_host *mmc;
	unsigned int mask;
	int ret;

	/* must have platform data */
@@ -806,20 +942,30 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
	if (ret)
		goto unmap;

	ret = request_irq(dev->irq[1], mmci_pio_irq, IRQF_SHARED, DRIVER_NAME " (pio)", host);
	if (dev->irq[1] == NO_IRQ)
		host->singleirq = true;
	else {
		ret = request_irq(dev->irq[1], mmci_pio_irq, IRQF_SHARED,
				  DRIVER_NAME " (pio)", host);
		if (ret)
			goto irq0_free;
	}

	writel(MCI_IRQENABLE, host->base + MMCIMASK0);
	mask = MCI_IRQENABLE;
	/* Don't use the datablockend flag if it's broken */
	if (variant->broken_blockend)
		mask &= ~MCI_DATABLOCKEND;

	amba_set_drvdata(dev, mmc);
	writel(mask, host->base + MMCIMASK0);

	mmc_add_host(mmc);
	amba_set_drvdata(dev, mmc);

	dev_info(&dev->dev, "%s: MMCI rev %x cfg %02x at 0x%016llx irq %d,%d\n",
		mmc_hostname(mmc), amba_rev(dev), amba_config(dev),
	dev_info(&dev->dev, "%s: PL%03x rev%u at 0x%08llx irq %d,%d\n",
		mmc_hostname(mmc), amba_part(dev), amba_rev(dev),
		(unsigned long long)dev->res.start, dev->irq[0], dev->irq[1]);

	mmc_add_host(mmc);

	return 0;

 irq0_free:
@@ -864,6 +1010,7 @@ static int __devexit mmci_remove(struct amba_device *dev)
		writel(0, host->base + MMCIDATACTRL);

		free_irq(dev->irq[0], host);
		if (!host->singleirq)
			free_irq(dev->irq[1], host);

		if (host->gpio_wp != -ENOSYS)
+9 −0
Original line number Diff line number Diff line
@@ -139,6 +139,11 @@
	MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK|	\
	MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_DATABLOCKENDMASK)

/* These interrupts are directed to IRQ1 when two IRQ lines are available */
#define MCI_IRQ1MASK \
	(MCI_RXFIFOHALFFULLMASK | MCI_RXDATAAVLBLMASK | \
	 MCI_TXFIFOHALFEMPTYMASK)

#define NR_SG		16

struct clk;
@@ -154,6 +159,7 @@ struct mmci_host {
	int			gpio_cd;
	int			gpio_wp;
	int			gpio_cd_irq;
	bool			singleirq;

	unsigned int		data_xfered;

@@ -171,6 +177,9 @@ struct mmci_host {
	struct timer_list	timer;
	unsigned int		oldstat;

	bool			blockend;
	bool			dataend;

	/* pio stuff */
	struct sg_mapping_iter	sg_miter;
	unsigned int		size;
+561 −31

File changed.

Preview size limit exceeded, changes collapsed.

+22 −0
Original line number Diff line number Diff line
@@ -113,6 +113,21 @@
#define UART01x_LCRH_PEN	0x02
#define UART01x_LCRH_BRK	0x01

#define ST_UART011_DMAWM_RX_1	(0 << 3)
#define ST_UART011_DMAWM_RX_2	(1 << 3)
#define ST_UART011_DMAWM_RX_4	(2 << 3)
#define ST_UART011_DMAWM_RX_8	(3 << 3)
#define ST_UART011_DMAWM_RX_16	(4 << 3)
#define ST_UART011_DMAWM_RX_32	(5 << 3)
#define ST_UART011_DMAWM_RX_48	(6 << 3)
#define ST_UART011_DMAWM_TX_1	0
#define ST_UART011_DMAWM_TX_2	1
#define ST_UART011_DMAWM_TX_4	2
#define ST_UART011_DMAWM_TX_8	3
#define ST_UART011_DMAWM_TX_16	4
#define ST_UART011_DMAWM_TX_32	5
#define ST_UART011_DMAWM_TX_48	6

#define UART010_IIR_RTIS	0x08
#define UART010_IIR_TIS		0x04
#define UART010_IIR_RIS		0x02
@@ -180,6 +195,13 @@ struct amba_device; /* in uncompress this is included but amba/bus.h is not */
struct amba_pl010_data {
	void (*set_mctrl)(struct amba_device *dev, void __iomem *base, unsigned int mctrl);
};

struct dma_chan;
struct amba_pl011_data {
	bool (*dma_filter)(struct dma_chan *chan, void *filter_param);
	void *dma_rx_param;
	void *dma_tx_param;
};
#endif

#endif