From b660df3c9031ba2efded2d083c34f2ea5ff978ff Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 26 Aug 2012 15:19:06 +0000 Subject: COMMON: Implement common bounce buffer Implement common bounce buffer to be used on a less capable hardware. That includes hardware that can not do DMA from any address or such. Signed-off-by: Marek Vasut Cc: Fabio Estevam Cc: Andy Fleming Signed-off-by: Andy Fleming diff --git a/common/Makefile b/common/Makefile index fdfead7..2e3b223 100644 --- a/common/Makefile +++ b/common/Makefile @@ -204,6 +204,7 @@ COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_common.o COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_nowhere.o COBJS-$(CONFIG_SPL_NET_SUPPORT) += miiphyutil.o endif +COBJS-$(CONFIG_BOUNCE_BUFFER) += bouncebuf.o COBJS-y += console.o COBJS-y += dlmalloc.o COBJS-y += image.o diff --git a/common/bouncebuf.c b/common/bouncebuf.c new file mode 100644 index 0000000..4f827f8 --- /dev/null +++ b/common/bouncebuf.c @@ -0,0 +1,92 @@ +/* + * Generic bounce buffer implementation + * + * Copyright (C) 2012 Marek Vasut + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 +#include +#include +#include + +static int addr_aligned(void *data, size_t len) +{ + const ulong align_mask = ARCH_DMA_MINALIGN - 1; + + /* Check if start is aligned */ + if ((ulong)data & align_mask) { + debug("Unaligned start address %p\n", data); + return 0; + } + + data += len; + + /* Check if end is aligned */ + if ((ulong)data & align_mask) { + debug("Unaligned end address %p\n", data); + return 0; + } + + /* Aligned */ + return 1; +} + +int bounce_buffer_start(void **data, size_t len, void **backup, uint8_t flags) +{ + void *tmp; + size_t alen; + + if (addr_aligned(*data, len)) { + *backup = NULL; + return 0; + } + + alen = roundup(len, ARCH_DMA_MINALIGN); + tmp = memalign(ARCH_DMA_MINALIGN, alen); + + if (!tmp) + return -ENOMEM; + + if (flags & GEN_BB_READ) + memcpy(tmp, *data, len); + + *backup = *data; + *data = tmp; + + return 0; +} + +int bounce_buffer_stop(void **data, size_t len, void **backup, uint8_t flags) +{ + void *tmp = *data; + + /* The buffer was already aligned, since "backup" is NULL. */ + if (!*backup) + return 0; + + if (flags & GEN_BB_WRITE) + memcpy(*backup, *data, len); + + *data = *backup; + free(tmp); + + return 0; +} diff --git a/include/bouncebuf.h b/include/bouncebuf.h new file mode 100644 index 0000000..31021c5 --- /dev/null +++ b/include/bouncebuf.h @@ -0,0 +1,87 @@ +/* + * Generic bounce buffer implementation + * + * Copyright (C) 2012 Marek Vasut + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 __INCLUDE_BOUNCEBUF_H__ +#define __INCLUDE_BOUNCEBUF_H__ + +/* + * GEN_BB_READ -- Data are read from the buffer eg. by DMA hardware. + * The source buffer is copied into the bounce buffer (if unaligned, otherwise + * the source buffer is used directly) upon start() call, then the operation + * requiring the aligned transfer happens, then the bounce buffer is lost upon + * stop() call. + */ +#define GEN_BB_READ (1 << 0) +/* + * GEN_BB_WRITE -- Data are written into the buffer eg. by DMA hardware. + * The source buffer starts in an undefined state upon start() call, then the + * operation requiring the aligned transfer happens, then the bounce buffer is + * copied into the destination buffer (if unaligned, otherwise destination + * buffer is used directly) upon stop() call. + */ +#define GEN_BB_WRITE (1 << 1) +/* + * GEN_BB_RW -- Data are read and written into the buffer eg. by DMA hardware. + * The source buffer is copied into the bounce buffer (if unaligned, otherwise + * the source buffer is used directly) upon start() call, then the operation + * requiring the aligned transfer happens, then the bounce buffer is copied + * into the destination buffer (if unaligned, otherwise destination buffer is + * used directly) upon stop() call. + */ +#define GEN_BB_RW (GEN_BB_READ | GEN_BB_WRITE) + +#ifdef CONFIG_BOUNCE_BUFFER +/** + * bounce_buffer_start() -- Start the bounce buffer session + * data: pointer to buffer to be aligned + * len: length of the buffer + * backup: pointer to backup buffer (the original value is stored here if + * needed + * flags: flags describing the transaction, see above. + */ +int bounce_buffer_start(void **data, size_t len, void **backup, uint8_t flags); +/** + * bounce_buffer_stop() -- Finish the bounce buffer session + * data: pointer to buffer that was aligned + * len: length of the buffer + * backup: pointer to backup buffer (the original value is stored here if + * needed + * flags: flags describing the transaction, see above. + */ +int bounce_buffer_stop(void **data, size_t len, void **backup, uint8_t flags); +#else +static inline int bounce_buffer_start(void **data, size_t len, void **backup, + uint8_t flags) +{ + return 0; +} + +static inline int bounce_buffer_stop(void **data, size_t len, void **backup, + uint8_t flags) +{ + return 0; +} +#endif + +#endif -- cgit v0.10.2 From 4e6d81d1a4f042760287b31a6dc121b4ad754b7c Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 26 Aug 2012 15:19:07 +0000 Subject: MMC: MXS: Convert MXS MMC driver to generic bounce buffer Implement necessary code to use the generic bounce buffer routines inside this driver. This replaces the MMC bounce buffer, which is to be removed. Signed-off-by: Marek Vasut Cc: Fabio Estevam Cc: Andy Fleming Signed-off-by: Andy Fleming diff --git a/drivers/mmc/mxsmmc.c b/drivers/mmc/mxsmmc.c index c80b41b..109acbf 100644 --- a/drivers/mmc/mxsmmc.c +++ b/drivers/mmc/mxsmmc.c @@ -42,6 +42,7 @@ #include #include #include +#include struct mxsmmc_priv { int id; @@ -95,28 +96,33 @@ static int mxsmmc_send_cmd_pio(struct mxsmmc_priv *priv, struct mmc_data *data) static int mxsmmc_send_cmd_dma(struct mxsmmc_priv *priv, struct mmc_data *data) { uint32_t data_count = data->blocksize * data->blocks; - uint32_t cache_data_count; + uint32_t cache_data_count = roundup(data_count, ARCH_DMA_MINALIGN); int dmach; struct mxs_dma_desc *desc = priv->desc; + void *addr, *backup; + uint8_t flags; memset(desc, 0, sizeof(struct mxs_dma_desc)); desc->address = (dma_addr_t)desc; - if (data_count % ARCH_DMA_MINALIGN) - cache_data_count = roundup(data_count, ARCH_DMA_MINALIGN); - else - cache_data_count = data_count; - if (data->flags & MMC_DATA_READ) { priv->desc->cmd.data = MXS_DMA_DESC_COMMAND_DMA_WRITE; - priv->desc->cmd.address = (dma_addr_t)data->dest; + addr = data->dest; + flags = GEN_BB_WRITE; } else { priv->desc->cmd.data = MXS_DMA_DESC_COMMAND_DMA_READ; - priv->desc->cmd.address = (dma_addr_t)data->src; + addr = (void *)data->src; + flags = GEN_BB_READ; + } + + bounce_buffer_start(&addr, data_count, &backup, flags); + + priv->desc->cmd.address = (dma_addr_t)addr; + if (data->flags & MMC_DATA_WRITE) { /* Flush data to DRAM so DMA can pick them up */ - flush_dcache_range((uint32_t)priv->desc->cmd.address, - (uint32_t)(priv->desc->cmd.address + cache_data_count)); + flush_dcache_range((uint32_t)addr, + (uint32_t)(addr) + cache_data_count); } /* Invalidate the area, so no writeback into the RAM races with DMA */ @@ -128,15 +134,19 @@ static int mxsmmc_send_cmd_dma(struct mxsmmc_priv *priv, struct mmc_data *data) dmach = MXS_DMA_CHANNEL_AHB_APBH_SSP0 + priv->id; mxs_dma_desc_append(dmach, priv->desc); - if (mxs_dma_go(dmach)) + if (mxs_dma_go(dmach)) { + bounce_buffer_stop(&addr, data_count, &backup, flags); return COMM_ERR; + } /* The data arrived into DRAM, invalidate cache over them */ if (data->flags & MMC_DATA_READ) { - invalidate_dcache_range((uint32_t)priv->desc->cmd.address, - (uint32_t)(priv->desc->cmd.address + cache_data_count)); + invalidate_dcache_range((uint32_t)addr, + (uint32_t)(addr) + cache_data_count); } + bounce_buffer_stop(&addr, data_count, &backup, flags); + return 0; } -- cgit v0.10.2 From 6dc71c8d2a3183a37624ef19a0532e7f827d868f Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 26 Aug 2012 15:19:08 +0000 Subject: MMC: MXS: Toggle the generic bounce buffer on the boards Flip the boards to use the generic bounce buffer instead of the MMC one. Signed-off-by: Marek Vasut Cc: Andy Fleming Cc: Fabio Estevam Signed-off-by: Andy Fleming diff --git a/include/configs/apx4devkit.h b/include/configs/apx4devkit.h index af0b714..6764b47 100644 --- a/include/configs/apx4devkit.h +++ b/include/configs/apx4devkit.h @@ -132,7 +132,7 @@ #ifdef CONFIG_CMD_MMC #define CONFIG_MMC #define CONFIG_GENERIC_MMC -#define CONFIG_MMC_BOUNCE_BUFFER +#define CONFIG_BOUNCE_BUFFER #define CONFIG_MXS_MMC #endif diff --git a/include/configs/m28evk.h b/include/configs/m28evk.h index bdbb820..b49ec8c 100644 --- a/include/configs/m28evk.h +++ b/include/configs/m28evk.h @@ -135,7 +135,7 @@ */ #ifdef CONFIG_CMD_MMC #define CONFIG_MMC -#define CONFIG_MMC_BOUNCE_BUFFER +#define CONFIG_BOUNCE_BUFFER #define CONFIG_GENERIC_MMC #define CONFIG_MXS_MMC #endif diff --git a/include/configs/mx28evk.h b/include/configs/mx28evk.h index 7cdbec6..1443833 100644 --- a/include/configs/mx28evk.h +++ b/include/configs/mx28evk.h @@ -142,7 +142,7 @@ #ifdef CONFIG_CMD_MMC #define CONFIG_MMC #define CONFIG_GENERIC_MMC -#define CONFIG_MMC_BOUNCE_BUFFER +#define CONFIG_BOUNCE_BUFFER #define CONFIG_MXS_MMC #endif -- cgit v0.10.2 From 49a627f8a1646db883a72c7df3bcc4079138076a Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 26 Aug 2012 15:19:09 +0000 Subject: MMC: Remove the MMC bounce buffer Signed-off-by: Marek Vasut Cc: Andy Fleming Cc: Fabio Estevam Signed-off-by: Andy Fleming diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index a60cfe1..5fbf956 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -47,93 +47,6 @@ int __board_mmc_getcd(struct mmc *mmc) { int board_mmc_getcd(struct mmc *mmc)__attribute__((weak, alias("__board_mmc_getcd"))); -#ifdef CONFIG_MMC_BOUNCE_BUFFER -static int mmc_bounce_need_bounce(struct mmc_data *orig) -{ - ulong addr, len; - - if (orig->flags & MMC_DATA_READ) - addr = (ulong)orig->dest; - else - addr = (ulong)orig->src; - - if (addr % ARCH_DMA_MINALIGN) { - debug("MMC: Unaligned data destination address %08lx!\n", addr); - return 1; - } - - len = (ulong)(orig->blocksize * orig->blocks); - if (len % ARCH_DMA_MINALIGN) { - debug("MMC: Unaligned data destination length %08lx!\n", len); - return 1; - } - - return 0; -} - -static int mmc_bounce_buffer_start(struct mmc_data *backup, - struct mmc_data *orig) -{ - ulong origlen, len; - void *buffer; - - if (!orig) - return 0; - - if (!mmc_bounce_need_bounce(orig)) - return 0; - - memcpy(backup, orig, sizeof(struct mmc_data)); - - origlen = orig->blocksize * orig->blocks; - len = roundup(origlen, ARCH_DMA_MINALIGN); - buffer = memalign(ARCH_DMA_MINALIGN, len); - if (!buffer) { - puts("MMC: Error allocating MMC bounce buffer!\n"); - return 1; - } - - if (orig->flags & MMC_DATA_READ) { - orig->dest = buffer; - } else { - memcpy(buffer, orig->src, origlen); - orig->src = buffer; - } - - return 0; -} - -static void mmc_bounce_buffer_stop(struct mmc_data *backup, - struct mmc_data *orig) -{ - ulong len; - - if (!orig) - return; - - if (!mmc_bounce_need_bounce(backup)) - return; - - if (backup->flags & MMC_DATA_READ) { - len = backup->blocksize * backup->blocks; - memcpy(backup->dest, orig->dest, len); - free(orig->dest); - orig->dest = backup->dest; - } else { - free((void *)orig->src); - orig->src = backup->src; - } - - return; - -} -#else -static inline int mmc_bounce_buffer_start(struct mmc_data *backup, - struct mmc_data *orig) { return 0; } -static inline void mmc_bounce_buffer_stop(struct mmc_data *backup, - struct mmc_data *orig) { } -#endif - int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) { struct mmc_data backup; @@ -141,10 +54,6 @@ int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) memset(&backup, 0, sizeof(backup)); - ret = mmc_bounce_buffer_start(&backup, data); - if (ret) - return ret; - #ifdef CONFIG_MMC_TRACE int i; u8 *ptr; @@ -196,7 +105,6 @@ int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) #else ret = mmc->send_cmd(mmc, cmd, data); #endif - mmc_bounce_buffer_stop(&backup, data); return ret; } -- cgit v0.10.2 From d6b2e5085c8fe3e70f9fffd450e54efae99cbf41 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Tue, 11 Sep 2012 08:59:51 +0000 Subject: mmc: Fix mmc_spi error on cmd->flags field The recent removal of the cmd->flags field caused error in the debuging code of mmc_spi. Fix this: mmc_spi.c: In function 'mmc_spi_request': mmc_spi.c:179:2: error: 'struct mmc_cmd' has no member named 'flags' Signed-off-by: Marek Vasut Cc: Andy Fleming Signed-off-by: Andy Fleming diff --git a/drivers/mmc/mmc_spi.c b/drivers/mmc/mmc_spi.c index de43a85..11ba532 100644 --- a/drivers/mmc/mmc_spi.c +++ b/drivers/mmc/mmc_spi.c @@ -176,8 +176,8 @@ static int mmc_spi_request(struct mmc *mmc, struct mmc_cmd *cmd, u8 r1; int i; int ret = 0; - debug("%s:cmd%d %x %x %x\n", __func__, - cmd->cmdidx, cmd->resp_type, cmd->cmdarg, cmd->flags); + debug("%s:cmd%d %x %x\n", __func__, + cmd->cmdidx, cmd->resp_type, cmd->cmdarg); spi_claim_bus(spi); spi_cs_activate(spi); r1 = mmc_spi_sendcmd(mmc, cmd->cmdidx, cmd->cmdarg); -- cgit v0.10.2 From 5d48e4224791611498456908fc23a845cc5b4ed7 Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Thu, 20 Sep 2012 20:31:54 +0000 Subject: mmc: sdhci: increase the timeout value for data transfer Timeout value is tunable. When run read/write operation, sometime returned the timeout error. Because the timeout value is too short. So increased the enough timeout value. (This timeout value is used to prevent the infinite loop.) Signed-off-by: Jaehoon Chung Signed-off-by: Kyungmin Park Signed-off-by: Andy Fleming diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 2e3c408..9329874 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -83,7 +83,7 @@ static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data, { unsigned int stat, rdy, mask, timeout, block = 0; - timeout = 10000; + timeout = 1000000; rdy = SDHCI_INT_SPACE_AVAIL | SDHCI_INT_DATA_AVAIL; mask = SDHCI_DATA_AVAILABLE | SDHCI_SPACE_AVAILABLE; do { -- cgit v0.10.2 From 804c7f422169212e92530e1ddaf74bf1ca9ebfa1 Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Thu, 20 Sep 2012 20:31:55 +0000 Subject: mmc: sdhci: add the DMA select for SDMA In host-control register, DMA select bit field is present. BUt in sdhci.c, didn't select for DMA. if set CONFIG_MMC_SDMA, we need to set SDMA-select bit. Signed-off-by: Jaehoon Chung Signed-off-by: Kyungmin Park Signed-off-by: Andy Fleming diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 9329874..15b4686 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -82,6 +82,13 @@ static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data, unsigned int start_addr) { unsigned int stat, rdy, mask, timeout, block = 0; +#ifdef CONFIG_MMC_SDMA + unsigned char ctrl; + ctrl = sdhci_readl(host, SDHCI_HOST_CONTROL); + ctrl &= ~SDHCI_CTRL_DMA_MASK; + ctrl |= SDHCI_CTRL_SDMA; + sdhci_writel(host, ctrl, SDHCI_HOST_CONTROL); +#endif timeout = 1000000; rdy = SDHCI_INT_SPACE_AVAIL | SDHCI_INT_DATA_AVAIL; -- cgit v0.10.2 From 13243f2eafc4292917178051fe1bb5aab2774dca Mon Sep 17 00:00:00 2001 From: Tushar Behera Date: Thu, 20 Sep 2012 20:31:57 +0000 Subject: mmc: sdhci: Add a quirk to add delay during completion of sdhci_send_cmd MMC host controller requires a delay between every sdhci_send_cmd() execution. In s5p_mmc driver (s5p_sdhci replaces this driver), a delay of 1000us was provided after every mmc_send_cmd() call. Adding a quirk in current sdhci driver to replicate the behaviour. Without this delay, MMC initialization on Origen board fails with following error messages. Timeout for status update! mmc fail to send stop cmd Signed-off-by: Tushar Behera Signed-off-by: Jaehoon Chung Signed-off-by: Andy Fleming diff --git a/drivers/mmc/s5p_sdhci.c b/drivers/mmc/s5p_sdhci.c index b978236..dc49d37 100644 --- a/drivers/mmc/s5p_sdhci.c +++ b/drivers/mmc/s5p_sdhci.c @@ -83,7 +83,8 @@ int s5p_sdhci_init(u32 regbase, int index, int bus_width) host->ioaddr = (void *)regbase; host->quirks = SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_BROKEN_VOLTAGE | - SDHCI_QUIRK_BROKEN_R1B | SDHCI_QUIRK_32BIT_DMA_ADDR; + SDHCI_QUIRK_BROKEN_R1B | SDHCI_QUIRK_32BIT_DMA_ADDR | + SDHCI_QUIRK_WAIT_SEND_CMD; host->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; host->version = sdhci_readw(host, SDHCI_HOST_VERSION); diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 15b4686..7845f87 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -240,6 +240,9 @@ int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd, if (!ret && data) ret = sdhci_transfer_data(host, data, start_addr); + if (host->quirks & SDHCI_QUIRK_WAIT_SEND_CMD) + udelay(1000); + stat = sdhci_readl(host, SDHCI_INT_STATUS); sdhci_writel(host, SDHCI_INT_ALL_MASK, SDHCI_INT_STATUS); if (!ret) { diff --git a/include/sdhci.h b/include/sdhci.h index c0345ed..c44793d 100644 --- a/include/sdhci.h +++ b/include/sdhci.h @@ -224,6 +224,7 @@ #define SDHCI_QUIRK_NO_HISPD_BIT (1 << 3) #define SDHCI_QUIRK_BROKEN_VOLTAGE (1 << 4) #define SDHCI_QUIRK_NO_CD (1 << 5) +#define SDHCI_QUIRK_WAIT_SEND_CMD (1 << 6) /* to make gcc happy */ struct sdhci_host; -- cgit v0.10.2 From 831f849f79f2c9fcaa6f85f4158296d2dbc3916c Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 30 Sep 2012 10:09:49 +0000 Subject: mmc: pxa: Flip over the remaining boards to pxa_mmc_generic Some of the boards still used the old PXA_MMC driver instead of the new generic one. Use the new one instead so the old can be removed and the generic MMC framework can be properly used. Signed-off-by: Marek Vasut Cc: Andy Fleming Signed-off-by: Andy Fleming diff --git a/board/lubbock/lubbock.c b/board/lubbock/lubbock.c index 3527b38..ef2cc24 100644 --- a/board/lubbock/lubbock.c +++ b/board/lubbock/lubbock.c @@ -29,6 +29,7 @@ #include #include #include +#include #include DECLARE_GLOBAL_DATA_PTR; @@ -56,6 +57,14 @@ int board_init (void) return 0; } +#ifdef CONFIG_CMD_MMC +int board_mmc_init(bd_t *bis) +{ + pxa_mmc_register(0); + return 0; +} +#endif + int board_late_init(void) { setenv("stdout", "serial"); diff --git a/board/palmtc/palmtc.c b/board/palmtc/palmtc.c index b23eec8..590ca41 100644 --- a/board/palmtc/palmtc.c +++ b/board/palmtc/palmtc.c @@ -24,6 +24,7 @@ #include #include #include +#include DECLARE_GLOBAL_DATA_PTR; @@ -51,6 +52,14 @@ int board_init(void) return 0; } +#ifdef CONFIG_CMD_MMC +int board_mmc_init(bd_t *bis) +{ + pxa_mmc_register(0); + return 0; +} +#endif + int dram_init(void) { pxa2xx_dram_init(); diff --git a/board/pxa255_idp/pxa_idp.c b/board/pxa255_idp/pxa_idp.c index 877e8d9..9931efd 100644 --- a/board/pxa255_idp/pxa_idp.c +++ b/board/pxa255_idp/pxa_idp.c @@ -35,6 +35,7 @@ #include #include #include +#include DECLARE_GLOBAL_DATA_PTR; @@ -77,6 +78,14 @@ int board_init (void) return 0; } +#ifdef CONFIG_CMD_MMC +int board_mmc_init(bd_t *bis) +{ + pxa_mmc_register(0); + return 0; +} +#endif + int board_late_init(void) { setenv("stdout", "serial"); diff --git a/board/trizepsiv/conxs.c b/board/trizepsiv/conxs.c index 871e052..c3dee84 100644 --- a/board/trizepsiv/conxs.c +++ b/board/trizepsiv/conxs.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -152,3 +153,11 @@ int board_eth_init(bd_t *bis) return dm9000_initialize(bis); } #endif + +#ifdef CONFIG_CMD_MMC +int board_mmc_init(bd_t *bis) +{ + pxa_mmc_register(0); + return 0; +} +#endif diff --git a/include/configs/lubbock.h b/include/configs/lubbock.h index ed64960..5886a15 100644 --- a/include/configs/lubbock.h +++ b/include/configs/lubbock.h @@ -130,7 +130,8 @@ #define CONFIG_SYS_CPUSPEED 0x161 /* set core clock to 400/200/100 MHz */ #ifdef CONFIG_MMC -#define CONFIG_PXA_MMC +#define CONFIG_GENERIC_MMC +#define CONFIG_PXA_MMC_GENERIC #define CONFIG_CMD_MMC #define CONFIG_SYS_MMC_BASE 0xF0000000 #endif diff --git a/include/configs/palmtc.h b/include/configs/palmtc.h index 6e8d8e9..9c948c5 100644 --- a/include/configs/palmtc.h +++ b/include/configs/palmtc.h @@ -77,7 +77,8 @@ */ #ifdef CONFIG_CMD_MMC #define CONFIG_MMC -#define CONFIG_PXA_MMC +#define CONFIG_GENERIC_MMC +#define CONFIG_PXA_MMC_GENERIC #define CONFIG_SYS_MMC_BASE 0xF0000000 #define CONFIG_CMD_FAT #define CONFIG_CMD_EXT2 diff --git a/include/configs/pxa255_idp.h b/include/configs/pxa255_idp.h index 24c5363..5a15af6 100644 --- a/include/configs/pxa255_idp.h +++ b/include/configs/pxa255_idp.h @@ -245,7 +245,8 @@ #define RTC 1 /* enable 32KHz osc */ #ifdef CONFIG_MMC -#define CONFIG_PXA_MMC +#define CONFIG_GENERIC_MMC +#define CONFIG_PXA_MMC_GENERIC #define CONFIG_CMD_MMC #define CONFIG_SYS_MMC_BASE 0xF0000000 #endif diff --git a/include/configs/trizepsiv.h b/include/configs/trizepsiv.h index bc69c1e..c1bfe31 100644 --- a/include/configs/trizepsiv.h +++ b/include/configs/trizepsiv.h @@ -170,7 +170,8 @@ #define CONFIG_SYS_CPUSPEED 0x207 /* need to look more closely, I think this is Turbo = 2x, L=91Mhz */ #ifdef CONFIG_MMC -#define CONFIG_PXA_MMC +#define CONFIG_GENERIC_MMC +#define CONFIG_PXA_MMC_GENERIC #define CONFIG_CMD_MMC #define CONFIG_SYS_MMC_BASE 0xF0000000 #endif -- cgit v0.10.2 From 48cf9dc63c9353febf8b2c27ff20f0d6dc56d6b6 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 30 Sep 2012 10:09:50 +0000 Subject: mmc: pxa: Remove the old non-generic PXA MMC driver This driver is no longer used and it's remaining users were converted to the new generic PXA MMC driver. Thus, remove this driver. Signed-off-by: Marek Vasut Cc: Andy Fleming Signed-off-by: Andy Fleming diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 565ba6a..ac3cb0b 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -41,7 +41,6 @@ COBJS-$(CONFIG_MV_SDHCI) += mv_sdhci.o COBJS-$(CONFIG_MXC_MMC) += mxcmmc.o COBJS-$(CONFIG_MXS_MMC) += mxsmmc.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_SDHCI) += sdhci.o COBJS-$(CONFIG_S5P_SDHCI) += s5p_sdhci.o diff --git a/drivers/mmc/pxa_mmc.c b/drivers/mmc/pxa_mmc.c deleted file mode 100644 index 80c4445..0000000 --- a/drivers/mmc/pxa_mmc.c +++ /dev/null @@ -1,643 +0,0 @@ -/* - * (C) Copyright 2003 - * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net - * - * See file CREDITS for list of people who contributed to this - * project. - * - * 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 -#include -#include -#include -#include -#include -#include - -#include "pxa_mmc.h" - -extern int fat_register_device(block_dev_desc_t * dev_desc, int part_no); - -static block_dev_desc_t mmc_dev; - -block_dev_desc_t *mmc_get_dev(int dev) -{ - return ((block_dev_desc_t *) & mmc_dev); -} - -/* - * FIXME needs to read cid and csd info to determine block size - * and other parameters - */ -static uchar mmc_buf[MMC_BLOCK_SIZE]; -static uchar spec_ver; -static int mmc_ready = 0; -static int wide = 0; - -static uint32_t * -/****************************************************/ -mmc_cmd(ushort cmd, ushort argh, ushort argl, ushort cmdat) -/****************************************************/ -{ - static uint32_t resp[4], a, b, c; - uint32_t status; - int i; - - debug("mmc_cmd %u 0x%04x 0x%04x 0x%04x\n", cmd, argh, argl, - cmdat | wide); - writel(MMC_STRPCL_STOP_CLK, MMC_STRPCL); - writel(~MMC_I_MASK_CLK_IS_OFF, MMC_I_MASK); - while (!(readl(MMC_I_REG) & MMC_I_REG_CLK_IS_OFF)) - ; - writel(cmd, MMC_CMD); - writel(argh, MMC_ARGH); - writel(argl, MMC_ARGL); - writel(cmdat | wide, MMC_CMDAT); - writel(~MMC_I_MASK_END_CMD_RES, MMC_I_MASK); - writel(MMC_STRPCL_START_CLK, MMC_STRPCL); - while (!(readl(MMC_I_REG) & MMC_I_REG_END_CMD_RES)) - ; - - status = readl(MMC_STAT); - debug("MMC status 0x%08x\n", status); - if (status & MMC_STAT_TIME_OUT_RESPONSE) { - return 0; - } - - /* 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(MMC_RES) & 0xffff); - for (i = 0; i < 4; i++) { - b = (readl(MMC_RES) & 0xffff); - c = (readl(MMC_RES) & 0xffff); - resp[i] = (a << 24) | (b << 8) | (c >> 8); - a = c; - debug("MMC resp[%d] = %#08x\n", i, resp[i]); - } - - return resp; -} - -int -/****************************************************/ -mmc_block_read(uchar * dst, uint32_t src, int len) -/****************************************************/ -{ - ushort argh, argl; - ulong status; - - if (len == 0) { - return 0; - } - - debug("mmc_block_rd dst %p src %08x len %d\n", dst, src, len); - - argh = len >> 16; - argl = len & 0xffff; - - /* set block len */ - mmc_cmd(MMC_CMD_SET_BLOCKLEN, argh, argl, MMC_CMDAT_R1); - - /* send read command */ - argh = src >> 16; - argl = src & 0xffff; - writel(MMC_STRPCL_STOP_CLK, MMC_STRPCL); - writel(0xffff, MMC_RDTO); - writel(1, MMC_NOB); - writel(len, MMC_BLKLEN); - mmc_cmd(MMC_CMD_READ_SINGLE_BLOCK, argh, argl, - MMC_CMDAT_R1 | MMC_CMDAT_READ | MMC_CMDAT_BLOCK | - MMC_CMDAT_DATA_EN); - - writel(~MMC_I_MASK_RXFIFO_RD_REQ, MMC_I_MASK); - while (len) { - if (readl(MMC_I_REG) & MMC_I_REG_RXFIFO_RD_REQ) { -#if defined(CONFIG_CPU_PXA27X) || defined(CONFIG_CPU_MONAHANS) - int i; - for (i = min(len, 32); i; i--) { - *dst++ = readb(MMC_RXFIFO); - len--; - } -#else - *dst++ = readb(MMC_RXFIFO); - len--; -#endif - } - status = readl(MMC_STAT); - if (status & MMC_STAT_ERRORS) { - printf("MMC_STAT error %lx\n", status); - return -1; - } - } - writel(~MMC_I_MASK_DATA_TRAN_DONE, MMC_I_MASK); - while (!(readl(MMC_I_REG) & MMC_I_REG_DATA_TRAN_DONE)) - ; - status = readl(MMC_STAT); - if (status & MMC_STAT_ERRORS) { - printf("MMC_STAT error %lx\n", status); - return -1; - } - return 0; -} - -int -/****************************************************/ -mmc_block_write(ulong dst, uchar * src, int len) -/****************************************************/ -{ - ushort argh, argl; - ulong status; - - if (len == 0) { - return 0; - } - - debug("mmc_block_wr dst %lx src %lx len %d\n", dst, (ulong) src, len); - - argh = len >> 16; - argl = len & 0xffff; - - /* set block len */ - mmc_cmd(MMC_CMD_SET_BLOCKLEN, argh, argl, MMC_CMDAT_R1); - - /* send write command */ - argh = dst >> 16; - argl = dst & 0xffff; - writel(MMC_STRPCL_STOP_CLK, MMC_STRPCL); - writel(1, MMC_NOB); - writel(len, MMC_BLKLEN); - mmc_cmd(MMC_CMD_WRITE_SINGLE_BLOCK, argh, argl, - MMC_CMDAT_R1 | MMC_CMDAT_WRITE | MMC_CMDAT_BLOCK | - MMC_CMDAT_DATA_EN); - - writel(~MMC_I_MASK_TXFIFO_WR_REQ, MMC_I_MASK); - while (len) { - if (readl(MMC_I_REG) & MMC_I_REG_TXFIFO_WR_REQ) { - int i, bytes = min(32, len); - - for (i = 0; i < bytes; i++) { - writel(*src++, MMC_TXFIFO); - } - if (bytes < 32) { - writel(MMC_PRTBUF_BUF_PART_FULL, MMC_PRTBUF); - } - len -= bytes; - } - status = readl(MMC_STAT); - if (status & MMC_STAT_ERRORS) { - printf("MMC_STAT error %lx\n", status); - return -1; - } - } - writel(~MMC_I_MASK_DATA_TRAN_DONE, MMC_I_MASK); - while (!(readl(MMC_I_REG) & MMC_I_REG_DATA_TRAN_DONE)) - ; - writel(~MMC_I_MASK_PRG_DONE, MMC_I_MASK); - while (!(readl(MMC_I_REG) & MMC_I_REG_PRG_DONE)) - ; - status = readl(MMC_STAT); - if (status & MMC_STAT_ERRORS) { - printf("MMC_STAT error %lx\n", status); - return -1; - } - return 0; -} - -int -/****************************************************/ -pxa_mmc_read(long src, uchar * dst, int size) -/****************************************************/ -{ - ulong end, part_start, part_end, part_len, aligned_start, aligned_end; - ulong mmc_block_size, mmc_block_address; - - if (size == 0) { - return 0; - } - - if (!mmc_ready) { - printf("Please initial the MMC first\n"); - return -1; - } - - mmc_block_size = MMC_BLOCK_SIZE; - mmc_block_address = ~(mmc_block_size - 1); - - src -= CONFIG_SYS_MMC_BASE; - end = src + size; - part_start = ~mmc_block_address & src; - part_end = ~mmc_block_address & end; - aligned_start = mmc_block_address & src; - aligned_end = mmc_block_address & end; - - /* all block aligned accesses */ - debug - ("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n", - src, (ulong) dst, end, part_start, part_end, aligned_start, - aligned_end); - if (part_start) { - part_len = mmc_block_size - part_start; - debug - ("ps src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n", - src, (ulong) dst, end, part_start, part_end, aligned_start, - aligned_end); - if ((mmc_block_read(mmc_buf, aligned_start, mmc_block_size)) < - 0) { - return -1; - } - memcpy(dst, mmc_buf + part_start, part_len); - dst += part_len; - src += part_len; - } - debug - ("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n", - src, (ulong) dst, end, part_start, part_end, aligned_start, - aligned_end); - for (; src < aligned_end; src += mmc_block_size, dst += mmc_block_size) { - debug - ("al src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n", - src, (ulong) dst, end, part_start, part_end, aligned_start, - aligned_end); - if ((mmc_block_read((uchar *) (dst), src, mmc_block_size)) < 0) { - return -1; - } - } - debug - ("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n", - src, (ulong) dst, end, part_start, part_end, aligned_start, - aligned_end); - if (part_end && src < end) { - debug - ("pe src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n", - src, (ulong) dst, end, part_start, part_end, aligned_start, - aligned_end); - if ((mmc_block_read(mmc_buf, aligned_end, mmc_block_size)) < 0) { - return -1; - } - memcpy(dst, mmc_buf, part_end); - } - return 0; -} - -int -/****************************************************/ -pxa_mmc_write(uchar * src, uint32_t dst, int size) -/****************************************************/ -{ - ulong end, part_start, part_end, part_len, aligned_start, aligned_end; - ulong mmc_block_size, mmc_block_address; - - if (size == 0) { - return 0; - } - - if (!mmc_ready) { - printf("Please initial the MMC first\n"); - return -1; - } - - mmc_block_size = MMC_BLOCK_SIZE; - mmc_block_address = ~(mmc_block_size - 1); - - dst -= CONFIG_SYS_MMC_BASE; - end = dst + size; - part_start = ~mmc_block_address & dst; - part_end = ~mmc_block_address & end; - aligned_start = mmc_block_address & dst; - aligned_end = mmc_block_address & end; - - /* all block aligned accesses */ - debug - ("src %p dst %08x end %lx pstart %lx pend %lx astart %lx aend %lx\n", - src, dst, end, part_start, part_end, aligned_start, - aligned_end); - if (part_start) { - part_len = mmc_block_size - part_start; - debug - ("ps src %p dst %08x end %lx pstart %lx pend %lx astart %lx aend %lx\n", - src, dst, end, part_start, part_end, aligned_start, - aligned_end); - if ((mmc_block_read(mmc_buf, aligned_start, mmc_block_size)) < - 0) { - return -1; - } - memcpy(mmc_buf + part_start, src, part_len); - if ((mmc_block_write(aligned_start, mmc_buf, mmc_block_size)) < - 0) { - return -1; - } - dst += part_len; - src += part_len; - } - debug - ("src %p dst %08x end %lx pstart %lx pend %lx astart %lx aend %lx\n", - src, dst, end, part_start, part_end, aligned_start, - aligned_end); - for (; dst < aligned_end; src += mmc_block_size, dst += mmc_block_size) { - debug - ("al src %p dst %08x end %lx pstart %lx pend %lx astart %lx aend %lx\n", - src, dst, end, part_start, part_end, aligned_start, - aligned_end); - if ((mmc_block_write(dst, (uchar *) src, mmc_block_size)) < 0) { - return -1; - } - } - debug - ("src %p dst %08x end %lx pstart %lx pend %lx astart %lx aend %lx\n", - src, dst, end, part_start, part_end, aligned_start, - aligned_end); - if (part_end && dst < end) { - debug - ("pe src %p dst %08x end %lx pstart %lx pend %lx astart %lx aend %lx\n", - src, dst, end, part_start, part_end, aligned_start, - aligned_end); - if ((mmc_block_read(mmc_buf, aligned_end, mmc_block_size)) < 0) { - return -1; - } - memcpy(mmc_buf, src, part_end); - if ((mmc_block_write(aligned_end, mmc_buf, mmc_block_size)) < 0) { - return -1; - } - } - return 0; -} - -static ulong -/****************************************************/ -mmc_bread(int dev_num, ulong blknr, lbaint_t blkcnt, void *dst) -/****************************************************/ -{ - int mmc_block_size = MMC_BLOCK_SIZE; - ulong src = blknr * mmc_block_size + CONFIG_SYS_MMC_BASE; - - pxa_mmc_read(src, (uchar *) dst, blkcnt * mmc_block_size); - return blkcnt; -} - -#ifdef __GNUC__ -#define likely(x) __builtin_expect(!!(x), 1) -#define unlikely(x) __builtin_expect(!!(x), 0) -#else -#define likely(x) (x) -#define unlikely(x) (x) -#endif - -#define UNSTUFF_BITS(resp,start,size) \ - ({ \ - const int __size = size; \ - const uint32_t __mask = (__size < 32 ? 1 << __size : 0) - 1; \ - const int32_t __off = 3 - ((start) / 32); \ - const int32_t __shft = (start) & 31; \ - uint32_t __res; \ - \ - __res = resp[__off] >> __shft; \ - if (__size + __shft > 32) \ - __res |= resp[__off-1] << ((32 - __shft) % 32); \ - __res & __mask; \ - }) - -/* - * Given the decoded CSD structure, decode the raw CID to our CID structure. - */ -static void mmc_decode_cid(uint32_t * resp) -{ - if (IF_TYPE_SD == mmc_dev.if_type) { - /* - * SD doesn't currently have a version field so we will - * have to assume we can parse this. - */ - sprintf((char *)mmc_dev.vendor, - "Man %02x OEM %c%c \"%c%c%c%c%c\" Date %02u/%04u", - UNSTUFF_BITS(resp, 120, 8), UNSTUFF_BITS(resp, 112, 8), - UNSTUFF_BITS(resp, 104, 8), UNSTUFF_BITS(resp, 96, 8), - UNSTUFF_BITS(resp, 88, 8), UNSTUFF_BITS(resp, 80, 8), - UNSTUFF_BITS(resp, 72, 8), UNSTUFF_BITS(resp, 64, 8), - UNSTUFF_BITS(resp, 8, 4), UNSTUFF_BITS(resp, 12, - 8) + 2000); - sprintf((char *)mmc_dev.revision, "%d.%d", - UNSTUFF_BITS(resp, 60, 4), UNSTUFF_BITS(resp, 56, 4)); - sprintf((char *)mmc_dev.product, "%u", - UNSTUFF_BITS(resp, 24, 32)); - } else { - /* - * The selection of the format here is based upon published - * specs from sandisk and from what people have reported. - */ - switch (spec_ver) { - case 0: /* MMC v1.0 - v1.2 */ - case 1: /* MMC v1.4 */ - sprintf((char *)mmc_dev.vendor, - "Man %02x%02x%02x \"%c%c%c%c%c%c%c\" Date %02u/%04u", - UNSTUFF_BITS(resp, 120, 8), UNSTUFF_BITS(resp, - 112, - 8), - UNSTUFF_BITS(resp, 104, 8), UNSTUFF_BITS(resp, - 96, 8), - UNSTUFF_BITS(resp, 88, 8), UNSTUFF_BITS(resp, - 80, 8), - UNSTUFF_BITS(resp, 72, 8), UNSTUFF_BITS(resp, - 64, 8), - UNSTUFF_BITS(resp, 56, 8), UNSTUFF_BITS(resp, - 48, 8), - UNSTUFF_BITS(resp, 12, 4), UNSTUFF_BITS(resp, 8, - 4) + - 1997); - sprintf((char *)mmc_dev.revision, "%d.%d", - UNSTUFF_BITS(resp, 44, 4), UNSTUFF_BITS(resp, - 40, 4)); - sprintf((char *)mmc_dev.product, "%u", - UNSTUFF_BITS(resp, 16, 24)); - break; - - case 2: /* MMC v2.0 - v2.2 */ - case 3: /* MMC v3.1 - v3.3 */ - case 4: /* MMC v4 */ - sprintf((char *)mmc_dev.vendor, - "Man %02x OEM %04x \"%c%c%c%c%c%c\" Date %02u/%04u", - UNSTUFF_BITS(resp, 120, 8), UNSTUFF_BITS(resp, - 104, - 16), - UNSTUFF_BITS(resp, 96, 8), UNSTUFF_BITS(resp, - 88, 8), - UNSTUFF_BITS(resp, 80, 8), UNSTUFF_BITS(resp, - 72, 8), - UNSTUFF_BITS(resp, 64, 8), UNSTUFF_BITS(resp, - 56, 8), - UNSTUFF_BITS(resp, 12, 4), UNSTUFF_BITS(resp, 8, - 4) + - 1997); - sprintf((char *)mmc_dev.product, "%u", - UNSTUFF_BITS(resp, 16, 32)); - sprintf((char *)mmc_dev.revision, "N/A"); - break; - - default: - printf("MMC card has unknown MMCA version %d\n", - spec_ver); - break; - } - } - printf("%s card.\nVendor: %s\nProduct: %s\nRevision: %s\n", - (IF_TYPE_SD == mmc_dev.if_type) ? "SD" : "MMC", mmc_dev.vendor, - mmc_dev.product, mmc_dev.revision); -} - -/* - * Given a 128-bit response, decode to our card CSD structure. - */ -static void mmc_decode_csd(uint32_t * resp) -{ - unsigned int mult, csd_struct; - - if (IF_TYPE_SD == mmc_dev.if_type) { - csd_struct = UNSTUFF_BITS(resp, 126, 2); - if (csd_struct != 0) { - printf("SD: unrecognised CSD structure version %d\n", - csd_struct); - return; - } - } else { - /* - * We only understand CSD structure v1.1 and v1.2. - * v1.2 has extra information in bits 15, 11 and 10. - */ - csd_struct = UNSTUFF_BITS(resp, 126, 2); - if (csd_struct != 1 && csd_struct != 2) { - printf("MMC: unrecognised CSD structure version %d\n", - csd_struct); - return; - } - - spec_ver = UNSTUFF_BITS(resp, 122, 4); - mmc_dev.if_type = IF_TYPE_MMC; - } - - mult = 1 << (UNSTUFF_BITS(resp, 47, 3) + 2); - mmc_dev.lba = (1 + UNSTUFF_BITS(resp, 62, 12)) * mult; - mmc_dev.blksz = 1 << UNSTUFF_BITS(resp, 80, 4); - - /* FIXME: The following just makes assumes that's the partition type -- should really read it */ - mmc_dev.part_type = PART_TYPE_DOS; - mmc_dev.dev = 0; - mmc_dev.lun = 0; - mmc_dev.type = DEV_TYPE_HARDDISK; - mmc_dev.removable = 0; - mmc_dev.block_read = mmc_bread; - - printf("Detected: %lu blocks of %lu bytes (%luMB) ", - mmc_dev.lba, - mmc_dev.blksz, - mmc_dev.lba * mmc_dev.blksz / (1024 * 1024)); -} - -int -/****************************************************/ -mmc_legacy_init(int verbose) -/****************************************************/ -{ - int retries, rc = -ENODEV; - uint32_t cid_resp[4]; - uint32_t *resp; - uint16_t rca = 0; - - /* Reset device interface type */ - mmc_dev.if_type = IF_TYPE_UNKNOWN; - -#ifdef CONFIG_CPU_MONAHANS /* pxa3xx */ - writel(readl(CKENA) | CKENA_12_MMC0 | CKENA_13_MMC1, CKENA); -#else /* pxa2xx */ - writel(readl(CKEN) | CKEN12_MMC, CKEN); /* enable MMC unit clock */ -#endif - writel(MMC_CLKRT_0_3125MHZ, MMC_CLKRT); - writel(MMC_RES_TO_MAX, MMC_RESTO); - writel(MMC_SPI_DISABLE, MMC_SPI); - - /* reset */ - mmc_cmd(MMC_CMD_GO_IDLE_STATE, 0, 0, MMC_CMDAT_INIT | MMC_CMDAT_R0); - udelay(200000); - retries = 3; - while (retries--) { - resp = mmc_cmd(MMC_CMD_APP_CMD, 0, 0, MMC_CMDAT_R1); - if (!(resp[0] & 0x00000020)) { /* Card does not support APP_CMD */ - debug("Card does not support APP_CMD\n"); - break; - } - - /* Select 3.2-3.3V and 3.3-3.4V */ - resp = mmc_cmd(SD_CMD_APP_SEND_OP_COND, 0x0030, 0x0000, - MMC_CMDAT_R3 | (retries < 2 ? 0 - : MMC_CMDAT_INIT)); - if (resp[0] & 0x80000000) { - mmc_dev.if_type = IF_TYPE_SD; - debug("Detected SD card\n"); - break; - } - udelay(200000); - } - - if (retries <= 0 || !(IF_TYPE_SD == mmc_dev.if_type)) { - debug("Failed to detect SD Card, trying MMC\n"); - resp = - mmc_cmd(MMC_CMD_SEND_OP_COND, 0x00ff, 0x8000, MMC_CMDAT_R3); - - retries = 10; - while (retries-- && resp && !(resp[0] & 0x80000000)) { - udelay(200000); - resp = - mmc_cmd(MMC_CMD_SEND_OP_COND, 0x00ff, 0x8000, - MMC_CMDAT_R3); - } - } - - /* try to get card id */ - resp = - mmc_cmd(MMC_CMD_ALL_SEND_CID, 0, 0, MMC_CMDAT_R2 | MMC_CMDAT_BUSY); - if (resp) { - memcpy(cid_resp, resp, sizeof(cid_resp)); - - /* MMC exists, get CSD too */ - resp = mmc_cmd(MMC_CMD_SET_RELATIVE_ADDR, 0, 0, MMC_CMDAT_R1); - if (IF_TYPE_SD == mmc_dev.if_type) - rca = ((resp[0] & 0xffff0000) >> 16); - resp = mmc_cmd(MMC_CMD_SEND_CSD, rca, 0, MMC_CMDAT_R2); - if (resp) { - mmc_decode_csd(resp); - rc = 0; - mmc_ready = 1; - } - - mmc_decode_cid(cid_resp); - } - - writel(0, MMC_CLKRT); /* 20 MHz */ - resp = mmc_cmd(MMC_CMD_SELECT_CARD, rca, 0, MMC_CMDAT_R1); - -#if defined(CONFIG_CPU_PXA27X) || defined(CONFIG_CPU_MONAHANS) - if (IF_TYPE_SD == mmc_dev.if_type) { - resp = mmc_cmd(MMC_CMD_APP_CMD, rca, 0, MMC_CMDAT_R1); - resp = mmc_cmd(SD_CMD_APP_SET_BUS_WIDTH, 0, 2, MMC_CMDAT_R1); - wide = MMC_CMDAT_SD_4DAT; - } -#endif - - fat_register_device(&mmc_dev, 1); /* partitions start counting with 1 */ - - return rc; -} -- cgit v0.10.2 From 757bff49ba3159d71ccacabdb68f8309b1eb6613 Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Mon, 15 Oct 2012 19:10:29 +0000 Subject: mmc: dw-mmc: support DesignWare MMC Controller Support the DesginWare MMC Controller. Signed-off-by: Jaehoon Chung Signed-off-by: Kyungmin Park Signed-off-by: Rajeshawari Shinde Signed-off-by: Andy Fleming diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index ac3cb0b..a1dd730 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -46,6 +46,7 @@ COBJS-$(CONFIG_SDHCI) += sdhci.o COBJS-$(CONFIG_S5P_SDHCI) += s5p_sdhci.o COBJS-$(CONFIG_SH_MMCIF) += sh_mmcif.o COBJS-$(CONFIG_TEGRA_MMC) += tegra_mmc.o +COBJS-$(CONFIG_DWMMC) += dw_mmc.o COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c new file mode 100644 index 0000000..4070d4e --- /dev/null +++ b/drivers/mmc/dw_mmc.c @@ -0,0 +1,385 @@ +/* + * (C) Copyright 2012 SAMSUNG Electronics + * Jaehoon Chung + * Rajeshawari Shinde + * + * 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 +#include +#include +#include +#include +#include + +#define PAGE_SIZE 4096 + +static int dwmci_wait_reset(struct dwmci_host *host, u32 value) +{ + unsigned long timeout = 1000; + u32 ctrl; + + dwmci_writel(host, DWMCI_CTRL, value); + + while (timeout--) { + ctrl = dwmci_readl(host, DWMCI_CTRL); + if (!(ctrl & DWMCI_RESET_ALL)) + return 1; + } + return 0; +} + +static void dwmci_set_idma_desc(struct dwmci_idmac *idmac, + u32 desc0, u32 desc1, u32 desc2) +{ + struct dwmci_idmac *desc = idmac; + + desc->flags = desc0; + desc->cnt = desc1; + desc->addr = desc2; + desc->next_addr = (unsigned int)desc + sizeof(struct dwmci_idmac); +} + +static void dwmci_prepare_data(struct dwmci_host *host, + struct mmc_data *data) +{ + unsigned long ctrl; + unsigned int i = 0, flags, cnt, blk_cnt; + ulong data_start, data_end, start_addr; + ALLOC_CACHE_ALIGN_BUFFER(struct dwmci_idmac, cur_idmac, data->blocks); + + + blk_cnt = data->blocks; + + dwmci_wait_reset(host, DWMCI_CTRL_FIFO_RESET); + + data_start = (ulong)cur_idmac; + dwmci_writel(host, DWMCI_DBADDR, (unsigned int)cur_idmac); + + if (data->flags == MMC_DATA_READ) + start_addr = (unsigned int)data->dest; + else + start_addr = (unsigned int)data->src; + + do { + flags = DWMCI_IDMAC_OWN | DWMCI_IDMAC_CH ; + flags |= (i == 0) ? DWMCI_IDMAC_FS : 0; + if (blk_cnt <= 8) { + flags |= DWMCI_IDMAC_LD; + cnt = data->blocksize * blk_cnt; + } else + cnt = data->blocksize * 8; + + dwmci_set_idma_desc(cur_idmac, flags, cnt, + start_addr + (i * PAGE_SIZE)); + + if(blk_cnt < 8) + break; + blk_cnt -= 8; + cur_idmac++; + i++; + } while(1); + + data_end = (ulong)cur_idmac; + flush_dcache_range(data_start, data_end + ARCH_DMA_MINALIGN); + + ctrl = dwmci_readl(host, DWMCI_CTRL); + ctrl |= DWMCI_IDMAC_EN | DWMCI_DMA_EN; + dwmci_writel(host, DWMCI_CTRL, ctrl); + + ctrl = dwmci_readl(host, DWMCI_BMOD); + ctrl |= DWMCI_BMOD_IDMAC_FB | DWMCI_BMOD_IDMAC_EN; + dwmci_writel(host, DWMCI_BMOD, ctrl); + + dwmci_writel(host, DWMCI_BLKSIZ, data->blocksize); + dwmci_writel(host, DWMCI_BYTCNT, data->blocksize * data->blocks); +} + +static int dwmci_set_transfer_mode(struct dwmci_host *host, + struct mmc_data *data) +{ + unsigned long mode; + + mode = DWMCI_CMD_DATA_EXP; + if (data->flags & MMC_DATA_WRITE) + mode |= DWMCI_CMD_RW; + + return mode; +} + +static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, + struct mmc_data *data) +{ + struct dwmci_host *host = (struct dwmci_host *)mmc->priv; + int flags = 0, i; + unsigned int timeout = 100000; + u32 retry = 10000; + u32 mask, ctrl; + + while (dwmci_readl(host, DWMCI_STATUS) & DWMCI_BUSY) { + if (timeout == 0) { + printf("Timeout on data busy\n"); + return TIMEOUT; + } + timeout--; + } + + dwmci_writel(host, DWMCI_RINTSTS, DWMCI_INTMSK_ALL); + + if (data) + dwmci_prepare_data(host, data); + + + dwmci_writel(host, DWMCI_CMDARG, cmd->cmdarg); + + if (data) + flags = dwmci_set_transfer_mode(host, data); + + if ((cmd->resp_type & MMC_RSP_136) && (cmd->resp_type & MMC_RSP_BUSY)) + return -1; + + if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) + flags |= DWMCI_CMD_ABORT_STOP; + else + flags |= DWMCI_CMD_PRV_DAT_WAIT; + + if (cmd->resp_type & MMC_RSP_PRESENT) { + flags |= DWMCI_CMD_RESP_EXP; + if (cmd->resp_type & MMC_RSP_136) + flags |= DWMCI_CMD_RESP_LENGTH; + } + + if (cmd->resp_type & MMC_RSP_CRC) + flags |= DWMCI_CMD_CHECK_CRC; + + flags |= (cmd->cmdidx | DWMCI_CMD_START | DWMCI_CMD_USE_HOLD_REG); + + debug("Sending CMD%d\n",cmd->cmdidx); + + dwmci_writel(host, DWMCI_CMD, flags); + + for (i = 0; i < retry; i++) { + mask = dwmci_readl(host, DWMCI_RINTSTS); + if (mask & DWMCI_INTMSK_CDONE) { + if (!data) + dwmci_writel(host, DWMCI_RINTSTS, mask); + break; + } + } + + if (i == retry) + return TIMEOUT; + + if (mask & DWMCI_INTMSK_RTO) { + debug("Response Timeout..\n"); + return TIMEOUT; + } else if (mask & DWMCI_INTMSK_RE) { + debug("Response Error..\n"); + return -1; + } + + + if (cmd->resp_type & MMC_RSP_PRESENT) { + if (cmd->resp_type & MMC_RSP_136) { + cmd->response[0] = dwmci_readl(host, DWMCI_RESP3); + cmd->response[1] = dwmci_readl(host, DWMCI_RESP2); + cmd->response[2] = dwmci_readl(host, DWMCI_RESP1); + cmd->response[3] = dwmci_readl(host, DWMCI_RESP0); + } else { + cmd->response[0] = dwmci_readl(host, DWMCI_RESP0); + } + } + + if (data) { + do { + mask = dwmci_readl(host, DWMCI_RINTSTS); + if (mask & (DWMCI_DATA_ERR | DWMCI_DATA_TOUT)) { + debug("DATA ERROR!\n"); + return -1; + } + } while (!(mask & DWMCI_INTMSK_DTO)); + + dwmci_writel(host, DWMCI_RINTSTS, mask); + + ctrl = dwmci_readl(host, DWMCI_CTRL); + ctrl &= ~(DWMCI_DMA_EN); + dwmci_writel(host, DWMCI_CTRL, ctrl); + } + + udelay(100); + + return 0; +} + +static int dwmci_setup_bus(struct dwmci_host *host, u32 freq) +{ + u32 div, status; + int timeout = 10000; + unsigned long sclk; + + if (freq == host->clock) + return 0; + + /* + * If host->mmc_clk didn't define, + * then assume that host->bus_hz is source clock value. + * host->bus_hz should be set from user. + */ + if (host->mmc_clk) + sclk = host->mmc_clk(host->dev_index); + else if (host->bus_hz) + sclk = host->bus_hz; + else { + printf("Didn't get source clock value..\n"); + return -EINVAL; + } + + div = DIV_ROUND_UP(sclk, 2 * freq); + + dwmci_writel(host, DWMCI_CLKENA, 0); + dwmci_writel(host, DWMCI_CLKSRC, 0); + + dwmci_writel(host, DWMCI_CLKDIV, div); + dwmci_writel(host, DWMCI_CMD, DWMCI_CMD_PRV_DAT_WAIT | + DWMCI_CMD_UPD_CLK | DWMCI_CMD_START); + + do { + status = dwmci_readl(host, DWMCI_CMD); + if (timeout-- < 0) { + printf("TIMEOUT error!!\n"); + return -ETIMEDOUT; + } + } while (status & DWMCI_CMD_START); + + dwmci_writel(host, DWMCI_CLKENA, DWMCI_CLKEN_ENABLE | + DWMCI_CLKEN_LOW_PWR); + + dwmci_writel(host, DWMCI_CMD, DWMCI_CMD_PRV_DAT_WAIT | + DWMCI_CMD_UPD_CLK | DWMCI_CMD_START); + + timeout = 10000; + do { + status = dwmci_readl(host, DWMCI_CMD); + if (timeout-- < 0) { + printf("TIMEOUT error!!\n"); + return -ETIMEDOUT; + } + } while (status & DWMCI_CMD_START); + + host->clock = freq; + + return 0; +} + +static void dwmci_set_ios(struct mmc *mmc) +{ + struct dwmci_host *host = (struct dwmci_host *)mmc->priv; + u32 ctype; + + debug("Buswidth = %d, clock: %d\n",mmc->bus_width, mmc->clock); + + dwmci_setup_bus(host, mmc->clock); + switch (mmc->bus_width) { + case 8: + ctype = DWMCI_CTYPE_8BIT; + break; + case 4: + ctype = DWMCI_CTYPE_4BIT; + break; + default: + ctype = DWMCI_CTYPE_1BIT; + break; + } + + dwmci_writel(host, DWMCI_CTYPE, ctype); + + if (host->clksel) + host->clksel(host); +} + +static int dwmci_init(struct mmc *mmc) +{ + struct dwmci_host *host = (struct dwmci_host *)mmc->priv; + u32 fifo_size, fifoth_val; + + dwmci_writel(host, DWMCI_PWREN, 1); + + if (!dwmci_wait_reset(host, DWMCI_RESET_ALL)) { + debug("%s[%d] Fail-reset!!\n",__func__,__LINE__); + return -1; + } + + dwmci_writel(host, DWMCI_RINTSTS, 0xFFFFFFFF); + dwmci_writel(host, DWMCI_INTMASK, 0); + + dwmci_writel(host, DWMCI_TMOUT, 0xFFFFFFFF); + + dwmci_writel(host, DWMCI_IDINTEN, 0); + dwmci_writel(host, DWMCI_BMOD, 1); + + fifo_size = dwmci_readl(host, DWMCI_FIFOTH); + if (host->fifoth_val) + fifoth_val = host->fifoth_val; + else + fifoth_val = MSIZE(0x2) | RX_WMARK(fifo_size/2 -1) | + TX_WMARK(fifo_size/2); + dwmci_writel(host, DWMCI_FIFOTH, fifoth_val); + + dwmci_writel(host, DWMCI_CLKENA, 0); + dwmci_writel(host, DWMCI_CLKSRC, 0); + + return 0; +} + +int add_dwmci(struct dwmci_host *host, u32 max_clk, u32 min_clk) +{ + struct mmc *mmc; + int err = 0; + + mmc = malloc(sizeof(struct mmc)); + if (!mmc) { + printf("mmc malloc fail!\n"); + return -1; + } + + mmc->priv = host; + host->mmc = mmc; + + sprintf(mmc->name, "%s", host->name); + mmc->send_cmd = dwmci_send_cmd; + mmc->set_ios = dwmci_set_ios; + mmc->init = dwmci_init; + mmc->f_min = min_clk; + mmc->f_max = max_clk; + + mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; + + mmc->host_caps = host->caps; + + if (host->buswidth == 8) { + mmc->host_caps |= MMC_MODE_8BIT; + mmc->host_caps &= ~MMC_MODE_4BIT; + } else { + mmc->host_caps |= MMC_MODE_4BIT; + mmc->host_caps &= ~MMC_MODE_8BIT; + } + mmc->host_caps |= MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_HC; + + err = mmc_register(mmc); + + return err; +} diff --git a/include/dwmmc.h b/include/dwmmc.h new file mode 100644 index 0000000..c8b1d40 --- /dev/null +++ b/include/dwmmc.h @@ -0,0 +1,191 @@ +/* + * (C) Copyright 2012 SAMSUNG Electronics + * Jaehoon Chung + * + * 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 __DWMMC_HW_H +#define __DWMMC_HW_H + +#include +#include + +#define DWMCI_CTRL 0x000 +#define DWMCI_PWREN 0x004 +#define DWMCI_CLKDIV 0x008 +#define DWMCI_CLKSRC 0x00C +#define DWMCI_CLKENA 0x010 +#define DWMCI_TMOUT 0x014 +#define DWMCI_CTYPE 0x018 +#define DWMCI_BLKSIZ 0x01C +#define DWMCI_BYTCNT 0x020 +#define DWMCI_INTMASK 0x024 +#define DWMCI_CMDARG 0x028 +#define DWMCI_CMD 0x02C +#define DWMCI_RESP0 0x030 +#define DWMCI_RESP1 0x034 +#define DWMCI_RESP2 0x038 +#define DWMCI_RESP3 0x03C +#define DWMCI_MINTSTS 0x040 +#define DWMCI_RINTSTS 0x044 +#define DWMCI_STATUS 0x048 +#define DWMCI_FIFOTH 0x04C +#define DWMCI_CDETECT 0x050 +#define DWMCI_WRTPRT 0x054 +#define DWMCI_GPIO 0x058 +#define DWMCI_TCMCNT 0x05C +#define DWMCI_TBBCNT 0x060 +#define DWMCI_DEBNCE 0x064 +#define DWMCI_USRID 0x068 +#define DWMCI_VERID 0x06C +#define DWMCI_HCON 0x070 +#define DWMCI_UHS_REG 0x074 +#define DWMCI_BMOD 0x080 +#define DWMCI_PLDMND 0x084 +#define DWMCI_DBADDR 0x088 +#define DWMCI_IDSTS 0x08C +#define DWMCI_IDINTEN 0x090 +#define DWMCI_DSCADDR 0x094 +#define DWMCI_BUFADDR 0x098 +#define DWMCI_DATA 0x200 + +/* Interrupt Mask register */ +#define DWMCI_INTMSK_ALL 0xffffffff +#define DWMCI_INTMSK_RE (1 << 1) +#define DWMCI_INTMSK_CDONE (1 << 2) +#define DWMCI_INTMSK_DTO (1 << 3) +#define DWMCI_INTMSK_TXDR (1 << 4) +#define DWMCI_INTMSK_RXDR (1 << 5) +#define DWMCI_INTMSK_DCRC (1 << 7) +#define DWMCI_INTMSK_RTO (1 << 8) +#define DWMCI_INTMSK_DRTO (1 << 9) +#define DWMCI_INTMSK_HTO (1 << 10) +#define DWMCI_INTMSK_FRUN (1 << 11) +#define DWMCI_INTMSK_HLE (1 << 12) +#define DWMCI_INTMSK_SBE (1 << 13) +#define DWMCI_INTMSK_ACD (1 << 14) +#define DWMCI_INTMSK_EBE (1 << 15) + +/* Raw interrupt Regsiter */ +#define DWMCI_DATA_ERR (DWMCI_INTMSK_EBE | DWMCI_INTMSK_SBE | DWMCI_INTMSK_HLE |\ + DWMCI_INTMSK_FRUN | DWMCI_INTMSK_EBE | DWMCI_INTMSK_DCRC) +#define DWMCI_DATA_TOUT (DWMCI_INTMSK_HTO | DWMCI_INTMSK_DRTO) +/* CTRL register */ +#define DWMCI_CTRL_RESET (1 << 0) +#define DWMCI_CTRL_FIFO_RESET (1 << 1) +#define DWMCI_CTRL_DMA_RESET (1 << 2) +#define DWMCI_DMA_EN (1 << 5) +#define DWMCI_CTRL_SEND_AS_CCSD (1 << 10) +#define DWMCI_IDMAC_EN (1 << 25) +#define DWMCI_RESET_ALL (DWMCI_CTRL_RESET | DWMCI_CTRL_FIFO_RESET |\ + DWMCI_CTRL_DMA_RESET) + +/* CMD register */ +#define DWMCI_CMD_RESP_EXP (1 << 6) +#define DWMCI_CMD_RESP_LENGTH (1 << 7) +#define DWMCI_CMD_CHECK_CRC (1 << 8) +#define DWMCI_CMD_DATA_EXP (1 << 9) +#define DWMCI_CMD_RW (1 << 10) +#define DWMCI_CMD_SEND_STOP (1 << 12) +#define DWMCI_CMD_ABORT_STOP (1 << 14) +#define DWMCI_CMD_PRV_DAT_WAIT (1 << 13) +#define DWMCI_CMD_UPD_CLK (1 << 21) +#define DWMCI_CMD_USE_HOLD_REG (1 << 29) +#define DWMCI_CMD_START (1 << 31) + +/* CLKENA register */ +#define DWMCI_CLKEN_ENABLE (1 << 0) +#define DWMCI_CLKEN_LOW_PWR (1 << 16) + +/* Card-type registe */ +#define DWMCI_CTYPE_1BIT 0 +#define DWMCI_CTYPE_4BIT (1 << 0) +#define DWMCI_CTYPE_8BIT (1 << 16) + +/* Status Register */ +#define DWMCI_BUSY (1 << 9) + +/* FIFOTH Register */ +#define MSIZE(x) ((x) << 28) +#define RX_WMARK(x) ((x) << 16) +#define TX_WMARK(x) (x) + +#define DWMCI_IDMAC_OWN (1 << 31) +#define DWMCI_IDMAC_CH (1 << 4) +#define DWMCI_IDMAC_FS (1 << 3) +#define DWMCI_IDMAC_LD (1 << 2) + +/* Bus Mode Register */ +#define DWMCI_BMOD_IDMAC_RESET (1 << 0) +#define DWMCI_BMOD_IDMAC_FB (1 << 1) +#define DWMCI_BMOD_IDMAC_EN (1 << 7) + +struct dwmci_host { + char *name; + void *ioaddr; + unsigned int quirks; + unsigned int caps; + unsigned int version; + unsigned int clock; + unsigned int bus_hz; + int dev_index; + int buswidth; + u32 fifoth_val; + struct mmc *mmc; + + void (*clksel)(struct dwmci_host *host); + unsigned int (*mmc_clk)(int dev_index); +}; + +struct dwmci_idmac { + u32 flags; + u32 cnt; + u32 addr; + u32 next_addr; +}; + +static inline void dwmci_writel(struct dwmci_host *host, int reg, u32 val) +{ + writel(val, host->ioaddr + reg); +} + +static inline void dwmci_writew(struct dwmci_host *host, int reg, u16 val) +{ + writew(val, host->ioaddr + reg); +} + +static inline void dwmci_writeb(struct dwmci_host *host, int reg, u8 val) +{ + writeb(val, host->ioaddr + reg); +} +static inline u32 dwmci_readl(struct dwmci_host *host, int reg) +{ + return readl(host->ioaddr + reg); +} + +static inline u16 dwmci_readw(struct dwmci_host *host, int reg) +{ + return readw(host->ioaddr + reg); +} + +static inline u8 dwmci_readb(struct dwmci_host *host, int reg) +{ + return readb(host->ioaddr + reg); +} + +int add_dwmci(struct dwmci_host *host, u32 max_clk, u32 min_clk); +#endif /* __DWMMC_HW_H */ -- cgit v0.10.2