All of lore.kernel.org
 help / color / mirror / Atom feed
From: Igor Grinberg <grinberg@compulab.co.il>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH 1/2] PXA: Add MMC driver using the generic MMC framework
Date: Tue, 01 Nov 2011 14:08:23 +0200	[thread overview]
Message-ID: <4EAFE137.80404@compulab.co.il> (raw)
In-Reply-To: <1314568975-19619-1-git-send-email-marek.vasut@gmail.com>

Hi Marek,

On 08/29/11 01:02, Marek Vasut wrote:
> Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
> ---
>  arch/arm/include/asm/arch-pxa/regs-mmc.h |  155 +++++++++++
>  drivers/mmc/Makefile                     |    1 +
>  drivers/mmc/pxa_mmc_gen.c                |  442 ++++++++++++++++++++++++++++++
>  3 files changed, 598 insertions(+), 0 deletions(-)
>  create mode 100644 arch/arm/include/asm/arch-pxa/regs-mmc.h
>  create mode 100644 drivers/mmc/pxa_mmc_gen.c
> 
> diff --git a/arch/arm/include/asm/arch-pxa/regs-mmc.h b/arch/arm/include/asm/arch-pxa/regs-mmc.h
> new file mode 100644
> index 0000000..fd1eb1e
> --- /dev/null
> +++ b/arch/arm/include/asm/arch-pxa/regs-mmc.h
> @@ -0,0 +1,155 @@
> +/*
> + * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
> + * MA 02111-1307 USA
> + */
> +
> +#ifndef	__REGS_MMC_H__
> +#define	__REGS_MMC_H__
> +
> +#define	MMC0_BASE	0x41100000
> +#define	MMC1_BASE	0x42000000
> +
> +int pxa_mmc_register(int card_index);
> +
> +struct pxa_mmc_regs {
> +	uint32_t	strpcl;
> +	uint32_t	stat;
> +	uint32_t	clkrt;
> +	uint32_t	spi;
> +	uint32_t	cmdat;
> +	uint32_t	resto;
> +	uint32_t	rdto;
> +	uint32_t	blklen;
> +	uint32_t	nob;
> +	uint32_t	prtbuf;
> +	uint32_t	i_mask;
> +	uint32_t	i_reg;
> +	uint32_t	cmd;
> +	uint32_t	argh;
> +	uint32_t	argl;
> +	uint32_t	res;
> +	uint32_t	rxfifo;
> +	uint32_t	txfifo;

Isn't space would be enough?
I mean, they all the same type, so no alignment issues...

> +};
> +
> +/* MMC_STRPCL */
> +#define	MMC_STRPCL_STOP_CLK		(1 << 0)
> +#define	MMC_STRPCL_START_CLK		(1 << 1)
> +
> +/* MMC_STAT */
> +#define	MMC_STAT_END_CMD_RES		(1 << 13)
> +#define	MMC_STAT_PRG_DONE		(1 << 12)
> +#define	MMC_STAT_DATA_TRAN_DONE		(1 << 11)
> +#define	MMC_STAT_CLK_EN			(1 << 8)
> +#define	MMC_STAT_RECV_FIFO_FULL		(1 << 7)
> +#define	MMC_STAT_XMIT_FIFO_EMPTY	(1 << 6)
> +#define	MMC_STAT_RES_CRC_ERROR		(1 << 5)
> +#define	MMC_STAT_SPI_READ_ERROR_TOKEN   (1 << 4)
> +#define	MMC_STAT_CRC_READ_ERROR		(1 << 3)
> +#define	MMC_STAT_CRC_WRITE_ERROR	(1 << 2)
> +#define	MMC_STAT_TIME_OUT_RESPONSE	(1 << 1)
> +#define	MMC_STAT_READ_TIME_OUT		(1 << 0)
> +
> +/* MMC_CLKRT */
> +#define	MMC_CLKRT_20MHZ			0
> +#define	MMC_CLKRT_10MHZ			1
> +#define	MMC_CLKRT_5MHZ			2
> +#define	MMC_CLKRT_2_5MHZ		3
> +#define	MMC_CLKRT_1_25MHZ		4
> +#define	MMC_CLKRT_0_625MHZ		5
> +#define	MMC_CLKRT_0_3125MHZ		6
> +
> +/* MMC_SPI */
> +#define	MMC_SPI_EN			(1 << 0)
> +#define	MMC_SPI_CS_EN			(1 << 2)
> +#define	MMC_SPI_CS_ADDRESS		(1 << 3)
> +#define	MMC_SPI_CRC_ON			(1 << 1)
> +
> +/* MMC_CMDAT */
> +#define	MMC_CMDAT_SD_4DAT		(1 << 8)
> +#define	MMC_CMDAT_MMC_DMA_EN		(1 << 7)
> +#define	MMC_CMDAT_INIT			(1 << 6)
> +#define	MMC_CMDAT_BUSY			(1 << 5)
> +#define	MMC_CMDAT_BCR			(MMC_CMDAT_BUSY | MMC_CMDAT_INIT)
> +#define	MMC_CMDAT_STREAM		(1 << 4)
> +#define	MMC_CMDAT_WRITE			(1 << 3)
> +#define	MMC_CMDAT_DATA_EN		(1 << 2)
> +#define	MMC_CMDAT_R0			0
> +#define	MMC_CMDAT_R1			1
> +#define	MMC_CMDAT_R2			2
> +#define	MMC_CMDAT_R3			3
> +
> +/* MMC_RESTO */
> +#define	MMC_RES_TO_MAX_MASK		0x7f
> +
> +/* MMC_RDTO */
> +#define	MMC_READ_TO_MAX_MASK		0xffff
> +
> +/* MMC_BLKLEN */
> +#define	MMC_BLK_LEN_MAX_MASK		0x3ff
> +
> +/* MMC_PRTBUF */
> +#define	MMC_PRTBUF_BUF_PART_FULL	(1 << 0)
> +
> +/* MMC_I_MASK */
> +#define	MMC_I_MASK_TXFIFO_WR_REQ	(1 << 6)
> +#define	MMC_I_MASK_RXFIFO_RD_REQ	(1 << 5)
> +#define	MMC_I_MASK_CLK_IS_OFF		(1 << 4)
> +#define	MMC_I_MASK_STOP_CMD		(1 << 3)
> +#define	MMC_I_MASK_END_CMD_RES		(1 << 2)
> +#define	MMC_I_MASK_PRG_DONE		(1 << 1)
> +#define	MMC_I_MASK_DATA_TRAN_DONE       (1 << 0)
> +#define	MMC_I_MASK_ALL			0x7f
> +
> +
> +/* MMC_I_REG */
> +#define	MMC_I_REG_TXFIFO_WR_REQ		(1 << 6)
> +#define	MMC_I_REG_RXFIFO_RD_REQ		(1 << 5)
> +#define	MMC_I_REG_CLK_IS_OFF		(1 << 4)
> +#define	MMC_I_REG_STOP_CMD		(1 << 3)
> +#define	MMC_I_REG_END_CMD_RES		(1 << 2)
> +#define	MMC_I_REG_PRG_DONE		(1 << 1)
> +#define	MMC_I_REG_DATA_TRAN_DONE	(1 << 0)
> +
> +/* MMC_CMD */
> +#define	MMC_CMD_INDEX_MAX		0x6f
> +#define	CMD(x)  (x)

You've missed this one

> +
> +#define	MMC_R1_IDLE_STATE		0x01
> +#define	MMC_R1_ERASE_STATE		0x02
> +#define	MMC_R1_ILLEGAL_CMD		0x04
> +#define	MMC_R1_COM_CRC_ERR		0x08
> +#define	MMC_R1_ERASE_SEQ_ERR		0x01
> +#define	MMC_R1_ADDR_ERR			0x02
> +#define	MMC_R1_PARAM_ERR		0x04
> +
> +#define	MMC_R1B_WP_ERASE_SKIP		0x0002
> +#define	MMC_R1B_ERR			0x0004
> +#define	MMC_R1B_CC_ERR			0x0008
> +#define	MMC_R1B_CARD_ECC_ERR		0x0010
> +#define	MMC_R1B_WP_VIOLATION		0x0020
> +#define	MMC_R1B_ERASE_PARAM		0x0040
> +#define	MMC_R1B_OOR			0x0080
> +#define	MMC_R1B_IDLE_STATE		0x0100
> +#define	MMC_R1B_ERASE_RESET		0x0200
> +#define	MMC_R1B_ILLEGAL_CMD		0x0400
> +#define	MMC_R1B_COM_CRC_ERR		0x0800
> +#define	MMC_R1B_ERASE_SEQ_ERR		0x1000
> +#define	MMC_R1B_ADDR_ERR		0x2000
> +#define	MMC_R1B_PARAM_ERR		0x4000

All the above defines are really unnecessarily "tabbed"...
The values are fine, but why the names?

> +
> +#endif	/* __REGS_MMC_H__ */
> diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
> index 3968c14..59bda49 100644
> --- a/drivers/mmc/Makefile
> +++ b/drivers/mmc/Makefile
> @@ -38,6 +38,7 @@ COBJS-$(CONFIG_MXC_MMC) += mxcmmc.o
>  COBJS-$(CONFIG_OMAP3_MMC) += omap3_mmc.o
>  COBJS-$(CONFIG_OMAP_HSMMC) += omap_hsmmc.o
>  COBJS-$(CONFIG_PXA_MMC) += pxa_mmc.o
> +COBJS-$(CONFIG_PXA_MMC_GENERIC) += pxa_mmc_gen.o
>  COBJS-$(CONFIG_S5P_MMC) += s5p_mmc.o
>  COBJS-$(CONFIG_SDHCI) += sdhci.o
>  COBJS-$(CONFIG_SH_MMCIF) += sh_mmcif.o
> diff --git a/drivers/mmc/pxa_mmc_gen.c b/drivers/mmc/pxa_mmc_gen.c
> new file mode 100644
> index 0000000..aa475e5
> --- /dev/null
> +++ b/drivers/mmc/pxa_mmc_gen.c
> @@ -0,0 +1,442 @@
> +/*
> + * Copyright (C) 2010 Marek Vasut <marek.vasut@gmail.com>
> + *
> + * Loosely based on the old code and Linux's PXA MMC driver
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
> + * MA 02111-1307 USA
> + */
> +
> +#include <config.h>
> +#include <common.h>
> +#include <malloc.h>
> +
> +#include <mmc.h>
> +#include <asm/errno.h>
> +#include <asm/arch/hardware.h>
> +#include <asm/arch/regs-mmc.h>
> +#include <asm/io.h>
> +
> +/* PXAMMC Generic default config for various CPUs */
> +#if defined(CONFIG_PXA250)
> +#define	PXAMMC_FIFO_SIZE	1
> +#define	PXAMMC_MIN_SPEED	312500
> +#define	PXAMMC_MAX_SPEED	20000000
> +#define	PXAMMC_HOST_CAPS	(0)
> +#elif defined(CONFIG_PXA27X)
> +#define	PXAMMC_CRC_SKIP
> +#define	PXAMMC_FIFO_SIZE	32
> +#define	PXAMMC_MIN_SPEED	304000
> +#define	PXAMMC_MAX_SPEED	19500000
> +#define	PXAMMC_HOST_CAPS	(MMC_MODE_4BIT)
> +#elif defined(CONFIG_CPU_MONAHANS)
> +#define	PXAMMC_FIFO_SIZE	32
> +#define	PXAMMC_MIN_SPEED	304000
> +#define	PXAMMC_MAX_SPEED	26000000
> +#define	PXAMMC_HOST_CAPS	(MMC_MODE_4BIT | MMC_MODE_HS)

Same here... and below... why?

> +#else
> +#error "This CPU isn't supported by PXA MMC!"
> +#endif
> +
> +#define	MMC_STAT_ERRORS							\
> +	(MMC_STAT_RES_CRC_ERROR | MMC_STAT_SPI_READ_ERROR_TOKEN |	\
> +	MMC_STAT_CRC_READ_ERROR | MMC_STAT_TIME_OUT_RESPONSE |		\
> +	MMC_STAT_READ_TIME_OUT | MMC_STAT_CRC_WRITE_ERROR)
> +
> +/* 1 millisecond (in wait cycles below it's 100 x 10uS waits) */
> +#define	PXA_MMC_TIMEOUT	100
> +
> +struct pxa_mmc_priv {
> +	struct pxa_mmc_regs *regs;
> +};
> +
> +/* Wait for bit to be set */
> +static int pxa_mmc_wait(struct mmc *mmc, uint32_t mask)
> +{
> +	struct pxa_mmc_priv *priv = (struct pxa_mmc_priv *)mmc->priv;
> +	struct pxa_mmc_regs *regs = priv->regs;
> +	unsigned int timeout = PXA_MMC_TIMEOUT;
> +
> +	/* Wait for bit to be set */
> +	while (--timeout) {
> +		if (readl(&regs->stat) & mask)
> +			break;
> +		udelay(10);
> +	}
> +
> +	if (!timeout)
> +		return -ETIMEDOUT;
> +
> +	return 0;
> +}
> +
> +static int pxa_mmc_stop_clock(struct mmc *mmc)
> +{
> +	struct pxa_mmc_priv *priv = (struct pxa_mmc_priv *)mmc->priv;
> +	struct pxa_mmc_regs *regs = priv->regs;
> +	unsigned int timeout = PXA_MMC_TIMEOUT;
> +
> +	/* If the clock aren't running, exit */
> +	if (!(readl(&regs->stat) & MMC_STAT_CLK_EN))
> +		return 0;
> +
> +	/* Tell the controller to turn off the clock */
> +	writel(MMC_STRPCL_STOP_CLK, &regs->strpcl);
> +
> +	/* Wait until the clock are off */
> +	while (--timeout) {
> +		if (!(readl(&regs->stat) & MMC_STAT_CLK_EN))
> +			break;
> +		udelay(10);
> +	}
> +
> +	/* The clock refused to stop, scream and die a painful death */
> +	if (!timeout)
> +		return -ETIMEDOUT;
> +
> +	/* The clock stopped correctly */
> +	return 0;
> +}
> +
> +static int pxa_mmc_start_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
> +				uint32_t cmdat)
> +{
> +	struct pxa_mmc_priv *priv = (struct pxa_mmc_priv *)mmc->priv;
> +	struct pxa_mmc_regs *regs = priv->regs;
> +	int ret;
> +
> +	/* The card can send a "busy" response */
> +	if (cmd->flags & MMC_RSP_BUSY)
> +		cmdat |= MMC_CMDAT_BUSY;
> +
> +	/* Inform the controller about response type */
> +	switch (cmd->resp_type) {
> +	case MMC_RSP_R1:
> +	case MMC_RSP_R1b:
> +		cmdat |= MMC_CMDAT_R1;
> +		break;
> +	case MMC_RSP_R2:
> +		cmdat |= MMC_CMDAT_R2;
> +		break;
> +	case MMC_RSP_R3:
> +		cmdat |= MMC_CMDAT_R3;
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	/* Load command and it's arguments into the controller */
> +	writel(cmd->cmdidx, &regs->cmd);
> +	writel(cmd->cmdarg >> 16, &regs->argh);
> +	writel(cmd->cmdarg & 0xffff, &regs->argl);
> +	writel(cmdat, &regs->cmdat);
> +
> +	/* Start the controller clock and wait until they are started */
> +	writel(MMC_STRPCL_START_CLK, &regs->strpcl);
> +
> +	ret = pxa_mmc_wait(mmc, MMC_STAT_CLK_EN);
> +	if (ret)
> +		return ret;
> +
> +	/* Correct and happy end */
> +	return 0;
> +}
> +
> +static int pxa_mmc_cmd_done(struct mmc *mmc, struct mmc_cmd *cmd)
> +{
> +	struct pxa_mmc_priv *priv = (struct pxa_mmc_priv *)mmc->priv;
> +	struct pxa_mmc_regs *regs = priv->regs;
> +	uint32_t a, b, c;
> +	int i;
> +	int stat;
> +
> +	/* Read the controller status */
> +	stat = readl(&regs->stat);
> +
> +	/*
> +	 * Linux says:
> +	 * Did I mention this is Sick.  We always need to
> +	 * discard the upper 8 bits of the first 16-bit word.
> +	 */
> +	a = readl(&regs->res) & 0xffff;
> +	for (i = 0; i < 4; i++) {
> +		b = readl(&regs->res) & 0xffff;
> +		c = readl(&regs->res) & 0xffff;
> +		cmd->response[i] = (a << 24) | (b << 8) | (c >> 8);
> +		a = c;
> +	}
> +
> +	/* The command response didn't arrive */
> +	if (stat & MMC_STAT_TIME_OUT_RESPONSE)
> +		return -ETIMEDOUT;
> +	else if (stat & MMC_STAT_RES_CRC_ERROR && cmd->flags & MMC_RSP_CRC) {
> +#ifdef	PXAMMC_CRC_SKIP
> +		if (cmd->flags & MMC_RSP_136 && cmd->response[0] & (1 << 31))
> +			printf("Ignoring CRC, this may be dangerous!\n");
> +		else
> +#endif
> +		return -EILSEQ;
> +	}
> +
> +	/* The command response was successfully read */
> +	return 0;
> +}
> +
> +static int pxa_mmc_do_read_xfer(struct mmc *mmc, struct mmc_data *data)
> +{
> +	struct pxa_mmc_priv *priv = (struct pxa_mmc_priv *)mmc->priv;
> +	struct pxa_mmc_regs *regs = priv->regs;
> +	uint32_t len;
> +	uint32_t *buf = (uint32_t *)data->dest;
> +	int size;
> +	int ret;
> +
> +	len = data->blocks * data->blocksize;
> +
> +	while (len) {
> +		/* The controller has data ready */
> +		if (readl(&regs->i_reg) & MMC_I_REG_RXFIFO_RD_REQ) {
> +			size = min(len, PXAMMC_FIFO_SIZE);
> +			len -= size;
> +			size /= 4;
> +
> +			/* Read data into the buffer */
> +			while (size--)
> +				*buf++ = readl(&regs->rxfifo);
> +
> +		}
> +
> +		if (readl(&regs->stat) & MMC_STAT_ERRORS)
> +			return -EIO;
> +	}
> +
> +	/* Wait for the transmission-done interrupt */
> +	ret = pxa_mmc_wait(mmc, MMC_STAT_DATA_TRAN_DONE);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int pxa_mmc_do_write_xfer(struct mmc *mmc, struct mmc_data *data)
> +{
> +	struct pxa_mmc_priv *priv = (struct pxa_mmc_priv *)mmc->priv;
> +	struct pxa_mmc_regs *regs = priv->regs;
> +	uint32_t len;
> +	uint32_t *buf = (uint32_t *)data->src;
> +	int size;
> +	int ret;
> +
> +	len = data->blocks * data->blocksize;
> +
> +	while (len) {
> +		/* The controller is ready to receive data */
> +		if (readl(&regs->i_reg) & MMC_I_REG_TXFIFO_WR_REQ) {
> +			size = min(len, PXAMMC_FIFO_SIZE);
> +			len -= size;
> +			size /= 4;
> +
> +			while (size--)
> +				writel(*buf++, &regs->txfifo);
> +
> +			if (min(len, PXAMMC_FIFO_SIZE) < 32)
> +				writel(MMC_PRTBUF_BUF_PART_FULL, &regs->prtbuf);
> +		}
> +
> +		if (readl(&regs->stat) & MMC_STAT_ERRORS)
> +			return -EIO;
> +	}
> +
> +	/* Wait for the transmission-done interrupt */
> +	ret = pxa_mmc_wait(mmc, MMC_STAT_DATA_TRAN_DONE);
> +	if (ret)
> +		return ret;
> +
> +	/* Wait until the data are really written to the card */
> +	ret = pxa_mmc_wait(mmc, MMC_STAT_PRG_DONE);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int pxa_mmc_request(struct mmc *mmc, struct mmc_cmd *cmd,
> +				struct mmc_data *data)
> +{
> +	struct pxa_mmc_priv *priv = (struct pxa_mmc_priv *)mmc->priv;
> +	struct pxa_mmc_regs *regs = priv->regs;
> +	uint32_t cmdat = 0;
> +	int ret;
> +
> +	/* Stop the controller */
> +	ret = pxa_mmc_stop_clock(mmc);
> +	if (ret)
> +		return ret;
> +
> +	/* If we're doing data transfer, configure the controller accordingly */
> +	if (data) {
> +		writel(data->blocks, &regs->nob);
> +		writel(data->blocksize, &regs->blklen);
> +		/* This delay can be optimized, but stick with max value */
> +		writel(0xffff, &regs->rdto);
> +		cmdat |= MMC_CMDAT_DATA_EN;
> +		if (data->flags & MMC_DATA_WRITE)
> +			cmdat |= MMC_CMDAT_WRITE;
> +	}
> +
> +	/* Run in 4bit mode if the card can do it */
> +	if (mmc->bus_width == 4)
> +		cmdat |= MMC_CMDAT_SD_4DAT;
> +
> +	/* Execute the command */
> +	ret = pxa_mmc_start_cmd(mmc, cmd, cmdat);
> +	if (ret)
> +		return ret;
> +
> +	/* Wait until the command completes */
> +	ret = pxa_mmc_wait(mmc, MMC_STAT_END_CMD_RES);
> +	if (ret)
> +		return ret;
> +
> +	/* Read back the result */
> +	ret = pxa_mmc_cmd_done(mmc, cmd);
> +	if (ret)
> +		return ret;
> +
> +	/* In case there was a data transfer scheduled, do it */
> +	if (data) {
> +		if (data->flags & MMC_DATA_WRITE)
> +			pxa_mmc_do_write_xfer(mmc, data);
> +		else
> +			pxa_mmc_do_read_xfer(mmc, data);
> +	}
> +
> +	return 0;
> +}
> +
> +static void pxa_mmc_set_ios(struct mmc *mmc)
> +{
> +	struct pxa_mmc_priv *priv = (struct pxa_mmc_priv *)mmc->priv;
> +	struct pxa_mmc_regs *regs = priv->regs;
> +	uint32_t tmp;
> +	uint32_t pxa_mmc_clock;
> +
> +	if (!mmc->clock) {
> +		pxa_mmc_stop_clock(mmc);
> +		return;
> +	}
> +
> +	/* PXA3xx can do 26MHz with special settings. */
> +	if (mmc->clock == 26000000) {
> +		writel(0x7, &regs->clkrt);
> +		return;
> +	}
> +
> +	/* Set clock to the card the usual way. */
> +	pxa_mmc_clock = 0;
> +	tmp = mmc->f_max / mmc->clock;
> +	tmp += tmp % 2;
> +
> +	while (tmp > 1) {
> +		pxa_mmc_clock++;
> +		tmp >>= 1;
> +	}
> +
> +	writel(pxa_mmc_clock, &regs->clkrt);
> +}
> +
> +static int pxa_mmc_init(struct mmc *mmc)
> +{
> +	struct pxa_mmc_priv *priv = (struct pxa_mmc_priv *)mmc->priv;
> +	struct pxa_mmc_regs *regs = priv->regs;
> +
> +	/* Make sure the clock are stopped */
> +	pxa_mmc_stop_clock(mmc);
> +
> +	/* Turn off SPI mode */
> +	writel(0, &regs->spi);
> +
> +	/* Set up maximum timeout to wait for command response */
> +	writel(MMC_RES_TO_MAX_MASK, &regs->resto);
> +
> +	/* Mask all interrupts */
> +	writel(~(MMC_I_MASK_TXFIFO_WR_REQ | MMC_I_MASK_RXFIFO_RD_REQ),
> +		&regs->i_mask);
> +	return 0;
> +}
> +
> +int pxa_mmc_register(int card_index)
> +{
> +	struct mmc *mmc;
> +	struct pxa_mmc_priv *priv;
> +	uint32_t reg;
> +	int ret = -ENOMEM;
> +
> +	mmc = malloc(sizeof(struct mmc));
> +	if (!mmc)
> +		goto err0;
> +
> +	priv = malloc(sizeof(struct pxa_mmc_priv));
> +	if (!priv)
> +		goto err1;
> +
> +	switch (card_index) {
> +	case 0:
> +		priv->regs = (struct pxa_mmc_regs *)MMC0_BASE;
> +		break;
> +	case 1:
> +		priv->regs = (struct pxa_mmc_regs *)MMC1_BASE;
> +		break;
> +	default:
> +		printf("PXA MMC: Invalid MMC controller ID (card_index = %d)\n",
> +			card_index);
> +		goto err2;
> +	}
> +
> +	mmc->priv = priv;
> +
> +	sprintf(mmc->name, "PXA MMC");
> +	mmc->send_cmd	= pxa_mmc_request;
> +	mmc->set_ios	= pxa_mmc_set_ios;
> +	mmc->init	= pxa_mmc_init;
> +
> +	mmc->voltages	= MMC_VDD_32_33 | MMC_VDD_33_34;
> +	mmc->f_max	= PXAMMC_MAX_SPEED;
> +	mmc->f_min	= PXAMMC_MIN_SPEED;
> +	mmc->host_caps	= PXAMMC_HOST_CAPS;
> +
> +	mmc->b_max = 0;
> +
> +#ifndef	CONFIG_CPU_MONAHANS	/* PXA2xx */
> +	reg = readl(CKEN);
> +	reg |= CKEN12_MMC;
> +	writel(reg, CKEN);
> +#else				/* PXA3xx */
> +	reg = readl(CKENA);
> +	reg |= CKENA_12_MMC0 | CKENA_13_MMC1;
> +	writel(reg, CKENA);
> +#endif
> +
> +	mmc_register(mmc);
> +
> +	return 0;
> +
> +err2:
> +	free(priv);
> +err1:
> +	free(mmc);
> +err0:
> +	return ret;
> +}

-- 
Regards,
Igor.

  parent reply	other threads:[~2011-11-01 12:08 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-08-28 22:02 [U-Boot] [PATCH 1/2] PXA: Add MMC driver using the generic MMC framework Marek Vasut
2011-08-28 22:02 ` [U-Boot] [PATCH 2/2] PXA: vpac270: Enable the new generic MMC driver Marek Vasut
2011-10-31 18:23 ` [U-Boot] [PATCH 1/2] PXA: Add MMC driver using the generic MMC framework Marek Vasut
2011-11-01 12:08 ` Igor Grinberg [this message]
2011-11-01 12:20   ` Marek Vasut
2011-11-02  8:41     ` Igor Grinberg
2011-11-01 22:58 ` [U-Boot] [PATCH 1/2 V2] " Marek Vasut
2011-11-02  8:48   ` Igor Grinberg
2011-11-02 10:28     ` Marek Vasut
2011-11-02 10:29   ` [U-Boot] [PATCH 1/2 V3] " Marek Vasut

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4EAFE137.80404@compulab.co.il \
    --to=grinberg@compulab.co.il \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.