* [PATCH 0/6] mmc: split the tmio driver into several modules
@ 2011-03-11 7:51 Guennadi Liakhovetski
2011-03-11 7:51 ` [PATCH 1/6] mmc: tmio: split core functionality, DMA and MFD glue Guennadi Liakhovetski
` (6 more replies)
0 siblings, 7 replies; 27+ messages in thread
From: Guennadi Liakhovetski @ 2011-03-11 7:51 UTC (permalink / raw)
To: linux-sh; +Cc: linux-mmc, Chris Ball, Ian Molton
Hi all
The tmio_mmc SD/SDIO driver is serving very different hardware
configurations: on the one hand multi-function style chips from Toshiba,
Compaq, on the other hand SDHI units in ARM- and SuperH-based sh-mobile
SoCs. Apart from the different native APIs: MFD for the former and
platform-device in the latter, sh-mobile implementations also have a
number of features, exclusive to them, which, if implemented in the common
driver, clutter it needlessly and make its maintenance more difficult.
This patch series simplifies the situation by splitting the driver up into
3 modules: the core, consisting of the main part and, on sh-mobile, of the
DMA part; the mfd glue; and the platform glue. This way also (imaginary)
sh-mobile systems with additional tmio mfd chips on them can be supported.
Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH 1/6] mmc: tmio: split core functionality, DMA and MFD glue
2011-03-11 7:51 [PATCH 0/6] mmc: split the tmio driver into several modules Guennadi Liakhovetski
@ 2011-03-11 7:51 ` Guennadi Liakhovetski
2011-03-12 16:05 ` Magnus Damm
2011-03-11 7:52 ` [PATCH 2/6] sh: ecovec: use the CONFIG_MMC_TMIO symbols instead of Guennadi Liakhovetski
` (5 subsequent siblings)
6 siblings, 1 reply; 27+ messages in thread
From: Guennadi Liakhovetski @ 2011-03-11 7:51 UTC (permalink / raw)
To: linux-sh; +Cc: linux-mmc, Chris Ball, Ian Molton
TMIO MMC chips contain an SD / SDIO IP core from Panasonic, similar to
the one, used in MN5774 and other MN57xx controllers. These IP cores are
included in many multifunction devices, in sh-mobile chips from Renesas,
in the latter case they can also use DMA. Some sh-mobile implementations
also have some other specialities, that MFD-based solutions don't have.
This makes supporting all these features in a monolithic driver inconveniet
and error-prone. This patch splits the driver into 3 parts: the core,
the MFD glue and the DMA support. In case of a modular build, two modules
will be built: mmc_tmio_core and mmc_tmio.
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
---
drivers/mmc/host/Kconfig | 4 +
drivers/mmc/host/Makefile | 3 +
drivers/mmc/host/tmio_mmc.c | 1303 +--------------------------------------
drivers/mmc/host/tmio_mmc.h | 152 +++++
drivers/mmc/host/tmio_mmc_dma.c | 302 +++++++++
drivers/mmc/host/tmio_mmc_pio.c | 923 +++++++++++++++++++++++++++
6 files changed, 1402 insertions(+), 1285 deletions(-)
create mode 100644 drivers/mmc/host/tmio_mmc.h
create mode 100644 drivers/mmc/host/tmio_mmc_dma.c
create mode 100644 drivers/mmc/host/tmio_mmc_pio.c
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 1a21c64..4d16166 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -439,9 +439,13 @@ config MMC_SDRICOH_CS
To compile this driver as a module, choose M here: the
module will be called sdricoh_cs.
+config MMC_TMIO_CORE
+ tristate
+
config MMC_TMIO
tristate "Toshiba Mobile IO Controller (TMIO) MMC/SD function support"
depends on MFD_TMIO || MFD_ASIC3 || MFD_SH_MOBILE_SDHI
+ select MMC_TMIO_CORE
help
This provides support for the SD/MMC cell found in TC6393XB,
T7L66XB and also HTC ASIC3
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 30aa686..79c42dd 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -29,6 +29,9 @@ endif
obj-$(CONFIG_MMC_S3C) += s3cmci.o
obj-$(CONFIG_MMC_SDRICOH_CS) += sdricoh_cs.o
obj-$(CONFIG_MMC_TMIO) += tmio_mmc.o
+obj-$(CONFIG_MMC_TMIO_CORE) += tmio_mmc_core.o
+tmio_mmc_core-y := tmio_mmc_pio.o
+tmio_mmc_core-$(CONFIG_TMIO_MMC_DMA) += tmio_mmc_dma.o
obj-$(CONFIG_MMC_CB710) += cb710-mmc.o
obj-$(CONFIG_MMC_VIA_SDMMC) += via-sdmmc.o
obj-$(CONFIG_SDH_BFIN) += bfin_sdh.o
diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c
index 32ab145..79c5684 100644
--- a/drivers/mmc/host/tmio_mmc.c
+++ b/drivers/mmc/host/tmio_mmc.c
@@ -1,8 +1,8 @@
/*
- * linux/drivers/mmc/tmio_mmc.c
+ * linux/drivers/mmc/host/tmio_mmc.c
*
- * Copyright (C) 2004 Ian Molton
- * Copyright (C) 2007 Ian Molton
+ * Copyright (C) 2007 Ian Molton
+ * Copyright (C) 2004 Ian Molton
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -11,1200 +11,17 @@
* Driver for the MMC / SD / SDIO cell found in:
*
* TC6393XB TC6391XB TC6387XB T7L66XB ASIC3
- *
- * This driver draws mainly on scattered spec sheets, Reverse engineering
- * of the toshiba e800 SD driver and some parts of the 2.4 ASIC3 driver (4 bit
- * support). (Further 4 bit support from a later datasheet).
- *
- * TODO:
- * Investigate using a workqueue for PIO transfers
- * Eliminate FIXMEs
- * SDIO support
- * Better Power management
- * Handle MMC errors better
- * double buffer support
- *
*/
-#include <linux/delay.h>
#include <linux/device.h>
-#include <linux/dmaengine.h>
-#include <linux/highmem.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/irq.h>
#include <linux/mfd/core.h>
#include <linux/mfd/tmio.h>
#include <linux/mmc/host.h>
#include <linux/module.h>
#include <linux/pagemap.h>
#include <linux/scatterlist.h>
-#include <linux/workqueue.h>
-#include <linux/spinlock.h>
-
-#define CTL_SD_CMD 0x00
-#define CTL_ARG_REG 0x04
-#define CTL_STOP_INTERNAL_ACTION 0x08
-#define CTL_XFER_BLK_COUNT 0xa
-#define CTL_RESPONSE 0x0c
-#define CTL_STATUS 0x1c
-#define CTL_IRQ_MASK 0x20
-#define CTL_SD_CARD_CLK_CTL 0x24
-#define CTL_SD_XFER_LEN 0x26
-#define CTL_SD_MEM_CARD_OPT 0x28
-#define CTL_SD_ERROR_DETAIL_STATUS 0x2c
-#define CTL_SD_DATA_PORT 0x30
-#define CTL_TRANSACTION_CTL 0x34
-#define CTL_SDIO_STATUS 0x36
-#define CTL_SDIO_IRQ_MASK 0x38
-#define CTL_RESET_SD 0xe0
-#define CTL_SDIO_REGS 0x100
-#define CTL_CLK_AND_WAIT_CTL 0x138
-#define CTL_RESET_SDIO 0x1e0
-
-/* Definitions for values the CTRL_STATUS register can take. */
-#define TMIO_STAT_CMDRESPEND 0x00000001
-#define TMIO_STAT_DATAEND 0x00000004
-#define TMIO_STAT_CARD_REMOVE 0x00000008
-#define TMIO_STAT_CARD_INSERT 0x00000010
-#define TMIO_STAT_SIGSTATE 0x00000020
-#define TMIO_STAT_WRPROTECT 0x00000080
-#define TMIO_STAT_CARD_REMOVE_A 0x00000100
-#define TMIO_STAT_CARD_INSERT_A 0x00000200
-#define TMIO_STAT_SIGSTATE_A 0x00000400
-#define TMIO_STAT_CMD_IDX_ERR 0x00010000
-#define TMIO_STAT_CRCFAIL 0x00020000
-#define TMIO_STAT_STOPBIT_ERR 0x00040000
-#define TMIO_STAT_DATATIMEOUT 0x00080000
-#define TMIO_STAT_RXOVERFLOW 0x00100000
-#define TMIO_STAT_TXUNDERRUN 0x00200000
-#define TMIO_STAT_CMDTIMEOUT 0x00400000
-#define TMIO_STAT_RXRDY 0x01000000
-#define TMIO_STAT_TXRQ 0x02000000
-#define TMIO_STAT_ILL_FUNC 0x20000000
-#define TMIO_STAT_CMD_BUSY 0x40000000
-#define TMIO_STAT_ILL_ACCESS 0x80000000
-
-/* Definitions for values the CTRL_SDIO_STATUS register can take. */
-#define TMIO_SDIO_STAT_IOIRQ 0x0001
-#define TMIO_SDIO_STAT_EXPUB52 0x4000
-#define TMIO_SDIO_STAT_EXWT 0x8000
-#define TMIO_SDIO_MASK_ALL 0xc007
-
-/* Define some IRQ masks */
-/* This is the mask used at reset by the chip */
-#define TMIO_MASK_ALL 0x837f031d
-#define TMIO_MASK_READOP (TMIO_STAT_RXRDY | TMIO_STAT_DATAEND)
-#define TMIO_MASK_WRITEOP (TMIO_STAT_TXRQ | TMIO_STAT_DATAEND)
-#define TMIO_MASK_CMD (TMIO_STAT_CMDRESPEND | TMIO_STAT_CMDTIMEOUT | \
- TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT)
-#define TMIO_MASK_IRQ (TMIO_MASK_READOP | TMIO_MASK_WRITEOP | TMIO_MASK_CMD)
-
-#define TMIO_MIN_DMA_LEN 8
-
-#define enable_mmc_irqs(host, i) \
- do { \
- u32 mask;\
- mask = sd_ctrl_read32((host), CTL_IRQ_MASK); \
- mask &= ~((i) & TMIO_MASK_IRQ); \
- sd_ctrl_write32((host), CTL_IRQ_MASK, mask); \
- } while (0)
-
-#define disable_mmc_irqs(host, i) \
- do { \
- u32 mask;\
- mask = sd_ctrl_read32((host), CTL_IRQ_MASK); \
- mask |= ((i) & TMIO_MASK_IRQ); \
- sd_ctrl_write32((host), CTL_IRQ_MASK, mask); \
- } while (0)
-
-#define ack_mmc_irqs(host, i) \
- do { \
- sd_ctrl_write32((host), CTL_STATUS, ~(i)); \
- } while (0)
-
-/* This is arbitrary, just noone needed any higher alignment yet */
-#define MAX_ALIGN 4
-
-struct tmio_mmc_host {
- void __iomem *ctl;
- unsigned long bus_shift;
- struct mmc_command *cmd;
- struct mmc_request *mrq;
- struct mmc_data *data;
- struct mmc_host *mmc;
- int irq;
- unsigned int sdio_irq_enabled;
-
- /* Callbacks for clock / power control */
- void (*set_pwr)(struct platform_device *host, int state);
- void (*set_clk_div)(struct platform_device *host, int state);
-
- /* pio related stuff */
- struct scatterlist *sg_ptr;
- struct scatterlist *sg_orig;
- unsigned int sg_len;
- unsigned int sg_off;
-
- struct platform_device *pdev;
-
- /* DMA support */
- bool force_pio;
- struct dma_chan *chan_rx;
- struct dma_chan *chan_tx;
- struct tasklet_struct dma_complete;
- struct tasklet_struct dma_issue;
-#ifdef CONFIG_TMIO_MMC_DMA
- u8 bounce_buf[PAGE_CACHE_SIZE] __attribute__((aligned(MAX_ALIGN)));
- struct scatterlist bounce_sg;
-#endif
-
- /* Track lost interrupts */
- struct delayed_work delayed_reset_work;
- spinlock_t lock;
- unsigned long last_req_ts;
-};
-
-static void tmio_check_bounce_buffer(struct tmio_mmc_host *host);
-
-static u16 sd_ctrl_read16(struct tmio_mmc_host *host, int addr)
-{
- return readw(host->ctl + (addr << host->bus_shift));
-}
-
-static void sd_ctrl_read16_rep(struct tmio_mmc_host *host, int addr,
- u16 *buf, int count)
-{
- readsw(host->ctl + (addr << host->bus_shift), buf, count);
-}
-
-static u32 sd_ctrl_read32(struct tmio_mmc_host *host, int addr)
-{
- return readw(host->ctl + (addr << host->bus_shift)) |
- readw(host->ctl + ((addr + 2) << host->bus_shift)) << 16;
-}
-
-static void sd_ctrl_write16(struct tmio_mmc_host *host, int addr, u16 val)
-{
- writew(val, host->ctl + (addr << host->bus_shift));
-}
-
-static void sd_ctrl_write16_rep(struct tmio_mmc_host *host, int addr,
- u16 *buf, int count)
-{
- writesw(host->ctl + (addr << host->bus_shift), buf, count);
-}
-
-static void sd_ctrl_write32(struct tmio_mmc_host *host, int addr, u32 val)
-{
- writew(val, host->ctl + (addr << host->bus_shift));
- writew(val >> 16, host->ctl + ((addr + 2) << host->bus_shift));
-}
-
-static void tmio_mmc_init_sg(struct tmio_mmc_host *host, struct mmc_data *data)
-{
- host->sg_len = data->sg_len;
- host->sg_ptr = data->sg;
- host->sg_orig = data->sg;
- host->sg_off = 0;
-}
-
-static int tmio_mmc_next_sg(struct tmio_mmc_host *host)
-{
- host->sg_ptr = sg_next(host->sg_ptr);
- host->sg_off = 0;
- return --host->sg_len;
-}
-
-static char *tmio_mmc_kmap_atomic(struct scatterlist *sg, unsigned long *flags)
-{
- local_irq_save(*flags);
- return kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset;
-}
-
-static void tmio_mmc_kunmap_atomic(struct scatterlist *sg, unsigned long *flags, void *virt)
-{
- kunmap_atomic(virt - sg->offset, KM_BIO_SRC_IRQ);
- local_irq_restore(*flags);
-}
-
-#ifdef CONFIG_MMC_DEBUG
-
-#define STATUS_TO_TEXT(a, status, i) \
- do { \
- if (status & TMIO_STAT_##a) { \
- if (i++) \
- printk(" | "); \
- printk(#a); \
- } \
- } while (0)
-
-void pr_debug_status(u32 status)
-{
- int i = 0;
- printk(KERN_DEBUG "status: %08x = ", status);
- STATUS_TO_TEXT(CARD_REMOVE, status, i);
- STATUS_TO_TEXT(CARD_INSERT, status, i);
- STATUS_TO_TEXT(SIGSTATE, status, i);
- STATUS_TO_TEXT(WRPROTECT, status, i);
- STATUS_TO_TEXT(CARD_REMOVE_A, status, i);
- STATUS_TO_TEXT(CARD_INSERT_A, status, i);
- STATUS_TO_TEXT(SIGSTATE_A, status, i);
- STATUS_TO_TEXT(CMD_IDX_ERR, status, i);
- STATUS_TO_TEXT(STOPBIT_ERR, status, i);
- STATUS_TO_TEXT(ILL_FUNC, status, i);
- STATUS_TO_TEXT(CMD_BUSY, status, i);
- STATUS_TO_TEXT(CMDRESPEND, status, i);
- STATUS_TO_TEXT(DATAEND, status, i);
- STATUS_TO_TEXT(CRCFAIL, status, i);
- STATUS_TO_TEXT(DATATIMEOUT, status, i);
- STATUS_TO_TEXT(CMDTIMEOUT, status, i);
- STATUS_TO_TEXT(RXOVERFLOW, status, i);
- STATUS_TO_TEXT(TXUNDERRUN, status, i);
- STATUS_TO_TEXT(RXRDY, status, i);
- STATUS_TO_TEXT(TXRQ, status, i);
- STATUS_TO_TEXT(ILL_ACCESS, status, i);
- printk("\n");
-}
-
-#else
-#define pr_debug_status(s) do { } while (0)
-#endif
-
-static void tmio_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
-{
- struct tmio_mmc_host *host = mmc_priv(mmc);
-
- if (enable) {
- host->sdio_irq_enabled = 1;
- sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0001);
- sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK,
- (TMIO_SDIO_MASK_ALL & ~TMIO_SDIO_STAT_IOIRQ));
- } else {
- sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, TMIO_SDIO_MASK_ALL);
- sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0000);
- host->sdio_irq_enabled = 0;
- }
-}
-
-static void tmio_mmc_set_clock(struct tmio_mmc_host *host, int new_clock)
-{
- u32 clk = 0, clock;
-
- if (new_clock) {
- for (clock = host->mmc->f_min, clk = 0x80000080;
- new_clock >= (clock<<1); clk >>= 1)
- clock <<= 1;
- clk |= 0x100;
- }
-
- if (host->set_clk_div)
- host->set_clk_div(host->pdev, (clk>>22) & 1);
-
- sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk & 0x1ff);
-}
-
-static void tmio_mmc_clk_stop(struct tmio_mmc_host *host)
-{
- struct tmio_mmc_data *pdata = mfd_get_data(host->pdev);
-
- /*
- * Testing on sh-mobile showed that SDIO IRQs are unmasked when
- * CTL_CLK_AND_WAIT_CTL gets written, so we have to disable the
- * device IRQ here and restore the SDIO IRQ mask before
- * re-enabling the device IRQ.
- */
- if (pdata->flags & TMIO_MMC_SDIO_IRQ)
- disable_irq(host->irq);
- sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0000);
- msleep(10);
- if (pdata->flags & TMIO_MMC_SDIO_IRQ) {
- tmio_mmc_enable_sdio_irq(host->mmc, host->sdio_irq_enabled);
- enable_irq(host->irq);
- }
- sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~0x0100 &
- sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
- msleep(10);
-}
-
-static void tmio_mmc_clk_start(struct tmio_mmc_host *host)
-{
- struct tmio_mmc_data *pdata = mfd_get_data(host->pdev);
-
- sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, 0x0100 |
- sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
- msleep(10);
- /* see comment in tmio_mmc_clk_stop above */
- if (pdata->flags & TMIO_MMC_SDIO_IRQ)
- disable_irq(host->irq);
- sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0100);
- msleep(10);
- if (pdata->flags & TMIO_MMC_SDIO_IRQ) {
- tmio_mmc_enable_sdio_irq(host->mmc, host->sdio_irq_enabled);
- enable_irq(host->irq);
- }
-}
-
-static void reset(struct tmio_mmc_host *host)
-{
- /* FIXME - should we set stop clock reg here */
- sd_ctrl_write16(host, CTL_RESET_SD, 0x0000);
- sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0000);
- msleep(10);
- sd_ctrl_write16(host, CTL_RESET_SD, 0x0001);
- sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0001);
- msleep(10);
-}
-
-static void tmio_mmc_reset_work(struct work_struct *work)
-{
- struct tmio_mmc_host *host = container_of(work, struct tmio_mmc_host,
- delayed_reset_work.work);
- struct mmc_request *mrq;
- unsigned long flags;
-
- spin_lock_irqsave(&host->lock, flags);
- mrq = host->mrq;
-
- /* request already finished */
- if (!mrq
- || time_is_after_jiffies(host->last_req_ts +
- msecs_to_jiffies(2000))) {
- spin_unlock_irqrestore(&host->lock, flags);
- return;
- }
-
- dev_warn(&host->pdev->dev,
- "timeout waiting for hardware interrupt (CMD%u)\n",
- mrq->cmd->opcode);
-
- if (host->data)
- host->data->error = -ETIMEDOUT;
- else if (host->cmd)
- host->cmd->error = -ETIMEDOUT;
- else
- mrq->cmd->error = -ETIMEDOUT;
-
- host->cmd = NULL;
- host->data = NULL;
- host->mrq = NULL;
- host->force_pio = false;
-
- spin_unlock_irqrestore(&host->lock, flags);
- reset(host);
-
- mmc_request_done(host->mmc, mrq);
-}
-
-static void
-tmio_mmc_finish_request(struct tmio_mmc_host *host)
-{
- struct mmc_request *mrq = host->mrq;
-
- if (!mrq)
- return;
-
- host->mrq = NULL;
- host->cmd = NULL;
- host->data = NULL;
- host->force_pio = false;
-
- cancel_delayed_work(&host->delayed_reset_work);
-
- mmc_request_done(host->mmc, mrq);
-}
-
-/* These are the bitmasks the tmio chip requires to implement the MMC response
- * types. Note that R1 and R6 are the same in this scheme. */
-#define APP_CMD 0x0040
-#define RESP_NONE 0x0300
-#define RESP_R1 0x0400
-#define RESP_R1B 0x0500
-#define RESP_R2 0x0600
-#define RESP_R3 0x0700
-#define DATA_PRESENT 0x0800
-#define TRANSFER_READ 0x1000
-#define TRANSFER_MULTI 0x2000
-#define SECURITY_CMD 0x4000
-
-static int
-tmio_mmc_start_command(struct tmio_mmc_host *host, struct mmc_command *cmd)
-{
- struct mmc_data *data = host->data;
- int c = cmd->opcode;
-
- /* Command 12 is handled by hardware */
- if (cmd->opcode = 12 && !cmd->arg) {
- sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0x001);
- return 0;
- }
-
- switch (mmc_resp_type(cmd)) {
- case MMC_RSP_NONE: c |= RESP_NONE; break;
- case MMC_RSP_R1: c |= RESP_R1; break;
- case MMC_RSP_R1B: c |= RESP_R1B; break;
- case MMC_RSP_R2: c |= RESP_R2; break;
- case MMC_RSP_R3: c |= RESP_R3; break;
- default:
- pr_debug("Unknown response type %d\n", mmc_resp_type(cmd));
- return -EINVAL;
- }
-
- host->cmd = cmd;
-
-/* FIXME - this seems to be ok commented out but the spec suggest this bit
- * should be set when issuing app commands.
- * if(cmd->flags & MMC_FLAG_ACMD)
- * c |= APP_CMD;
- */
- if (data) {
- c |= DATA_PRESENT;
- if (data->blocks > 1) {
- sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0x100);
- c |= TRANSFER_MULTI;
- }
- if (data->flags & MMC_DATA_READ)
- c |= TRANSFER_READ;
- }
-
- enable_mmc_irqs(host, TMIO_MASK_CMD);
-
- /* Fire off the command */
- sd_ctrl_write32(host, CTL_ARG_REG, cmd->arg);
- sd_ctrl_write16(host, CTL_SD_CMD, c);
-
- return 0;
-}
-
-/*
- * This chip always returns (at least?) as much data as you ask for.
- * I'm unsure what happens if you ask for less than a block. This should be
- * looked into to ensure that a funny length read doesnt hose the controller.
- */
-static void tmio_mmc_pio_irq(struct tmio_mmc_host *host)
-{
- struct mmc_data *data = host->data;
- void *sg_virt;
- unsigned short *buf;
- unsigned int count;
- unsigned long flags;
-
- if ((host->chan_tx || host->chan_rx) && !host->force_pio) {
- pr_err("PIO IRQ in DMA mode!\n");
- return;
- } else if (!data) {
- pr_debug("Spurious PIO IRQ\n");
- return;
- }
-
- sg_virt = tmio_mmc_kmap_atomic(host->sg_ptr, &flags);
- buf = (unsigned short *)(sg_virt + host->sg_off);
-
- count = host->sg_ptr->length - host->sg_off;
- if (count > data->blksz)
- count = data->blksz;
-
- pr_debug("count: %08x offset: %08x flags %08x\n",
- count, host->sg_off, data->flags);
-
- /* Transfer the data */
- if (data->flags & MMC_DATA_READ)
- sd_ctrl_read16_rep(host, CTL_SD_DATA_PORT, buf, count >> 1);
- else
- sd_ctrl_write16_rep(host, CTL_SD_DATA_PORT, buf, count >> 1);
-
- host->sg_off += count;
-
- tmio_mmc_kunmap_atomic(host->sg_ptr, &flags, sg_virt);
-
- if (host->sg_off = host->sg_ptr->length)
- tmio_mmc_next_sg(host);
-
- return;
-}
-
-/* needs to be called with host->lock held */
-static void tmio_mmc_do_data_irq(struct tmio_mmc_host *host)
-{
- struct mmc_data *data = host->data;
- struct mmc_command *stop;
-
- host->data = NULL;
-
- if (!data) {
- dev_warn(&host->pdev->dev, "Spurious data end IRQ\n");
- return;
- }
- stop = data->stop;
-
- /* FIXME - return correct transfer count on errors */
- if (!data->error)
- data->bytes_xfered = data->blocks * data->blksz;
- else
- data->bytes_xfered = 0;
-
- pr_debug("Completed data request\n");
-
- /*
- * FIXME: other drivers allow an optional stop command of any given type
- * which we dont do, as the chip can auto generate them.
- * Perhaps we can be smarter about when to use auto CMD12 and
- * only issue the auto request when we know this is the desired
- * stop command, allowing fallback to the stop command the
- * upper layers expect. For now, we do what works.
- */
-
- if (data->flags & MMC_DATA_READ) {
- if (host->chan_rx && !host->force_pio)
- tmio_check_bounce_buffer(host);
- dev_dbg(&host->pdev->dev, "Complete Rx request %p\n",
- host->mrq);
- } else {
- dev_dbg(&host->pdev->dev, "Complete Tx request %p\n",
- host->mrq);
- }
-
- if (stop) {
- if (stop->opcode = 12 && !stop->arg)
- sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0x000);
- else
- BUG();
- }
-
- tmio_mmc_finish_request(host);
-}
-
-static void tmio_mmc_data_irq(struct tmio_mmc_host *host)
-{
- struct mmc_data *data;
- spin_lock(&host->lock);
- data = host->data;
-
- if (!data)
- goto out;
-
- if (host->chan_tx && (data->flags & MMC_DATA_WRITE) && !host->force_pio) {
- /*
- * Has all data been written out yet? Testing on SuperH showed,
- * that in most cases the first interrupt comes already with the
- * BUSY status bit clear, but on some operations, like mount or
- * in the beginning of a write / sync / umount, there is one
- * DATAEND interrupt with the BUSY bit set, in this cases
- * waiting for one more interrupt fixes the problem.
- */
- if (!(sd_ctrl_read32(host, CTL_STATUS) & TMIO_STAT_CMD_BUSY)) {
- disable_mmc_irqs(host, TMIO_STAT_DATAEND);
- tasklet_schedule(&host->dma_complete);
- }
- } else if (host->chan_rx && (data->flags & MMC_DATA_READ) && !host->force_pio) {
- disable_mmc_irqs(host, TMIO_STAT_DATAEND);
- tasklet_schedule(&host->dma_complete);
- } else {
- tmio_mmc_do_data_irq(host);
- disable_mmc_irqs(host, TMIO_MASK_READOP | TMIO_MASK_WRITEOP);
- }
-out:
- spin_unlock(&host->lock);
-}
-
-static void tmio_mmc_cmd_irq(struct tmio_mmc_host *host,
- unsigned int stat)
-{
- struct mmc_command *cmd = host->cmd;
- int i, addr;
-
- spin_lock(&host->lock);
-
- if (!host->cmd) {
- pr_debug("Spurious CMD irq\n");
- goto out;
- }
-
- host->cmd = NULL;
-
- /* This controller is sicker than the PXA one. Not only do we need to
- * drop the top 8 bits of the first response word, we also need to
- * modify the order of the response for short response command types.
- */
-
- for (i = 3, addr = CTL_RESPONSE ; i >= 0 ; i--, addr += 4)
- cmd->resp[i] = sd_ctrl_read32(host, addr);
-
- if (cmd->flags & MMC_RSP_136) {
- cmd->resp[0] = (cmd->resp[0] << 8) | (cmd->resp[1] >> 24);
- cmd->resp[1] = (cmd->resp[1] << 8) | (cmd->resp[2] >> 24);
- cmd->resp[2] = (cmd->resp[2] << 8) | (cmd->resp[3] >> 24);
- cmd->resp[3] <<= 8;
- } else if (cmd->flags & MMC_RSP_R3) {
- cmd->resp[0] = cmd->resp[3];
- }
-
- if (stat & TMIO_STAT_CMDTIMEOUT)
- cmd->error = -ETIMEDOUT;
- else if (stat & TMIO_STAT_CRCFAIL && cmd->flags & MMC_RSP_CRC)
- cmd->error = -EILSEQ;
-
- /* If there is data to handle we enable data IRQs here, and
- * we will ultimatley finish the request in the data_end handler.
- * If theres no data or we encountered an error, finish now.
- */
- if (host->data && !cmd->error) {
- if (host->data->flags & MMC_DATA_READ) {
- if (host->force_pio || !host->chan_rx)
- enable_mmc_irqs(host, TMIO_MASK_READOP);
- else
- tasklet_schedule(&host->dma_issue);
- } else {
- if (host->force_pio || !host->chan_tx)
- enable_mmc_irqs(host, TMIO_MASK_WRITEOP);
- else
- tasklet_schedule(&host->dma_issue);
- }
- } else {
- tmio_mmc_finish_request(host);
- }
-
-out:
- spin_unlock(&host->lock);
-
- return;
-}
-
-static irqreturn_t tmio_mmc_irq(int irq, void *devid)
-{
- struct tmio_mmc_host *host = devid;
- struct tmio_mmc_data *pdata = mfd_get_data(host->pdev);
- unsigned int ireg, irq_mask, status;
- unsigned int sdio_ireg, sdio_irq_mask, sdio_status;
-
- pr_debug("MMC IRQ begin\n");
-
- status = sd_ctrl_read32(host, CTL_STATUS);
- irq_mask = sd_ctrl_read32(host, CTL_IRQ_MASK);
- ireg = status & TMIO_MASK_IRQ & ~irq_mask;
-
- sdio_ireg = 0;
- if (!ireg && pdata->flags & TMIO_MMC_SDIO_IRQ) {
- sdio_status = sd_ctrl_read16(host, CTL_SDIO_STATUS);
- sdio_irq_mask = sd_ctrl_read16(host, CTL_SDIO_IRQ_MASK);
- sdio_ireg = sdio_status & TMIO_SDIO_MASK_ALL & ~sdio_irq_mask;
-
- sd_ctrl_write16(host, CTL_SDIO_STATUS, sdio_status & ~TMIO_SDIO_MASK_ALL);
-
- if (sdio_ireg && !host->sdio_irq_enabled) {
- pr_warning("tmio_mmc: Spurious SDIO IRQ, disabling! 0x%04x 0x%04x 0x%04x\n",
- sdio_status, sdio_irq_mask, sdio_ireg);
- tmio_mmc_enable_sdio_irq(host->mmc, 0);
- goto out;
- }
-
- if (host->mmc->caps & MMC_CAP_SDIO_IRQ &&
- sdio_ireg & TMIO_SDIO_STAT_IOIRQ)
- mmc_signal_sdio_irq(host->mmc);
-
- if (sdio_ireg)
- goto out;
- }
-
- pr_debug_status(status);
- pr_debug_status(ireg);
-
- if (!ireg) {
- disable_mmc_irqs(host, status & ~irq_mask);
-
- pr_warning("tmio_mmc: Spurious irq, disabling! "
- "0x%08x 0x%08x 0x%08x\n", status, irq_mask, ireg);
- pr_debug_status(status);
-
- goto out;
- }
-
- while (ireg) {
- /* Card insert / remove attempts */
- if (ireg & (TMIO_STAT_CARD_INSERT | TMIO_STAT_CARD_REMOVE)) {
- ack_mmc_irqs(host, TMIO_STAT_CARD_INSERT |
- TMIO_STAT_CARD_REMOVE);
- mmc_detect_change(host->mmc, msecs_to_jiffies(100));
- }
-
- /* CRC and other errors */
-/* if (ireg & TMIO_STAT_ERR_IRQ)
- * handled |= tmio_error_irq(host, irq, stat);
- */
-
- /* Command completion */
- if (ireg & (TMIO_STAT_CMDRESPEND | TMIO_STAT_CMDTIMEOUT)) {
- ack_mmc_irqs(host,
- TMIO_STAT_CMDRESPEND |
- TMIO_STAT_CMDTIMEOUT);
- tmio_mmc_cmd_irq(host, status);
- }
-
- /* Data transfer */
- if (ireg & (TMIO_STAT_RXRDY | TMIO_STAT_TXRQ)) {
- ack_mmc_irqs(host, TMIO_STAT_RXRDY | TMIO_STAT_TXRQ);
- tmio_mmc_pio_irq(host);
- }
-
- /* Data transfer completion */
- if (ireg & TMIO_STAT_DATAEND) {
- ack_mmc_irqs(host, TMIO_STAT_DATAEND);
- tmio_mmc_data_irq(host);
- }
-
- /* Check status - keep going until we've handled it all */
- status = sd_ctrl_read32(host, CTL_STATUS);
- irq_mask = sd_ctrl_read32(host, CTL_IRQ_MASK);
- ireg = status & TMIO_MASK_IRQ & ~irq_mask;
-
- pr_debug("Status at end of loop: %08x\n", status);
- pr_debug_status(status);
- }
- pr_debug("MMC IRQ end\n");
-
-out:
- return IRQ_HANDLED;
-}
-
-#ifdef CONFIG_TMIO_MMC_DMA
-static void tmio_check_bounce_buffer(struct tmio_mmc_host *host)
-{
- if (host->sg_ptr = &host->bounce_sg) {
- unsigned long flags;
- void *sg_vaddr = tmio_mmc_kmap_atomic(host->sg_orig, &flags);
- memcpy(sg_vaddr, host->bounce_buf, host->bounce_sg.length);
- tmio_mmc_kunmap_atomic(host->sg_orig, &flags, sg_vaddr);
- }
-}
-
-static void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable)
-{
-#if defined(CONFIG_SUPERH) || defined(CONFIG_ARCH_SHMOBILE)
- /* Switch DMA mode on or off - SuperH specific? */
- sd_ctrl_write16(host, 0xd8, enable ? 2 : 0);
-#endif
-}
-
-static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host)
-{
- struct scatterlist *sg = host->sg_ptr, *sg_tmp;
- struct dma_async_tx_descriptor *desc = NULL;
- struct dma_chan *chan = host->chan_rx;
- struct tmio_mmc_data *pdata = mfd_get_data(host->pdev);
- dma_cookie_t cookie;
- int ret, i;
- bool aligned = true, multiple = true;
- unsigned int align = (1 << pdata->dma->alignment_shift) - 1;
-
- for_each_sg(sg, sg_tmp, host->sg_len, i) {
- if (sg_tmp->offset & align)
- aligned = false;
- if (sg_tmp->length & align) {
- multiple = false;
- break;
- }
- }
-
- if ((!aligned && (host->sg_len > 1 || sg->length > PAGE_CACHE_SIZE ||
- align >= MAX_ALIGN)) || !multiple) {
- ret = -EINVAL;
- goto pio;
- }
-
- if (sg->length < TMIO_MIN_DMA_LEN) {
- host->force_pio = true;
- return;
- }
-
- disable_mmc_irqs(host, TMIO_STAT_RXRDY);
-
- /* The only sg element can be unaligned, use our bounce buffer then */
- if (!aligned) {
- sg_init_one(&host->bounce_sg, host->bounce_buf, sg->length);
- host->sg_ptr = &host->bounce_sg;
- sg = host->sg_ptr;
- }
-
- ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_FROM_DEVICE);
- if (ret > 0)
- desc = chan->device->device_prep_slave_sg(chan, sg, ret,
- DMA_FROM_DEVICE, DMA_CTRL_ACK);
-
- if (desc)
- cookie = dmaengine_submit(desc);
-
- dev_dbg(&host->pdev->dev, "%s(): mapped %d -> %d, cookie %d, rq %p\n",
- __func__, host->sg_len, ret, cookie, host->mrq);
-
-pio:
- if (!desc) {
- /* DMA failed, fall back to PIO */
- if (ret >= 0)
- ret = -EIO;
- host->chan_rx = NULL;
- dma_release_channel(chan);
- /* Free the Tx channel too */
- chan = host->chan_tx;
- if (chan) {
- host->chan_tx = NULL;
- dma_release_channel(chan);
- }
- dev_warn(&host->pdev->dev,
- "DMA failed: %d, falling back to PIO\n", ret);
- tmio_mmc_enable_dma(host, false);
- }
-
- dev_dbg(&host->pdev->dev, "%s(): desc %p, cookie %d, sg[%d]\n", __func__,
- desc, cookie, host->sg_len);
-}
-
-static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host)
-{
- struct scatterlist *sg = host->sg_ptr, *sg_tmp;
- struct dma_async_tx_descriptor *desc = NULL;
- struct dma_chan *chan = host->chan_tx;
- struct tmio_mmc_data *pdata = mfd_get_data(host->pdev);
- dma_cookie_t cookie;
- int ret, i;
- bool aligned = true, multiple = true;
- unsigned int align = (1 << pdata->dma->alignment_shift) - 1;
-
- for_each_sg(sg, sg_tmp, host->sg_len, i) {
- if (sg_tmp->offset & align)
- aligned = false;
- if (sg_tmp->length & align) {
- multiple = false;
- break;
- }
- }
-
- if ((!aligned && (host->sg_len > 1 || sg->length > PAGE_CACHE_SIZE ||
- align >= MAX_ALIGN)) || !multiple) {
- ret = -EINVAL;
- goto pio;
- }
-
- if (sg->length < TMIO_MIN_DMA_LEN) {
- host->force_pio = true;
- return;
- }
-
- disable_mmc_irqs(host, TMIO_STAT_TXRQ);
-
- /* The only sg element can be unaligned, use our bounce buffer then */
- if (!aligned) {
- unsigned long flags;
- void *sg_vaddr = tmio_mmc_kmap_atomic(sg, &flags);
- sg_init_one(&host->bounce_sg, host->bounce_buf, sg->length);
- memcpy(host->bounce_buf, sg_vaddr, host->bounce_sg.length);
- tmio_mmc_kunmap_atomic(sg, &flags, sg_vaddr);
- host->sg_ptr = &host->bounce_sg;
- sg = host->sg_ptr;
- }
-
- ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_TO_DEVICE);
- if (ret > 0)
- desc = chan->device->device_prep_slave_sg(chan, sg, ret,
- DMA_TO_DEVICE, DMA_CTRL_ACK);
-
- if (desc)
- cookie = dmaengine_submit(desc);
-
- dev_dbg(&host->pdev->dev, "%s(): mapped %d -> %d, cookie %d, rq %p\n",
- __func__, host->sg_len, ret, cookie, host->mrq);
-
-pio:
- if (!desc) {
- /* DMA failed, fall back to PIO */
- if (ret >= 0)
- ret = -EIO;
- host->chan_tx = NULL;
- dma_release_channel(chan);
- /* Free the Rx channel too */
- chan = host->chan_rx;
- if (chan) {
- host->chan_rx = NULL;
- dma_release_channel(chan);
- }
- dev_warn(&host->pdev->dev,
- "DMA failed: %d, falling back to PIO\n", ret);
- tmio_mmc_enable_dma(host, false);
- }
-
- dev_dbg(&host->pdev->dev, "%s(): desc %p, cookie %d\n", __func__,
- desc, cookie);
-}
-
-static void tmio_mmc_start_dma(struct tmio_mmc_host *host,
- struct mmc_data *data)
-{
- if (data->flags & MMC_DATA_READ) {
- if (host->chan_rx)
- tmio_mmc_start_dma_rx(host);
- } else {
- if (host->chan_tx)
- tmio_mmc_start_dma_tx(host);
- }
-}
-
-static void tmio_issue_tasklet_fn(unsigned long priv)
-{
- struct tmio_mmc_host *host = (struct tmio_mmc_host *)priv;
- struct dma_chan *chan = NULL;
-
- spin_lock_irq(&host->lock);
-
- if (host && host->data) {
- if (host->data->flags & MMC_DATA_READ)
- chan = host->chan_rx;
- else
- chan = host->chan_tx;
- }
-
- spin_unlock_irq(&host->lock);
-
- enable_mmc_irqs(host, TMIO_STAT_DATAEND);
-
- if (chan)
- dma_async_issue_pending(chan);
-}
-
-static void tmio_tasklet_fn(unsigned long arg)
-{
- struct tmio_mmc_host *host = (struct tmio_mmc_host *)arg;
-
- spin_lock_irq(&host->lock);
-
- if (!host->data)
- goto out;
-
- if (host->data->flags & MMC_DATA_READ)
- dma_unmap_sg(host->chan_rx->device->dev,
- host->sg_ptr, host->sg_len,
- DMA_FROM_DEVICE);
- else
- dma_unmap_sg(host->chan_tx->device->dev,
- host->sg_ptr, host->sg_len,
- DMA_TO_DEVICE);
-
- tmio_mmc_do_data_irq(host);
-out:
- spin_unlock_irq(&host->lock);
-}
-
-/* It might be necessary to make filter MFD specific */
-static bool tmio_mmc_filter(struct dma_chan *chan, void *arg)
-{
- dev_dbg(chan->device->dev, "%s: slave data %p\n", __func__, arg);
- chan->private = arg;
- return true;
-}
-
-static void tmio_mmc_request_dma(struct tmio_mmc_host *host,
- struct tmio_mmc_data *pdata)
-{
- /* We can only either use DMA for both Tx and Rx or not use it at all */
- if (pdata->dma) {
- dma_cap_mask_t mask;
-
- dma_cap_zero(mask);
- dma_cap_set(DMA_SLAVE, mask);
-
- host->chan_tx = dma_request_channel(mask, tmio_mmc_filter,
- pdata->dma->chan_priv_tx);
- dev_dbg(&host->pdev->dev, "%s: TX: got channel %p\n", __func__,
- host->chan_tx);
-
- if (!host->chan_tx)
- return;
-
- host->chan_rx = dma_request_channel(mask, tmio_mmc_filter,
- pdata->dma->chan_priv_rx);
- dev_dbg(&host->pdev->dev, "%s: RX: got channel %p\n", __func__,
- host->chan_rx);
-
- if (!host->chan_rx) {
- dma_release_channel(host->chan_tx);
- host->chan_tx = NULL;
- return;
- }
-
- tasklet_init(&host->dma_complete, tmio_tasklet_fn, (unsigned long)host);
- tasklet_init(&host->dma_issue, tmio_issue_tasklet_fn, (unsigned long)host);
-
- tmio_mmc_enable_dma(host, true);
- }
-}
-
-static void tmio_mmc_release_dma(struct tmio_mmc_host *host)
-{
- if (host->chan_tx) {
- struct dma_chan *chan = host->chan_tx;
- host->chan_tx = NULL;
- dma_release_channel(chan);
- }
- if (host->chan_rx) {
- struct dma_chan *chan = host->chan_rx;
- host->chan_rx = NULL;
- dma_release_channel(chan);
- }
-}
-#else
-static void tmio_check_bounce_buffer(struct tmio_mmc_host *host)
-{
-}
-
-static void tmio_mmc_start_dma(struct tmio_mmc_host *host,
- struct mmc_data *data)
-{
-}
-
-static void tmio_mmc_request_dma(struct tmio_mmc_host *host,
- struct tmio_mmc_data *pdata)
-{
- host->chan_tx = NULL;
- host->chan_rx = NULL;
-}
-
-static void tmio_mmc_release_dma(struct tmio_mmc_host *host)
-{
-}
-#endif
-
-static int tmio_mmc_start_data(struct tmio_mmc_host *host,
- struct mmc_data *data)
-{
- struct tmio_mmc_data *pdata = mfd_get_data(host->pdev);
-
- pr_debug("setup data transfer: blocksize %08x nr_blocks %d\n",
- data->blksz, data->blocks);
-
- /* Some hardware cannot perform 2 byte requests in 4 bit mode */
- if (host->mmc->ios.bus_width = MMC_BUS_WIDTH_4) {
- int blksz_2bytes = pdata->flags & TMIO_MMC_BLKSZ_2BYTES;
-
- if (data->blksz < 2 || (data->blksz < 4 && !blksz_2bytes)) {
- pr_err("%s: %d byte block unsupported in 4 bit mode\n",
- mmc_hostname(host->mmc), data->blksz);
- return -EINVAL;
- }
- }
-
- tmio_mmc_init_sg(host, data);
- host->data = data;
-
- /* Set transfer length / blocksize */
- sd_ctrl_write16(host, CTL_SD_XFER_LEN, data->blksz);
- sd_ctrl_write16(host, CTL_XFER_BLK_COUNT, data->blocks);
-
- tmio_mmc_start_dma(host, data);
-
- return 0;
-}
-
-/* Process requests from the MMC layer */
-static void tmio_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
-{
- struct tmio_mmc_host *host = mmc_priv(mmc);
- int ret;
-
- if (host->mrq)
- pr_debug("request not null\n");
-
- host->last_req_ts = jiffies;
- wmb();
- host->mrq = mrq;
-
- if (mrq->data) {
- ret = tmio_mmc_start_data(host, mrq->data);
- if (ret)
- goto fail;
- }
-
- ret = tmio_mmc_start_command(host, mrq->cmd);
- if (!ret) {
- schedule_delayed_work(&host->delayed_reset_work,
- msecs_to_jiffies(2000));
- return;
- }
-
-fail:
- host->mrq = NULL;
- host->force_pio = false;
- mrq->cmd->error = ret;
- mmc_request_done(mmc, mrq);
-}
-
-/* Set MMC clock / power.
- * Note: This controller uses a simple divider scheme therefore it cannot
- * run a MMC card at full speed (20MHz). The max clock is 24MHz on SD, but as
- * MMC wont run that fast, it has to be clocked at 12MHz which is the next
- * slowest setting.
- */
-static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
- struct tmio_mmc_host *host = mmc_priv(mmc);
-
- if (ios->clock)
- tmio_mmc_set_clock(host, ios->clock);
-
- /* Power sequence - OFF -> ON -> UP */
- switch (ios->power_mode) {
- case MMC_POWER_OFF: /* power down SD bus */
- if (host->set_pwr)
- host->set_pwr(host->pdev, 0);
- tmio_mmc_clk_stop(host);
- break;
- case MMC_POWER_ON: /* power up SD bus */
- if (host->set_pwr)
- host->set_pwr(host->pdev, 1);
- break;
- case MMC_POWER_UP: /* start bus clock */
- tmio_mmc_clk_start(host);
- break;
- }
-
- switch (ios->bus_width) {
- case MMC_BUS_WIDTH_1:
- sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x80e0);
- break;
- case MMC_BUS_WIDTH_4:
- sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x00e0);
- break;
- }
-
- /* Let things settle. delay taken from winCE driver */
- udelay(140);
-}
-
-static int tmio_mmc_get_ro(struct mmc_host *mmc)
-{
- struct tmio_mmc_host *host = mmc_priv(mmc);
- struct tmio_mmc_data *pdata = mfd_get_data(host->pdev);
-
- return ((pdata->flags & TMIO_MMC_WRPROTECT_DISABLE) ||
- (sd_ctrl_read32(host, CTL_STATUS) & TMIO_STAT_WRPROTECT)) ? 0 : 1;
-}
-
-static int tmio_mmc_get_cd(struct mmc_host *mmc)
-{
- struct tmio_mmc_host *host = mmc_priv(mmc);
- struct tmio_mmc_data *pdata = mfd_get_data(host->pdev);
-
- if (!pdata->get_cd)
- return -ENOSYS;
- else
- return pdata->get_cd(host->pdev);
-}
-
-static const struct mmc_host_ops tmio_mmc_ops = {
- .request = tmio_mmc_request,
- .set_ios = tmio_mmc_set_ios,
- .get_ro = tmio_mmc_get_ro,
- .get_cd = tmio_mmc_get_cd,
- .enable_sdio_irq = tmio_mmc_enable_sdio_irq,
-};
+#include "tmio_mmc.h"
#ifdef CONFIG_PM
static int tmio_mmc_suspend(struct platform_device *dev, pm_message_t state)
@@ -1245,138 +62,54 @@ out:
#define tmio_mmc_resume NULL
#endif
-static int __devinit tmio_mmc_probe(struct platform_device *dev)
+static int __devinit tmio_mmc_probe(struct platform_device *pdev)
{
- const struct mfd_cell *cell = mfd_get_cell(dev);
+ const struct mfd_cell *cell = mfd_get_cell(pdev);
struct tmio_mmc_data *pdata;
- struct resource *res_ctl;
struct tmio_mmc_host *host;
- struct mmc_host *mmc;
int ret = -EINVAL;
- u32 irq_mask = TMIO_MASK_CMD;
- if (dev->num_resources != 2)
+ if (pdev->num_resources != 2)
goto out;
- res_ctl = platform_get_resource(dev, IORESOURCE_MEM, 0);
- if (!res_ctl)
- goto out;
-
- pdata = mfd_get_data(dev);
+ pdata = mfd_get_data(pdev);
if (!pdata || !pdata->hclk)
goto out;
- ret = -ENOMEM;
-
- mmc = mmc_alloc_host(sizeof(struct tmio_mmc_host), &dev->dev);
- if (!mmc)
- goto out;
-
- host = mmc_priv(mmc);
- host->mmc = mmc;
- host->pdev = dev;
- platform_set_drvdata(dev, mmc);
-
- host->set_pwr = pdata->set_pwr;
- host->set_clk_div = pdata->set_clk_div;
-
- /* SD control register space size is 0x200, 0x400 for bus_shift=1 */
- host->bus_shift = resource_size(res_ctl) >> 10;
-
- host->ctl = ioremap(res_ctl->start, resource_size(res_ctl));
- if (!host->ctl)
- goto host_free;
-
- mmc->ops = &tmio_mmc_ops;
- mmc->caps = MMC_CAP_4_BIT_DATA | pdata->capabilities;
- mmc->f_max = pdata->hclk;
- mmc->f_min = mmc->f_max / 512;
- mmc->max_segs = 32;
- mmc->max_blk_size = 512;
- mmc->max_blk_count = (PAGE_CACHE_SIZE / mmc->max_blk_size) *
- mmc->max_segs;
- mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
- mmc->max_seg_size = mmc->max_req_size;
- if (pdata->ocr_mask)
- mmc->ocr_avail = pdata->ocr_mask;
- else
- mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
-
/* Tell the MFD core we are ready to be enabled */
if (cell->enable) {
- ret = cell->enable(dev);
+ ret = cell->enable(pdev);
if (ret)
- goto unmap_ctl;
+ goto out;
}
- tmio_mmc_clk_stop(host);
- reset(host);
-
- ret = platform_get_irq(dev, 0);
- if (ret >= 0)
- host->irq = ret;
- else
- goto cell_disable;
-
- disable_mmc_irqs(host, TMIO_MASK_ALL);
- if (pdata->flags & TMIO_MMC_SDIO_IRQ)
- tmio_mmc_enable_sdio_irq(mmc, 0);
-
- ret = request_irq(host->irq, tmio_mmc_irq, IRQF_DISABLED |
- IRQF_TRIGGER_FALLING, dev_name(&dev->dev), host);
+ ret = tmio_mmc_host_probe(&host, pdev, pdata);
if (ret)
goto cell_disable;
- spin_lock_init(&host->lock);
-
- /* Init delayed work for request timeouts */
- INIT_DELAYED_WORK(&host->delayed_reset_work, tmio_mmc_reset_work);
-
- /* See if we also get DMA */
- tmio_mmc_request_dma(host, pdata);
-
- mmc_add_host(mmc);
-
pr_info("%s at 0x%08lx irq %d\n", mmc_hostname(host->mmc),
(unsigned long)host->ctl, host->irq);
- /* Unmask the IRQs we want to know about */
- if (!host->chan_rx)
- irq_mask |= TMIO_MASK_READOP;
- if (!host->chan_tx)
- irq_mask |= TMIO_MASK_WRITEOP;
- enable_mmc_irqs(host, irq_mask);
-
return 0;
cell_disable:
if (cell->disable)
- cell->disable(dev);
-unmap_ctl:
- iounmap(host->ctl);
-host_free:
- mmc_free_host(mmc);
+ cell->disable(pdev);
out:
return ret;
}
-static int __devexit tmio_mmc_remove(struct platform_device *dev)
+static int __devexit tmio_mmc_remove(struct platform_device *pdev)
{
- const struct mfd_cell *cell = mfd_get_cell(dev);
- struct mmc_host *mmc = platform_get_drvdata(dev);
+ const struct mfd_cell *cell = mfd_get_cell(pdev);
+ struct mmc_host *mmc = platform_get_drvdata(pdev);
- platform_set_drvdata(dev, NULL);
+ platform_set_drvdata(pdev, NULL);
if (mmc) {
- struct tmio_mmc_host *host = mmc_priv(mmc);
- mmc_remove_host(mmc);
- cancel_delayed_work_sync(&host->delayed_reset_work);
- tmio_mmc_release_dma(host);
- free_irq(host->irq, host);
+ tmio_mmc_host_remove(mmc_priv(mmc));
if (cell->disable)
- cell->disable(dev);
- iounmap(host->ctl);
- mmc_free_host(mmc);
+ cell->disable(pdev);
}
return 0;
diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h
new file mode 100644
index 0000000..8ae936b
--- /dev/null
+++ b/drivers/mmc/host/tmio_mmc.h
@@ -0,0 +1,152 @@
+/*
+ * linux/drivers/mmc/host/tmio_mmc.h
+ *
+ * Copyright (C) 2007 Ian Molton
+ * Copyright (C) 2004 Ian Molton
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Driver for the MMC / SD / SDIO cell found in:
+ *
+ * TC6393XB TC6391XB TC6387XB T7L66XB ASIC3
+ */
+
+#ifndef TMIO_MMC_H
+#define TMIO_MMC_H
+
+#include <linux/highmem.h>
+#include <linux/pagemap.h>
+
+/* Definitions for values the CTRL_STATUS register can take. */
+#define TMIO_STAT_CMDRESPEND 0x00000001
+#define TMIO_STAT_DATAEND 0x00000004
+#define TMIO_STAT_CARD_REMOVE 0x00000008
+#define TMIO_STAT_CARD_INSERT 0x00000010
+#define TMIO_STAT_SIGSTATE 0x00000020
+#define TMIO_STAT_WRPROTECT 0x00000080
+#define TMIO_STAT_CARD_REMOVE_A 0x00000100
+#define TMIO_STAT_CARD_INSERT_A 0x00000200
+#define TMIO_STAT_SIGSTATE_A 0x00000400
+#define TMIO_STAT_CMD_IDX_ERR 0x00010000
+#define TMIO_STAT_CRCFAIL 0x00020000
+#define TMIO_STAT_STOPBIT_ERR 0x00040000
+#define TMIO_STAT_DATATIMEOUT 0x00080000
+#define TMIO_STAT_RXOVERFLOW 0x00100000
+#define TMIO_STAT_TXUNDERRUN 0x00200000
+#define TMIO_STAT_CMDTIMEOUT 0x00400000
+#define TMIO_STAT_RXRDY 0x01000000
+#define TMIO_STAT_TXRQ 0x02000000
+#define TMIO_STAT_ILL_FUNC 0x20000000
+#define TMIO_STAT_CMD_BUSY 0x40000000
+#define TMIO_STAT_ILL_ACCESS 0x80000000
+
+/* Definitions for values the CTRL_SDIO_STATUS register can take. */
+#define TMIO_SDIO_STAT_IOIRQ 0x0001
+#define TMIO_SDIO_STAT_EXPUB52 0x4000
+#define TMIO_SDIO_STAT_EXWT 0x8000
+#define TMIO_SDIO_MASK_ALL 0xc007
+
+/* Define some IRQ masks */
+/* This is the mask used at reset by the chip */
+#define TMIO_MASK_ALL 0x837f031d
+#define TMIO_MASK_READOP (TMIO_STAT_RXRDY | TMIO_STAT_DATAEND)
+#define TMIO_MASK_WRITEOP (TMIO_STAT_TXRQ | TMIO_STAT_DATAEND)
+#define TMIO_MASK_CMD (TMIO_STAT_CMDRESPEND | TMIO_STAT_CMDTIMEOUT | \
+ TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT)
+#define TMIO_MASK_IRQ (TMIO_MASK_READOP | TMIO_MASK_WRITEOP | TMIO_MASK_CMD)
+
+/* This is arbitrary, just noone needed any higher alignment yet */
+#define TMIO_MAX_ALIGN 4
+
+struct tmio_mmc_data;
+
+struct tmio_mmc_host {
+ void __iomem *ctl;
+ unsigned long bus_shift;
+ struct mmc_command *cmd;
+ struct mmc_request *mrq;
+ struct mmc_data *data;
+ struct mmc_host *mmc;
+ int irq;
+ unsigned int sdio_irq_enabled;
+
+ /* Callbacks for clock / power control */
+ void (*set_pwr)(struct platform_device *host, int state);
+ void (*set_clk_div)(struct platform_device *host, int state);
+
+ /* pio related stuff */
+ struct scatterlist *sg_ptr;
+ struct scatterlist *sg_orig;
+ unsigned int sg_len;
+ unsigned int sg_off;
+
+ struct platform_device *pdev;
+ struct tmio_mmc_data *pdata;
+
+ /* DMA support */
+ bool force_pio;
+ struct dma_chan *chan_rx;
+ struct dma_chan *chan_tx;
+ struct tasklet_struct dma_complete;
+ struct tasklet_struct dma_issue;
+ struct scatterlist bounce_sg;
+#ifdef CONFIG_TMIO_MMC_DMA
+ u8 bounce_buf[PAGE_CACHE_SIZE] __attribute__((aligned(TMIO_MAX_ALIGN)));
+#else
+ u8 bounce_buf[1]; /* A dummy in no-DMA case */
+#endif
+
+ /* Track lost interrupts */
+ struct delayed_work delayed_reset_work;
+ spinlock_t lock;
+ unsigned long last_req_ts;
+};
+
+int tmio_mmc_host_probe(struct tmio_mmc_host **host,
+ struct platform_device *pdev,
+ struct tmio_mmc_data *pdata);
+void tmio_mmc_host_remove(struct tmio_mmc_host *host);
+void tmio_mmc_do_data_irq(struct tmio_mmc_host *host);
+
+void tmio_mmc_enable_mmc_irqs(struct tmio_mmc_host *host, u32 i);
+void tmio_mmc_disable_mmc_irqs(struct tmio_mmc_host *host, u32 i);
+
+static inline char *tmio_mmc_kmap_atomic(struct scatterlist *sg,
+ unsigned long *flags)
+{
+ local_irq_save(*flags);
+ return kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset;
+}
+
+static inline void tmio_mmc_kunmap_atomic(struct scatterlist *sg,
+ unsigned long *flags, void *virt)
+{
+ kunmap_atomic(virt - sg->offset, KM_BIO_SRC_IRQ);
+ local_irq_restore(*flags);
+}
+
+#ifdef CONFIG_TMIO_MMC_DMA
+void tmio_mmc_start_dma(struct tmio_mmc_host *host, struct mmc_data *data);
+void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdata);
+void tmio_mmc_release_dma(struct tmio_mmc_host *host);
+#else
+static inline void tmio_mmc_start_dma(struct tmio_mmc_host *host,
+ struct mmc_data *data)
+{
+}
+
+static inline void tmio_mmc_request_dma(struct tmio_mmc_host *host,
+ struct tmio_mmc_data *pdata)
+{
+ host->chan_tx = NULL;
+ host->chan_rx = NULL;
+}
+
+static inline void tmio_mmc_release_dma(struct tmio_mmc_host *host)
+{
+}
+#endif
+
+#endif
diff --git a/drivers/mmc/host/tmio_mmc_dma.c b/drivers/mmc/host/tmio_mmc_dma.c
new file mode 100644
index 0000000..65ffe6d
--- /dev/null
+++ b/drivers/mmc/host/tmio_mmc_dma.c
@@ -0,0 +1,302 @@
+/*
+ * linux/drivers/mmc/tmio_mmc_dma.c
+ *
+ * Copyright (C) 2010-2011 Guennadi Liakhovetski
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * DMA function for TMIO MMC implementations
+ */
+
+#include <linux/device.h>
+#include <linux/dmaengine.h>
+#include <linux/mfd/tmio.h>
+#include <linux/mmc/host.h>
+#include <linux/pagemap.h>
+#include <linux/scatterlist.h>
+
+#include "tmio_mmc.h"
+
+#define TMIO_MMC_MIN_DMA_LEN 8
+
+static void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable)
+{
+#if defined(CONFIG_SUPERH) || defined(CONFIG_ARCH_SHMOBILE)
+ /* Switch DMA mode on or off - SuperH specific? */
+ writew(enable ? 2 : 0, host->ctl + (0xd8 << host->bus_shift));
+#endif
+}
+
+static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host)
+{
+ struct scatterlist *sg = host->sg_ptr, *sg_tmp;
+ struct dma_async_tx_descriptor *desc = NULL;
+ struct dma_chan *chan = host->chan_rx;
+ struct tmio_mmc_data *pdata = host->pdata;
+ dma_cookie_t cookie;
+ int ret, i;
+ bool aligned = true, multiple = true;
+ unsigned int align = (1 << pdata->dma->alignment_shift) - 1;
+
+ for_each_sg(sg, sg_tmp, host->sg_len, i) {
+ if (sg_tmp->offset & align)
+ aligned = false;
+ if (sg_tmp->length & align) {
+ multiple = false;
+ break;
+ }
+ }
+
+ if ((!aligned && (host->sg_len > 1 || sg->length > PAGE_CACHE_SIZE ||
+ align >= TMIO_MAX_ALIGN)) || !multiple) {
+ ret = -EINVAL;
+ goto pio;
+ }
+
+ if (sg->length < TMIO_MMC_MIN_DMA_LEN) {
+ host->force_pio = true;
+ return;
+ }
+
+ tmio_mmc_disable_mmc_irqs(host, TMIO_STAT_RXRDY);
+
+ /* The only sg element can be unaligned, use our bounce buffer then */
+ if (!aligned) {
+ sg_init_one(&host->bounce_sg, host->bounce_buf, sg->length);
+ host->sg_ptr = &host->bounce_sg;
+ sg = host->sg_ptr;
+ }
+
+ ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_FROM_DEVICE);
+ if (ret > 0)
+ desc = chan->device->device_prep_slave_sg(chan, sg, ret,
+ DMA_FROM_DEVICE, DMA_CTRL_ACK);
+
+ if (desc) {
+ cookie = dmaengine_submit(desc);
+ if (cookie < 0) {
+ desc = NULL;
+ ret = cookie;
+ }
+ }
+ dev_dbg(&host->pdev->dev, "%s(): mapped %d -> %d, cookie %d, rq %p\n",
+ __func__, host->sg_len, ret, cookie, host->mrq);
+
+pio:
+ if (!desc) {
+ /* DMA failed, fall back to PIO */
+ if (ret >= 0)
+ ret = -EIO;
+ host->chan_rx = NULL;
+ dma_release_channel(chan);
+ /* Free the Tx channel too */
+ chan = host->chan_tx;
+ if (chan) {
+ host->chan_tx = NULL;
+ dma_release_channel(chan);
+ }
+ dev_warn(&host->pdev->dev,
+ "DMA failed: %d, falling back to PIO\n", ret);
+ tmio_mmc_enable_dma(host, false);
+ }
+
+ dev_dbg(&host->pdev->dev, "%s(): desc %p, cookie %d, sg[%d]\n", __func__,
+ desc, cookie, host->sg_len);
+}
+
+static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host)
+{
+ struct scatterlist *sg = host->sg_ptr, *sg_tmp;
+ struct dma_async_tx_descriptor *desc = NULL;
+ struct dma_chan *chan = host->chan_tx;
+ struct tmio_mmc_data *pdata = host->pdata;
+ dma_cookie_t cookie;
+ int ret, i;
+ bool aligned = true, multiple = true;
+ unsigned int align = (1 << pdata->dma->alignment_shift) - 1;
+
+ for_each_sg(sg, sg_tmp, host->sg_len, i) {
+ if (sg_tmp->offset & align)
+ aligned = false;
+ if (sg_tmp->length & align) {
+ multiple = false;
+ break;
+ }
+ }
+
+ if ((!aligned && (host->sg_len > 1 || sg->length > PAGE_CACHE_SIZE ||
+ align >= TMIO_MAX_ALIGN)) || !multiple) {
+ ret = -EINVAL;
+ goto pio;
+ }
+
+ if (sg->length < TMIO_MMC_MIN_DMA_LEN) {
+ host->force_pio = true;
+ return;
+ }
+
+ tmio_mmc_disable_mmc_irqs(host, TMIO_STAT_TXRQ);
+
+ /* The only sg element can be unaligned, use our bounce buffer then */
+ if (!aligned) {
+ unsigned long flags;
+ void *sg_vaddr = tmio_mmc_kmap_atomic(sg, &flags);
+ sg_init_one(&host->bounce_sg, host->bounce_buf, sg->length);
+ memcpy(host->bounce_buf, sg_vaddr, host->bounce_sg.length);
+ tmio_mmc_kunmap_atomic(sg, &flags, sg_vaddr);
+ host->sg_ptr = &host->bounce_sg;
+ sg = host->sg_ptr;
+ }
+
+ ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_TO_DEVICE);
+ if (ret > 0)
+ desc = chan->device->device_prep_slave_sg(chan, sg, ret,
+ DMA_TO_DEVICE, DMA_CTRL_ACK);
+
+ if (desc) {
+ cookie = dmaengine_submit(desc);
+ if (cookie < 0) {
+ desc = NULL;
+ ret = cookie;
+ }
+ }
+ dev_dbg(&host->pdev->dev, "%s(): mapped %d -> %d, cookie %d, rq %p\n",
+ __func__, host->sg_len, ret, cookie, host->mrq);
+
+pio:
+ if (!desc) {
+ /* DMA failed, fall back to PIO */
+ if (ret >= 0)
+ ret = -EIO;
+ host->chan_tx = NULL;
+ dma_release_channel(chan);
+ /* Free the Rx channel too */
+ chan = host->chan_rx;
+ if (chan) {
+ host->chan_rx = NULL;
+ dma_release_channel(chan);
+ }
+ dev_warn(&host->pdev->dev,
+ "DMA failed: %d, falling back to PIO\n", ret);
+ tmio_mmc_enable_dma(host, false);
+ }
+
+ dev_dbg(&host->pdev->dev, "%s(): desc %p, cookie %d\n", __func__,
+ desc, cookie);
+}
+
+void tmio_mmc_start_dma(struct tmio_mmc_host *host,
+ struct mmc_data *data)
+{
+ if (data->flags & MMC_DATA_READ) {
+ if (host->chan_rx)
+ tmio_mmc_start_dma_rx(host);
+ } else {
+ if (host->chan_tx)
+ tmio_mmc_start_dma_tx(host);
+ }
+}
+
+static void tmio_mmc_issue_tasklet_fn(unsigned long priv)
+{
+ struct tmio_mmc_host *host = (struct tmio_mmc_host *)priv;
+ struct dma_chan *chan = NULL;
+
+ spin_lock_irq(&host->lock);
+
+ if (host && host->data) {
+ if (host->data->flags & MMC_DATA_READ)
+ chan = host->chan_rx;
+ else
+ chan = host->chan_tx;
+ }
+
+ spin_unlock_irq(&host->lock);
+
+ tmio_mmc_enable_mmc_irqs(host, TMIO_STAT_DATAEND);
+
+ if (chan)
+ dma_async_issue_pending(chan);
+}
+
+static void tmio_mmc_tasklet_fn(unsigned long arg)
+{
+ struct tmio_mmc_host *host = (struct tmio_mmc_host *)arg;
+
+ spin_lock_irq(&host->lock);
+
+ if (!host->data)
+ goto out;
+
+ if (host->data->flags & MMC_DATA_READ)
+ dma_unmap_sg(host->chan_rx->device->dev,
+ host->sg_ptr, host->sg_len,
+ DMA_FROM_DEVICE);
+ else
+ dma_unmap_sg(host->chan_tx->device->dev,
+ host->sg_ptr, host->sg_len,
+ DMA_TO_DEVICE);
+
+ tmio_mmc_do_data_irq(host);
+out:
+ spin_unlock_irq(&host->lock);
+}
+
+/* It might be necessary to make filter MFD specific */
+static bool tmio_mmc_filter(struct dma_chan *chan, void *arg)
+{
+ dev_dbg(chan->device->dev, "%s: slave data %p\n", __func__, arg);
+ chan->private = arg;
+ return true;
+}
+
+void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdata)
+{
+ /* We can only either use DMA for both Tx and Rx or not use it at all */
+ if (pdata->dma) {
+ dma_cap_mask_t mask;
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+
+ host->chan_tx = dma_request_channel(mask, tmio_mmc_filter,
+ pdata->dma->chan_priv_tx);
+ dev_dbg(&host->pdev->dev, "%s: TX: got channel %p\n", __func__,
+ host->chan_tx);
+
+ if (!host->chan_tx)
+ return;
+
+ host->chan_rx = dma_request_channel(mask, tmio_mmc_filter,
+ pdata->dma->chan_priv_rx);
+ dev_dbg(&host->pdev->dev, "%s: RX: got channel %p\n", __func__,
+ host->chan_rx);
+
+ if (!host->chan_rx) {
+ dma_release_channel(host->chan_tx);
+ host->chan_tx = NULL;
+ return;
+ }
+
+ tasklet_init(&host->dma_complete, tmio_mmc_tasklet_fn, (unsigned long)host);
+ tasklet_init(&host->dma_issue, tmio_mmc_issue_tasklet_fn, (unsigned long)host);
+
+ tmio_mmc_enable_dma(host, true);
+ }
+}
+
+void tmio_mmc_release_dma(struct tmio_mmc_host *host)
+{
+ if (host->chan_tx) {
+ struct dma_chan *chan = host->chan_tx;
+ host->chan_tx = NULL;
+ dma_release_channel(chan);
+ }
+ if (host->chan_rx) {
+ struct dma_chan *chan = host->chan_rx;
+ host->chan_rx = NULL;
+ dma_release_channel(chan);
+ }
+}
diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c
new file mode 100644
index 0000000..a7406e3
--- /dev/null
+++ b/drivers/mmc/host/tmio_mmc_pio.c
@@ -0,0 +1,923 @@
+/*
+ * linux/drivers/mmc/host/tmio_mmc_pio.c
+ *
+ * Copyright (C) 2011 Guennadi Liakhovetski
+ * Copyright (C) 2007 Ian Molton
+ * Copyright (C) 2004 Ian Molton
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Driver for the MMC / SD / SDIO IP found in:
+ *
+ * TC6393XB, TC6391XB, TC6387XB, T7L66XB, ASIC3, SH-Mobile SoCs
+ *
+ * This driver draws mainly on scattered spec sheets, Reverse engineering
+ * of the toshiba e800 SD driver and some parts of the 2.4 ASIC3 driver (4 bit
+ * support). (Further 4 bit support from a later datasheet).
+ *
+ * TODO:
+ * Investigate using a workqueue for PIO transfers
+ * Eliminate FIXMEs
+ * SDIO support
+ * Better Power management
+ * Handle MMC errors better
+ * double buffer support
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/highmem.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/mfd/tmio.h>
+#include <linux/mmc/host.h>
+#include <linux/module.h>
+#include <linux/pagemap.h>
+#include <linux/platform_device.h>
+#include <linux/scatterlist.h>
+#include <linux/workqueue.h>
+#include <linux/spinlock.h>
+
+#include "tmio_mmc.h"
+
+#define CTL_SD_CMD 0x00
+#define CTL_ARG_REG 0x04
+#define CTL_STOP_INTERNAL_ACTION 0x08
+#define CTL_XFER_BLK_COUNT 0xa
+#define CTL_RESPONSE 0x0c
+#define CTL_STATUS 0x1c
+#define CTL_IRQ_MASK 0x20
+#define CTL_SD_CARD_CLK_CTL 0x24
+#define CTL_SD_XFER_LEN 0x26
+#define CTL_SD_MEM_CARD_OPT 0x28
+#define CTL_SD_ERROR_DETAIL_STATUS 0x2c
+#define CTL_SD_DATA_PORT 0x30
+#define CTL_TRANSACTION_CTL 0x34
+#define CTL_SDIO_STATUS 0x36
+#define CTL_SDIO_IRQ_MASK 0x38
+#define CTL_RESET_SD 0xe0
+#define CTL_SDIO_REGS 0x100
+#define CTL_CLK_AND_WAIT_CTL 0x138
+#define CTL_RESET_SDIO 0x1e0
+
+static u16 sd_ctrl_read16(struct tmio_mmc_host *host, int addr)
+{
+ return readw(host->ctl + (addr << host->bus_shift));
+}
+
+static void sd_ctrl_read16_rep(struct tmio_mmc_host *host, int addr,
+ u16 *buf, int count)
+{
+ readsw(host->ctl + (addr << host->bus_shift), buf, count);
+}
+
+static u32 sd_ctrl_read32(struct tmio_mmc_host *host, int addr)
+{
+ return readw(host->ctl + (addr << host->bus_shift)) |
+ readw(host->ctl + ((addr + 2) << host->bus_shift)) << 16;
+}
+
+static void sd_ctrl_write16(struct tmio_mmc_host *host, int addr, u16 val)
+{
+ writew(val, host->ctl + (addr << host->bus_shift));
+}
+
+static void sd_ctrl_write16_rep(struct tmio_mmc_host *host, int addr,
+ u16 *buf, int count)
+{
+ writesw(host->ctl + (addr << host->bus_shift), buf, count);
+}
+
+static void sd_ctrl_write32(struct tmio_mmc_host *host, int addr, u32 val)
+{
+ writew(val, host->ctl + (addr << host->bus_shift));
+ writew(val >> 16, host->ctl + ((addr + 2) << host->bus_shift));
+}
+
+void tmio_mmc_enable_mmc_irqs(struct tmio_mmc_host *host, u32 i)
+{
+ u32 mask = sd_ctrl_read32(host, CTL_IRQ_MASK) & ~(i & TMIO_MASK_IRQ);
+ sd_ctrl_write32(host, CTL_IRQ_MASK, mask);
+}
+
+void tmio_mmc_disable_mmc_irqs(struct tmio_mmc_host *host, u32 i)
+{
+ u32 mask = sd_ctrl_read32(host, CTL_IRQ_MASK) | (i & TMIO_MASK_IRQ);
+ sd_ctrl_write32(host, CTL_IRQ_MASK, mask);
+}
+
+static void tmio_mmc_ack_mmc_irqs(struct tmio_mmc_host *host, u32 i)
+{
+ sd_ctrl_write32(host, CTL_STATUS, ~i);
+}
+
+static void tmio_mmc_init_sg(struct tmio_mmc_host *host, struct mmc_data *data)
+{
+ host->sg_len = data->sg_len;
+ host->sg_ptr = data->sg;
+ host->sg_orig = data->sg;
+ host->sg_off = 0;
+}
+
+static int tmio_mmc_next_sg(struct tmio_mmc_host *host)
+{
+ host->sg_ptr = sg_next(host->sg_ptr);
+ host->sg_off = 0;
+ return --host->sg_len;
+}
+
+#ifdef CONFIG_MMC_DEBUG
+
+#define STATUS_TO_TEXT(a, status, i) \
+ do { \
+ if (status & TMIO_STAT_##a) { \
+ if (i++) \
+ printk(" | "); \
+ printk(#a); \
+ } \
+ } while (0)
+
+static void pr_debug_status(u32 status)
+{
+ int i = 0;
+ printk(KERN_DEBUG "status: %08x = ", status);
+ STATUS_TO_TEXT(CARD_REMOVE, status, i);
+ STATUS_TO_TEXT(CARD_INSERT, status, i);
+ STATUS_TO_TEXT(SIGSTATE, status, i);
+ STATUS_TO_TEXT(WRPROTECT, status, i);
+ STATUS_TO_TEXT(CARD_REMOVE_A, status, i);
+ STATUS_TO_TEXT(CARD_INSERT_A, status, i);
+ STATUS_TO_TEXT(SIGSTATE_A, status, i);
+ STATUS_TO_TEXT(CMD_IDX_ERR, status, i);
+ STATUS_TO_TEXT(STOPBIT_ERR, status, i);
+ STATUS_TO_TEXT(ILL_FUNC, status, i);
+ STATUS_TO_TEXT(CMD_BUSY, status, i);
+ STATUS_TO_TEXT(CMDRESPEND, status, i);
+ STATUS_TO_TEXT(DATAEND, status, i);
+ STATUS_TO_TEXT(CRCFAIL, status, i);
+ STATUS_TO_TEXT(DATATIMEOUT, status, i);
+ STATUS_TO_TEXT(CMDTIMEOUT, status, i);
+ STATUS_TO_TEXT(RXOVERFLOW, status, i);
+ STATUS_TO_TEXT(TXUNDERRUN, status, i);
+ STATUS_TO_TEXT(RXRDY, status, i);
+ STATUS_TO_TEXT(TXRQ, status, i);
+ STATUS_TO_TEXT(ILL_ACCESS, status, i);
+ printk("\n");
+}
+
+#else
+#define pr_debug_status(s) do { } while (0)
+#endif
+
+static void tmio_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
+{
+ struct tmio_mmc_host *host = mmc_priv(mmc);
+
+ if (enable) {
+ host->sdio_irq_enabled = 1;
+ sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0001);
+ sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK,
+ (TMIO_SDIO_MASK_ALL & ~TMIO_SDIO_STAT_IOIRQ));
+ } else {
+ sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, TMIO_SDIO_MASK_ALL);
+ sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0000);
+ host->sdio_irq_enabled = 0;
+ }
+}
+
+static void tmio_mmc_set_clock(struct tmio_mmc_host *host, int new_clock)
+{
+ u32 clk = 0, clock;
+
+ if (new_clock) {
+ for (clock = host->mmc->f_min, clk = 0x80000080;
+ new_clock >= (clock<<1); clk >>= 1)
+ clock <<= 1;
+ clk |= 0x100;
+ }
+
+ if (host->set_clk_div)
+ host->set_clk_div(host->pdev, (clk>>22) & 1);
+
+ sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk & 0x1ff);
+}
+
+static void tmio_mmc_clk_stop(struct tmio_mmc_host *host)
+{
+ struct tmio_mmc_data *pdata = host->pdata;
+
+ /*
+ * Testing on sh-mobile showed that SDIO IRQs are unmasked when
+ * CTL_CLK_AND_WAIT_CTL gets written, so we have to disable the
+ * device IRQ here and restore the SDIO IRQ mask before
+ * re-enabling the device IRQ.
+ */
+ if (pdata->flags & TMIO_MMC_SDIO_IRQ)
+ disable_irq(host->irq);
+ sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0000);
+ msleep(10);
+ if (pdata->flags & TMIO_MMC_SDIO_IRQ) {
+ tmio_mmc_enable_sdio_irq(host->mmc, host->sdio_irq_enabled);
+ enable_irq(host->irq);
+ }
+ sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~0x0100 &
+ sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
+ msleep(10);
+}
+
+static void tmio_mmc_clk_start(struct tmio_mmc_host *host)
+{
+ struct tmio_mmc_data *pdata = host->pdata;
+
+ sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, 0x0100 |
+ sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
+ msleep(10);
+ /* see comment in tmio_mmc_clk_stop above */
+ if (pdata->flags & TMIO_MMC_SDIO_IRQ)
+ disable_irq(host->irq);
+ sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0100);
+ msleep(10);
+ if (pdata->flags & TMIO_MMC_SDIO_IRQ) {
+ tmio_mmc_enable_sdio_irq(host->mmc, host->sdio_irq_enabled);
+ enable_irq(host->irq);
+ }
+}
+
+static void tmio_mmc_reset(struct tmio_mmc_host *host)
+{
+ /* FIXME - should we set stop clock reg here */
+ sd_ctrl_write16(host, CTL_RESET_SD, 0x0000);
+ sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0000);
+ msleep(10);
+ sd_ctrl_write16(host, CTL_RESET_SD, 0x0001);
+ sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0001);
+ msleep(10);
+}
+
+static void tmio_mmc_reset_work(struct work_struct *work)
+{
+ struct tmio_mmc_host *host = container_of(work, struct tmio_mmc_host,
+ delayed_reset_work.work);
+ struct mmc_request *mrq;
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+ mrq = host->mrq;
+
+ /* request already finished */
+ if (!mrq
+ || time_is_after_jiffies(host->last_req_ts +
+ msecs_to_jiffies(2000))) {
+ spin_unlock_irqrestore(&host->lock, flags);
+ return;
+ }
+
+ dev_warn(&host->pdev->dev,
+ "timeout waiting for hardware interrupt (CMD%u)\n",
+ mrq->cmd->opcode);
+
+ if (host->data)
+ host->data->error = -ETIMEDOUT;
+ else if (host->cmd)
+ host->cmd->error = -ETIMEDOUT;
+ else
+ mrq->cmd->error = -ETIMEDOUT;
+
+ host->cmd = NULL;
+ host->data = NULL;
+ host->mrq = NULL;
+ host->force_pio = false;
+
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ tmio_mmc_reset(host);
+
+ mmc_request_done(host->mmc, mrq);
+}
+
+static void tmio_mmc_finish_request(struct tmio_mmc_host *host)
+{
+ struct mmc_request *mrq = host->mrq;
+
+ if (!mrq)
+ return;
+
+ host->mrq = NULL;
+ host->cmd = NULL;
+ host->data = NULL;
+ host->force_pio = false;
+
+ cancel_delayed_work(&host->delayed_reset_work);
+
+ mmc_request_done(host->mmc, mrq);
+}
+
+/* These are the bitmasks the tmio chip requires to implement the MMC response
+ * types. Note that R1 and R6 are the same in this scheme. */
+#define APP_CMD 0x0040
+#define RESP_NONE 0x0300
+#define RESP_R1 0x0400
+#define RESP_R1B 0x0500
+#define RESP_R2 0x0600
+#define RESP_R3 0x0700
+#define DATA_PRESENT 0x0800
+#define TRANSFER_READ 0x1000
+#define TRANSFER_MULTI 0x2000
+#define SECURITY_CMD 0x4000
+
+static int tmio_mmc_start_command(struct tmio_mmc_host *host, struct mmc_command *cmd)
+{
+ struct mmc_data *data = host->data;
+ int c = cmd->opcode;
+
+ /* Command 12 is handled by hardware */
+ if (cmd->opcode = 12 && !cmd->arg) {
+ sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0x001);
+ return 0;
+ }
+
+ switch (mmc_resp_type(cmd)) {
+ case MMC_RSP_NONE: c |= RESP_NONE; break;
+ case MMC_RSP_R1: c |= RESP_R1; break;
+ case MMC_RSP_R1B: c |= RESP_R1B; break;
+ case MMC_RSP_R2: c |= RESP_R2; break;
+ case MMC_RSP_R3: c |= RESP_R3; break;
+ default:
+ pr_debug("Unknown response type %d\n", mmc_resp_type(cmd));
+ return -EINVAL;
+ }
+
+ host->cmd = cmd;
+
+/* FIXME - this seems to be ok commented out but the spec suggest this bit
+ * should be set when issuing app commands.
+ * if(cmd->flags & MMC_FLAG_ACMD)
+ * c |= APP_CMD;
+ */
+ if (data) {
+ c |= DATA_PRESENT;
+ if (data->blocks > 1) {
+ sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0x100);
+ c |= TRANSFER_MULTI;
+ }
+ if (data->flags & MMC_DATA_READ)
+ c |= TRANSFER_READ;
+ }
+
+ tmio_mmc_enable_mmc_irqs(host, TMIO_MASK_CMD);
+
+ /* Fire off the command */
+ sd_ctrl_write32(host, CTL_ARG_REG, cmd->arg);
+ sd_ctrl_write16(host, CTL_SD_CMD, c);
+
+ return 0;
+}
+
+/*
+ * This chip always returns (at least?) as much data as you ask for.
+ * I'm unsure what happens if you ask for less than a block. This should be
+ * looked into to ensure that a funny length read doesnt hose the controller.
+ */
+static void tmio_mmc_pio_irq(struct tmio_mmc_host *host)
+{
+ struct mmc_data *data = host->data;
+ void *sg_virt;
+ unsigned short *buf;
+ unsigned int count;
+ unsigned long flags;
+
+ if ((host->chan_tx || host->chan_rx) && !host->force_pio) {
+ pr_err("PIO IRQ in DMA mode!\n");
+ return;
+ } else if (!data) {
+ pr_debug("Spurious PIO IRQ\n");
+ return;
+ }
+
+ sg_virt = tmio_mmc_kmap_atomic(host->sg_ptr, &flags);
+ buf = (unsigned short *)(sg_virt + host->sg_off);
+
+ count = host->sg_ptr->length - host->sg_off;
+ if (count > data->blksz)
+ count = data->blksz;
+
+ pr_debug("count: %08x offset: %08x flags %08x\n",
+ count, host->sg_off, data->flags);
+
+ /* Transfer the data */
+ if (data->flags & MMC_DATA_READ)
+ sd_ctrl_read16_rep(host, CTL_SD_DATA_PORT, buf, count >> 1);
+ else
+ sd_ctrl_write16_rep(host, CTL_SD_DATA_PORT, buf, count >> 1);
+
+ host->sg_off += count;
+
+ tmio_mmc_kunmap_atomic(host->sg_ptr, &flags, sg_virt);
+
+ if (host->sg_off = host->sg_ptr->length)
+ tmio_mmc_next_sg(host);
+
+ return;
+}
+
+static void tmio_mmc_check_bounce_buffer(struct tmio_mmc_host *host)
+{
+ if (host->sg_ptr = &host->bounce_sg) {
+ unsigned long flags;
+ void *sg_vaddr = tmio_mmc_kmap_atomic(host->sg_orig, &flags);
+ memcpy(sg_vaddr, host->bounce_buf, host->bounce_sg.length);
+ tmio_mmc_kunmap_atomic(host->sg_orig, &flags, sg_vaddr);
+ }
+}
+
+/* needs to be called with host->lock held */
+void tmio_mmc_do_data_irq(struct tmio_mmc_host *host)
+{
+ struct mmc_data *data = host->data;
+ struct mmc_command *stop;
+
+ host->data = NULL;
+
+ if (!data) {
+ dev_warn(&host->pdev->dev, "Spurious data end IRQ\n");
+ return;
+ }
+ stop = data->stop;
+
+ /* FIXME - return correct transfer count on errors */
+ if (!data->error)
+ data->bytes_xfered = data->blocks * data->blksz;
+ else
+ data->bytes_xfered = 0;
+
+ pr_debug("Completed data request\n");
+
+ /*
+ * FIXME: other drivers allow an optional stop command of any given type
+ * which we dont do, as the chip can auto generate them.
+ * Perhaps we can be smarter about when to use auto CMD12 and
+ * only issue the auto request when we know this is the desired
+ * stop command, allowing fallback to the stop command the
+ * upper layers expect. For now, we do what works.
+ */
+
+ if (data->flags & MMC_DATA_READ) {
+ if (host->chan_rx && !host->force_pio)
+ tmio_mmc_check_bounce_buffer(host);
+ dev_dbg(&host->pdev->dev, "Complete Rx request %p\n",
+ host->mrq);
+ } else {
+ dev_dbg(&host->pdev->dev, "Complete Tx request %p\n",
+ host->mrq);
+ }
+
+ if (stop) {
+ if (stop->opcode = 12 && !stop->arg)
+ sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0x000);
+ else
+ BUG();
+ }
+
+ tmio_mmc_finish_request(host);
+}
+
+static void tmio_mmc_data_irq(struct tmio_mmc_host *host)
+{
+ struct mmc_data *data;
+ spin_lock(&host->lock);
+ data = host->data;
+
+ if (!data)
+ goto out;
+
+ if (host->chan_tx && (data->flags & MMC_DATA_WRITE) && !host->force_pio) {
+ /*
+ * Has all data been written out yet? Testing on SuperH showed,
+ * that in most cases the first interrupt comes already with the
+ * BUSY status bit clear, but on some operations, like mount or
+ * in the beginning of a write / sync / umount, there is one
+ * DATAEND interrupt with the BUSY bit set, in this cases
+ * waiting for one more interrupt fixes the problem.
+ */
+ if (!(sd_ctrl_read32(host, CTL_STATUS) & TMIO_STAT_CMD_BUSY)) {
+ tmio_mmc_disable_mmc_irqs(host, TMIO_STAT_DATAEND);
+ tasklet_schedule(&host->dma_complete);
+ }
+ } else if (host->chan_rx && (data->flags & MMC_DATA_READ) && !host->force_pio) {
+ tmio_mmc_disable_mmc_irqs(host, TMIO_STAT_DATAEND);
+ tasklet_schedule(&host->dma_complete);
+ } else {
+ tmio_mmc_do_data_irq(host);
+ tmio_mmc_disable_mmc_irqs(host, TMIO_MASK_READOP | TMIO_MASK_WRITEOP);
+ }
+out:
+ spin_unlock(&host->lock);
+}
+
+static void tmio_mmc_cmd_irq(struct tmio_mmc_host *host,
+ unsigned int stat)
+{
+ struct mmc_command *cmd = host->cmd;
+ int i, addr;
+
+ spin_lock(&host->lock);
+
+ if (!host->cmd) {
+ pr_debug("Spurious CMD irq\n");
+ goto out;
+ }
+
+ host->cmd = NULL;
+
+ /* This controller is sicker than the PXA one. Not only do we need to
+ * drop the top 8 bits of the first response word, we also need to
+ * modify the order of the response for short response command types.
+ */
+
+ for (i = 3, addr = CTL_RESPONSE ; i >= 0 ; i--, addr += 4)
+ cmd->resp[i] = sd_ctrl_read32(host, addr);
+
+ if (cmd->flags & MMC_RSP_136) {
+ cmd->resp[0] = (cmd->resp[0] << 8) | (cmd->resp[1] >> 24);
+ cmd->resp[1] = (cmd->resp[1] << 8) | (cmd->resp[2] >> 24);
+ cmd->resp[2] = (cmd->resp[2] << 8) | (cmd->resp[3] >> 24);
+ cmd->resp[3] <<= 8;
+ } else if (cmd->flags & MMC_RSP_R3) {
+ cmd->resp[0] = cmd->resp[3];
+ }
+
+ if (stat & TMIO_STAT_CMDTIMEOUT)
+ cmd->error = -ETIMEDOUT;
+ else if (stat & TMIO_STAT_CRCFAIL && cmd->flags & MMC_RSP_CRC)
+ cmd->error = -EILSEQ;
+
+ /* If there is data to handle we enable data IRQs here, and
+ * we will ultimatley finish the request in the data_end handler.
+ * If theres no data or we encountered an error, finish now.
+ */
+ if (host->data && !cmd->error) {
+ if (host->data->flags & MMC_DATA_READ) {
+ if (host->force_pio || !host->chan_rx)
+ tmio_mmc_enable_mmc_irqs(host, TMIO_MASK_READOP);
+ else
+ tasklet_schedule(&host->dma_issue);
+ } else {
+ if (host->force_pio || !host->chan_tx)
+ tmio_mmc_enable_mmc_irqs(host, TMIO_MASK_WRITEOP);
+ else
+ tasklet_schedule(&host->dma_issue);
+ }
+ } else {
+ tmio_mmc_finish_request(host);
+ }
+
+out:
+ spin_unlock(&host->lock);
+}
+
+static irqreturn_t tmio_mmc_irq(int irq, void *devid)
+{
+ struct tmio_mmc_host *host = devid;
+ struct tmio_mmc_data *pdata = host->pdata;
+ unsigned int ireg, irq_mask, status;
+ unsigned int sdio_ireg, sdio_irq_mask, sdio_status;
+
+ pr_debug("MMC IRQ begin\n");
+
+ status = sd_ctrl_read32(host, CTL_STATUS);
+ irq_mask = sd_ctrl_read32(host, CTL_IRQ_MASK);
+ ireg = status & TMIO_MASK_IRQ & ~irq_mask;
+
+ sdio_ireg = 0;
+ if (!ireg && pdata->flags & TMIO_MMC_SDIO_IRQ) {
+ sdio_status = sd_ctrl_read16(host, CTL_SDIO_STATUS);
+ sdio_irq_mask = sd_ctrl_read16(host, CTL_SDIO_IRQ_MASK);
+ sdio_ireg = sdio_status & TMIO_SDIO_MASK_ALL & ~sdio_irq_mask;
+
+ sd_ctrl_write16(host, CTL_SDIO_STATUS, sdio_status & ~TMIO_SDIO_MASK_ALL);
+
+ if (sdio_ireg && !host->sdio_irq_enabled) {
+ pr_warning("tmio_mmc: Spurious SDIO IRQ, disabling! 0x%04x 0x%04x 0x%04x\n",
+ sdio_status, sdio_irq_mask, sdio_ireg);
+ tmio_mmc_enable_sdio_irq(host->mmc, 0);
+ goto out;
+ }
+
+ if (host->mmc->caps & MMC_CAP_SDIO_IRQ &&
+ sdio_ireg & TMIO_SDIO_STAT_IOIRQ)
+ mmc_signal_sdio_irq(host->mmc);
+
+ if (sdio_ireg)
+ goto out;
+ }
+
+ pr_debug_status(status);
+ pr_debug_status(ireg);
+
+ if (!ireg) {
+ tmio_mmc_disable_mmc_irqs(host, status & ~irq_mask);
+
+ pr_warning("tmio_mmc: Spurious irq, disabling! "
+ "0x%08x 0x%08x 0x%08x\n", status, irq_mask, ireg);
+ pr_debug_status(status);
+
+ goto out;
+ }
+
+ while (ireg) {
+ /* Card insert / remove attempts */
+ if (ireg & (TMIO_STAT_CARD_INSERT | TMIO_STAT_CARD_REMOVE)) {
+ tmio_mmc_ack_mmc_irqs(host, TMIO_STAT_CARD_INSERT |
+ TMIO_STAT_CARD_REMOVE);
+ mmc_detect_change(host->mmc, msecs_to_jiffies(100));
+ }
+
+ /* CRC and other errors */
+/* if (ireg & TMIO_STAT_ERR_IRQ)
+ * handled |= tmio_error_irq(host, irq, stat);
+ */
+
+ /* Command completion */
+ if (ireg & (TMIO_STAT_CMDRESPEND | TMIO_STAT_CMDTIMEOUT)) {
+ tmio_mmc_ack_mmc_irqs(host,
+ TMIO_STAT_CMDRESPEND |
+ TMIO_STAT_CMDTIMEOUT);
+ tmio_mmc_cmd_irq(host, status);
+ }
+
+ /* Data transfer */
+ if (ireg & (TMIO_STAT_RXRDY | TMIO_STAT_TXRQ)) {
+ tmio_mmc_ack_mmc_irqs(host, TMIO_STAT_RXRDY | TMIO_STAT_TXRQ);
+ tmio_mmc_pio_irq(host);
+ }
+
+ /* Data transfer completion */
+ if (ireg & TMIO_STAT_DATAEND) {
+ tmio_mmc_ack_mmc_irqs(host, TMIO_STAT_DATAEND);
+ tmio_mmc_data_irq(host);
+ }
+
+ /* Check status - keep going until we've handled it all */
+ status = sd_ctrl_read32(host, CTL_STATUS);
+ irq_mask = sd_ctrl_read32(host, CTL_IRQ_MASK);
+ ireg = status & TMIO_MASK_IRQ & ~irq_mask;
+
+ pr_debug("Status at end of loop: %08x\n", status);
+ pr_debug_status(status);
+ }
+ pr_debug("MMC IRQ end\n");
+
+out:
+ return IRQ_HANDLED;
+}
+
+static int tmio_mmc_start_data(struct tmio_mmc_host *host,
+ struct mmc_data *data)
+{
+ struct tmio_mmc_data *pdata = host->pdata;
+
+ pr_debug("setup data transfer: blocksize %08x nr_blocks %d\n",
+ data->blksz, data->blocks);
+
+ /* Some hardware cannot perform 2 byte requests in 4 bit mode */
+ if (host->mmc->ios.bus_width = MMC_BUS_WIDTH_4) {
+ int blksz_2bytes = pdata->flags & TMIO_MMC_BLKSZ_2BYTES;
+
+ if (data->blksz < 2 || (data->blksz < 4 && !blksz_2bytes)) {
+ pr_err("%s: %d byte block unsupported in 4 bit mode\n",
+ mmc_hostname(host->mmc), data->blksz);
+ return -EINVAL;
+ }
+ }
+
+ tmio_mmc_init_sg(host, data);
+ host->data = data;
+
+ /* Set transfer length / blocksize */
+ sd_ctrl_write16(host, CTL_SD_XFER_LEN, data->blksz);
+ sd_ctrl_write16(host, CTL_XFER_BLK_COUNT, data->blocks);
+
+ tmio_mmc_start_dma(host, data);
+
+ return 0;
+}
+
+/* Process requests from the MMC layer */
+static void tmio_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+ struct tmio_mmc_host *host = mmc_priv(mmc);
+ int ret;
+
+ if (host->mrq)
+ pr_debug("request not null\n");
+
+ host->last_req_ts = jiffies;
+ wmb();
+ host->mrq = mrq;
+
+ if (mrq->data) {
+ ret = tmio_mmc_start_data(host, mrq->data);
+ if (ret)
+ goto fail;
+ }
+
+ ret = tmio_mmc_start_command(host, mrq->cmd);
+ if (!ret) {
+ schedule_delayed_work(&host->delayed_reset_work,
+ msecs_to_jiffies(2000));
+ return;
+ }
+
+fail:
+ host->mrq = NULL;
+ host->force_pio = false;
+ mrq->cmd->error = ret;
+ mmc_request_done(mmc, mrq);
+}
+
+/* Set MMC clock / power.
+ * Note: This controller uses a simple divider scheme therefore it cannot
+ * run a MMC card at full speed (20MHz). The max clock is 24MHz on SD, but as
+ * MMC wont run that fast, it has to be clocked at 12MHz which is the next
+ * slowest setting.
+ */
+static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+ struct tmio_mmc_host *host = mmc_priv(mmc);
+
+ if (ios->clock)
+ tmio_mmc_set_clock(host, ios->clock);
+
+ /* Power sequence - OFF -> ON -> UP */
+ switch (ios->power_mode) {
+ case MMC_POWER_OFF: /* power down SD bus */
+ if (host->set_pwr)
+ host->set_pwr(host->pdev, 0);
+ tmio_mmc_clk_stop(host);
+ break;
+ case MMC_POWER_ON: /* power up SD bus */
+ if (host->set_pwr)
+ host->set_pwr(host->pdev, 1);
+ break;
+ case MMC_POWER_UP: /* start bus clock */
+ tmio_mmc_clk_start(host);
+ break;
+ }
+
+ switch (ios->bus_width) {
+ case MMC_BUS_WIDTH_1:
+ sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x80e0);
+ break;
+ case MMC_BUS_WIDTH_4:
+ sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x00e0);
+ break;
+ }
+
+ /* Let things settle. delay taken from winCE driver */
+ udelay(140);
+}
+
+static int tmio_mmc_get_ro(struct mmc_host *mmc)
+{
+ struct tmio_mmc_host *host = mmc_priv(mmc);
+ struct tmio_mmc_data *pdata = host->pdata;
+
+ return ((pdata->flags & TMIO_MMC_WRPROTECT_DISABLE) ||
+ !(sd_ctrl_read32(host, CTL_STATUS) & TMIO_STAT_WRPROTECT));
+}
+
+static int tmio_mmc_get_cd(struct mmc_host *mmc)
+{
+ struct tmio_mmc_host *host = mmc_priv(mmc);
+ struct tmio_mmc_data *pdata = host->pdata;
+
+ if (!pdata->get_cd)
+ return -ENOSYS;
+ else
+ return pdata->get_cd(host->pdev);
+}
+
+static const struct mmc_host_ops tmio_mmc_ops = {
+ .request = tmio_mmc_request,
+ .set_ios = tmio_mmc_set_ios,
+ .get_ro = tmio_mmc_get_ro,
+ .get_cd = tmio_mmc_get_cd,
+ .enable_sdio_irq = tmio_mmc_enable_sdio_irq,
+};
+
+int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
+ struct platform_device *pdev,
+ struct tmio_mmc_data *pdata)
+{
+ struct tmio_mmc_host *_host;
+ struct mmc_host *mmc;
+ struct resource *res_ctl;
+ int ret;
+ u32 irq_mask = TMIO_MASK_CMD;
+
+ res_ctl = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res_ctl)
+ return -EINVAL;
+
+ mmc = mmc_alloc_host(sizeof(struct tmio_mmc_host), &pdev->dev);
+ if (!mmc)
+ return -ENOMEM;
+
+ _host = mmc_priv(mmc);
+ _host->pdata = pdata;
+ _host->mmc = mmc;
+ _host->pdev = pdev;
+ platform_set_drvdata(pdev, mmc);
+
+ _host->set_pwr = pdata->set_pwr;
+ _host->set_clk_div = pdata->set_clk_div;
+
+ /* SD control register space size is 0x200, 0x400 for bus_shift=1 */
+ _host->bus_shift = resource_size(res_ctl) >> 10;
+
+ _host->ctl = ioremap(res_ctl->start, resource_size(res_ctl));
+ if (!_host->ctl) {
+ ret = -ENOMEM;
+ goto host_free;
+ }
+
+ mmc->ops = &tmio_mmc_ops;
+ mmc->caps = MMC_CAP_4_BIT_DATA | pdata->capabilities;
+ mmc->f_max = pdata->hclk;
+ mmc->f_min = mmc->f_max / 512;
+ mmc->max_segs = 32;
+ mmc->max_blk_size = 512;
+ mmc->max_blk_count = (PAGE_CACHE_SIZE / mmc->max_blk_size) *
+ mmc->max_segs;
+ mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
+ mmc->max_seg_size = mmc->max_req_size;
+ if (pdata->ocr_mask)
+ mmc->ocr_avail = pdata->ocr_mask;
+ else
+ mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
+
+ tmio_mmc_clk_stop(_host);
+ tmio_mmc_reset(_host);
+
+ ret = platform_get_irq(pdev, 0);
+ if (ret < 0)
+ goto unmap_ctl;
+
+ _host->irq = ret;
+
+ tmio_mmc_disable_mmc_irqs(_host, TMIO_MASK_ALL);
+ if (pdata->flags & TMIO_MMC_SDIO_IRQ)
+ tmio_mmc_enable_sdio_irq(mmc, 0);
+
+ ret = request_irq(_host->irq, tmio_mmc_irq, IRQF_DISABLED |
+ IRQF_TRIGGER_FALLING, dev_name(&pdev->dev), _host);
+ if (ret)
+ goto unmap_ctl;
+
+ spin_lock_init(&_host->lock);
+
+ /* Init delayed work for request timeouts */
+ INIT_DELAYED_WORK(&_host->delayed_reset_work, tmio_mmc_reset_work);
+
+ /* See if we also get DMA */
+ tmio_mmc_request_dma(_host, pdata);
+
+ mmc_add_host(mmc);
+
+ /* Unmask the IRQs we want to know about */
+ if (!_host->chan_rx)
+ irq_mask |= TMIO_MASK_READOP;
+ if (!_host->chan_tx)
+ irq_mask |= TMIO_MASK_WRITEOP;
+
+ tmio_mmc_enable_mmc_irqs(_host, irq_mask);
+
+ *host = _host;
+
+ return 0;
+
+unmap_ctl:
+ iounmap(_host->ctl);
+host_free:
+ mmc_free_host(mmc);
+
+ return ret;
+}
+EXPORT_SYMBOL(tmio_mmc_host_probe);
+
+void tmio_mmc_host_remove(struct tmio_mmc_host *host)
+{
+ mmc_remove_host(host->mmc);
+ cancel_delayed_work_sync(&host->delayed_reset_work);
+ tmio_mmc_release_dma(host);
+ free_irq(host->irq, host);
+ iounmap(host->ctl);
+ mmc_free_host(host->mmc);
+}
+EXPORT_SYMBOL(tmio_mmc_host_remove);
+
+MODULE_LICENSE("GPL v2");
--
1.7.2.3
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 2/6] sh: ecovec: use the CONFIG_MMC_TMIO symbols instead of
2011-03-11 7:51 [PATCH 0/6] mmc: split the tmio driver into several modules Guennadi Liakhovetski
2011-03-11 7:51 ` [PATCH 1/6] mmc: tmio: split core functionality, DMA and MFD glue Guennadi Liakhovetski
@ 2011-03-11 7:52 ` Guennadi Liakhovetski
2011-03-12 16:18 ` [PATCH 2/6] sh: ecovec: use the CONFIG_MMC_TMIO symbols instead Magnus Damm
2011-03-11 7:52 ` [PATCH 3/6] mmc: tmio: convert the SDHI MMC driver from MFD to a Guennadi Liakhovetski
` (4 subsequent siblings)
6 siblings, 1 reply; 27+ messages in thread
From: Guennadi Liakhovetski @ 2011-03-11 7:52 UTC (permalink / raw)
To: linux-sh; +Cc: linux-mmc, Chris Ball, Ian Molton
The CONFIG_MFD_SH_MOBILE_SDHI Kconfig symbol is going to disappear soon,
switch ecovec to using CONFIG_MMC_TMIO(_MODULE).
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
---
arch/sh/boards/mach-ecovec24/setup.c | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c
index 52751f0..37ad5dc 100644
--- a/arch/sh/boards/mach-ecovec24/setup.c
+++ b/arch/sh/boards/mach-ecovec24/setup.c
@@ -462,7 +462,7 @@ static struct i2c_board_info ts_i2c_clients = {
.irq = IRQ0,
};
-#ifdef CONFIG_MFD_SH_MOBILE_SDHI
+#if defined(CONFIG_MMC_TMIO) || defined(CONFIG_MMC_TMIO_MODULE)
/* SDHI0 */
static void sdhi0_set_pwr(struct platform_device *pdev, int state)
{
@@ -887,7 +887,7 @@ static struct platform_device *ecovec_devices[] __initdata = {
&ceu0_device,
&ceu1_device,
&keysc_device,
-#ifdef CONFIG_MFD_SH_MOBILE_SDHI
+#if defined(CONFIG_MMC_TMIO) || defined(CONFIG_MMC_TMIO_MODULE)
&sdhi0_device,
#if !defined(CONFIG_MMC_SH_MMCIF)
&sdhi1_device,
@@ -1169,7 +1169,7 @@ static int __init arch_setup(void)
gpio_direction_input(GPIO_PTR5);
gpio_direction_input(GPIO_PTR6);
-#ifdef CONFIG_MFD_SH_MOBILE_SDHI
+#if defined(CONFIG_MMC_TMIO) || defined(CONFIG_MMC_TMIO_MODULE)
/* enable SDHI0 on CN11 (needs DS2.4 set to ON) */
gpio_request(GPIO_FN_SDHI0CD, NULL);
gpio_request(GPIO_FN_SDHI0WP, NULL);
--
1.7.2.3
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 3/6] mmc: tmio: convert the SDHI MMC driver from MFD to a
2011-03-11 7:51 [PATCH 0/6] mmc: split the tmio driver into several modules Guennadi Liakhovetski
2011-03-11 7:51 ` [PATCH 1/6] mmc: tmio: split core functionality, DMA and MFD glue Guennadi Liakhovetski
2011-03-11 7:52 ` [PATCH 2/6] sh: ecovec: use the CONFIG_MMC_TMIO symbols instead of Guennadi Liakhovetski
@ 2011-03-11 7:52 ` Guennadi Liakhovetski
2011-03-13 4:14 ` Magnus Damm
2011-03-11 7:52 ` [PATCH 4/6] ARM: mach-shmobile: convert boards to use Guennadi Liakhovetski
` (3 subsequent siblings)
6 siblings, 1 reply; 27+ messages in thread
From: Guennadi Liakhovetski @ 2011-03-11 7:52 UTC (permalink / raw)
To: linux-sh; +Cc: linux-mmc, Chris Ball, Ian Molton
On sh-mobile platforms the SDHI driver was using the tmio_mmc SD/SDIO
MFD cell driver. Now that the tmio_mmc driver has been split into a
core and a separate MFD glue, we can support SDHI natively without the
need to emulate an MFD controller. This also allows to support systems
with an on-SoC SDHI controller and a separate MFD with a TMIO core.
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
---
drivers/mfd/Kconfig | 14 ---
drivers/mfd/Makefile | 1 -
drivers/mfd/sh_mobile_sdhi.c | 200 ------------------------------------
drivers/mmc/host/Kconfig | 9 ++-
drivers/mmc/host/Makefile | 7 +-
drivers/mmc/host/sh_mobile_sdhi.c | 171 ++++++++++++++++++++++++++++++
drivers/mmc/host/tmio_mmc.h | 4 +-
include/linux/mfd/sh_mobile_sdhi.h | 19 +---
include/linux/mmc/sh_mobile_sdhi.h | 16 +++
9 files changed, 207 insertions(+), 234 deletions(-)
delete mode 100644 drivers/mfd/sh_mobile_sdhi.c
create mode 100644 drivers/mmc/host/sh_mobile_sdhi.c
create mode 100644 include/linux/mmc/sh_mobile_sdhi.h
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 7509858..1928ed3 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -60,15 +60,6 @@ config MFD_ASIC3
This driver supports the ASIC3 multifunction chip found on many
PDAs (mainly iPAQ and HTC based ones)
-config MFD_SH_MOBILE_SDHI
- bool "Support for SuperH Mobile SDHI"
- depends on SUPERH || ARCH_SHMOBILE
- select MFD_CORE
- select TMIO_MMC_DMA
- ---help---
- This driver supports the SDHI hardware block found in many
- SuperH Mobile SoCs.
-
config MFD_DAVINCI_VOICECODEC
tristate
select MFD_CORE
@@ -243,11 +234,6 @@ config MFD_TMIO
bool
default n
-config TMIO_MMC_DMA
- bool
- select DMA_ENGINE
- select DMADEVICES
-
config MFD_T7L66XB
bool "Support Toshiba T7L66XB"
depends on ARM && HAVE_CLK
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index b51d353..b755293 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -6,7 +6,6 @@
obj-$(CONFIG_MFD_88PM860X) += 88pm860x.o
obj-$(CONFIG_MFD_SM501) += sm501.o
obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o
-obj-$(CONFIG_MFD_SH_MOBILE_SDHI) += sh_mobile_sdhi.o
obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o
obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o
diff --git a/drivers/mfd/sh_mobile_sdhi.c b/drivers/mfd/sh_mobile_sdhi.c
deleted file mode 100644
index 53a6302..0000000
--- a/drivers/mfd/sh_mobile_sdhi.c
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * SuperH Mobile SDHI
- *
- * Copyright (C) 2009 Magnus Damm
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Based on "Compaq ASIC3 support":
- *
- * Copyright 2001 Compaq Computer Corporation.
- * Copyright 2004-2005 Phil Blundell
- * Copyright 2007-2008 OpenedHand Ltd.
- *
- * Authors: Phil Blundell <pb@handhelds.org>,
- * Samuel Ortiz <sameo@openedhand.com>
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/clk.h>
-#include <linux/slab.h>
-#include <linux/platform_device.h>
-#include <linux/mmc/host.h>
-#include <linux/mfd/core.h>
-#include <linux/mfd/tmio.h>
-#include <linux/mfd/sh_mobile_sdhi.h>
-#include <linux/sh_dma.h>
-
-struct sh_mobile_sdhi {
- struct clk *clk;
- struct tmio_mmc_data mmc_data;
- struct mfd_cell cell_mmc;
- struct sh_dmae_slave param_tx;
- struct sh_dmae_slave param_rx;
- struct tmio_mmc_dma dma_priv;
-};
-
-static struct resource sh_mobile_sdhi_resources[] = {
- {
- .start = 0x000,
- .end = 0x1ff,
- .flags = IORESOURCE_MEM,
- },
- {
- .start = 0,
- .end = 0,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct mfd_cell sh_mobile_sdhi_cell = {
- .name = "tmio-mmc",
- .num_resources = ARRAY_SIZE(sh_mobile_sdhi_resources),
- .resources = sh_mobile_sdhi_resources,
-};
-
-static void sh_mobile_sdhi_set_pwr(struct platform_device *tmio, int state)
-{
- struct platform_device *pdev = to_platform_device(tmio->dev.parent);
- struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
-
- if (p && p->set_pwr)
- p->set_pwr(pdev, state);
-}
-
-static int sh_mobile_sdhi_get_cd(struct platform_device *tmio)
-{
- struct platform_device *pdev = to_platform_device(tmio->dev.parent);
- struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
-
- if (p && p->get_cd)
- return p->get_cd(pdev);
- else
- return -ENOSYS;
-}
-
-static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
-{
- struct sh_mobile_sdhi *priv;
- struct tmio_mmc_data *mmc_data;
- struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
- struct resource *mem;
- char clk_name[8];
- int ret, irq;
-
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem)
- dev_err(&pdev->dev, "missing MEM resource\n");
-
- irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- dev_err(&pdev->dev, "missing IRQ resource\n");
-
- if (!mem || (irq < 0))
- return -EINVAL;
-
- priv = kzalloc(sizeof(struct sh_mobile_sdhi), GFP_KERNEL);
- if (priv = NULL) {
- dev_err(&pdev->dev, "kzalloc failed\n");
- return -ENOMEM;
- }
-
- mmc_data = &priv->mmc_data;
-
- snprintf(clk_name, sizeof(clk_name), "sdhi%d", pdev->id);
- priv->clk = clk_get(&pdev->dev, clk_name);
- if (IS_ERR(priv->clk)) {
- dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
- ret = PTR_ERR(priv->clk);
- kfree(priv);
- return ret;
- }
-
- clk_enable(priv->clk);
-
- mmc_data->hclk = clk_get_rate(priv->clk);
- mmc_data->set_pwr = sh_mobile_sdhi_set_pwr;
- mmc_data->get_cd = sh_mobile_sdhi_get_cd;
- mmc_data->capabilities = MMC_CAP_MMC_HIGHSPEED;
- if (p) {
- mmc_data->flags = p->tmio_flags;
- mmc_data->ocr_mask = p->tmio_ocr_mask;
- mmc_data->capabilities |= p->tmio_caps;
- }
-
- /*
- * All SDHI blocks support 2-byte and larger block sizes in 4-bit
- * bus width mode.
- */
- mmc_data->flags |= TMIO_MMC_BLKSZ_2BYTES;
-
- /*
- * All SDHI blocks support SDIO IRQ signalling.
- */
- mmc_data->flags |= TMIO_MMC_SDIO_IRQ;
-
- if (p && p->dma_slave_tx >= 0 && p->dma_slave_rx >= 0) {
- priv->param_tx.slave_id = p->dma_slave_tx;
- priv->param_rx.slave_id = p->dma_slave_rx;
- priv->dma_priv.chan_priv_tx = &priv->param_tx;
- priv->dma_priv.chan_priv_rx = &priv->param_rx;
- priv->dma_priv.alignment_shift = 1; /* 2-byte alignment */
- mmc_data->dma = &priv->dma_priv;
- }
-
- memcpy(&priv->cell_mmc, &sh_mobile_sdhi_cell, sizeof(priv->cell_mmc));
- priv->cell_mmc.mfd_data = mmc_data;
-
- platform_set_drvdata(pdev, priv);
-
- ret = mfd_add_devices(&pdev->dev, pdev->id,
- &priv->cell_mmc, 1, mem, irq);
- if (ret) {
- clk_disable(priv->clk);
- clk_put(priv->clk);
- kfree(priv);
- }
-
- return ret;
-}
-
-static int sh_mobile_sdhi_remove(struct platform_device *pdev)
-{
- struct sh_mobile_sdhi *priv = platform_get_drvdata(pdev);
-
- mfd_remove_devices(&pdev->dev);
- clk_disable(priv->clk);
- clk_put(priv->clk);
- kfree(priv);
-
- return 0;
-}
-
-static struct platform_driver sh_mobile_sdhi_driver = {
- .driver = {
- .name = "sh_mobile_sdhi",
- .owner = THIS_MODULE,
- },
- .probe = sh_mobile_sdhi_probe,
- .remove = __devexit_p(sh_mobile_sdhi_remove),
-};
-
-static int __init sh_mobile_sdhi_init(void)
-{
- return platform_driver_register(&sh_mobile_sdhi_driver);
-}
-
-static void __exit sh_mobile_sdhi_exit(void)
-{
- platform_driver_unregister(&sh_mobile_sdhi_driver);
-}
-
-module_init(sh_mobile_sdhi_init);
-module_exit(sh_mobile_sdhi_exit);
-
-MODULE_DESCRIPTION("SuperH Mobile SDHI driver");
-MODULE_AUTHOR("Magnus Damm");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 4d16166..0b03cee 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -444,12 +444,19 @@ config MMC_TMIO_CORE
config MMC_TMIO
tristate "Toshiba Mobile IO Controller (TMIO) MMC/SD function support"
- depends on MFD_TMIO || MFD_ASIC3 || MFD_SH_MOBILE_SDHI
+ depends on MFD_TMIO || MFD_ASIC3
select MMC_TMIO_CORE
help
This provides support for the SD/MMC cell found in TC6393XB,
T7L66XB and also HTC ASIC3
+config MMC_SDHI
+ tristate "SH-Mobile SDHI SD/SDIO controller support"
+ select MMC_TMIO_CORE
+ help
+ This provides support for the SDHI SD/SDIO controller found in
+ SuperH and ARM SH-Mobile SoCs
+
config MMC_CB710
tristate "ENE CB710 MMC/SD Interface support"
depends on PCI
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 79c42dd..4f1df0a 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -31,8 +31,11 @@ obj-$(CONFIG_MMC_SDRICOH_CS) += sdricoh_cs.o
obj-$(CONFIG_MMC_TMIO) += tmio_mmc.o
obj-$(CONFIG_MMC_TMIO_CORE) += tmio_mmc_core.o
tmio_mmc_core-y := tmio_mmc_pio.o
-tmio_mmc_core-$(CONFIG_TMIO_MMC_DMA) += tmio_mmc_dma.o
-obj-$(CONFIG_MMC_CB710) += cb710-mmc.o
+ifneq ($(CONFIG_MMC_SDHI),n)
+tmio_mmc_core-y += tmio_mmc_dma.o
+endif
+obj-$(CONFIG_MMC_SDHI) += sh_mobile_sdhi.o
+obj-$(CONFIG_MMC_CB710) += cb710-mmc.o
obj-$(CONFIG_MMC_VIA_SDMMC) += via-sdmmc.o
obj-$(CONFIG_SDH_BFIN) += bfin_sdh.o
obj-$(CONFIG_MMC_DW) += dw_mmc.o
diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c
new file mode 100644
index 0000000..cc70123
--- /dev/null
+++ b/drivers/mmc/host/sh_mobile_sdhi.c
@@ -0,0 +1,171 @@
+/*
+ * SuperH Mobile SDHI
+ *
+ * Copyright (C) 2009 Magnus Damm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Based on "Compaq ASIC3 support":
+ *
+ * Copyright 2001 Compaq Computer Corporation.
+ * Copyright 2004-2005 Phil Blundell
+ * Copyright 2007-2008 OpenedHand Ltd.
+ *
+ * Authors: Phil Blundell <pb@handhelds.org>,
+ * Samuel Ortiz <sameo@openedhand.com>
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/sh_mobile_sdhi.h>
+#include <linux/mfd/tmio.h>
+#include <linux/sh_dma.h>
+
+#include "tmio_mmc.h"
+
+struct sh_mobile_sdhi {
+ struct clk *clk;
+ struct tmio_mmc_data mmc_data;
+ struct sh_dmae_slave param_tx;
+ struct sh_dmae_slave param_rx;
+ struct tmio_mmc_dma dma_priv;
+};
+
+static void sh_mobile_sdhi_set_pwr(struct platform_device *pdev, int state)
+{
+ struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
+
+ if (p && p->set_pwr)
+ p->set_pwr(pdev, state);
+}
+
+static int sh_mobile_sdhi_get_cd(struct platform_device *pdev)
+{
+ struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
+
+ if (p && p->get_cd)
+ return p->get_cd(pdev);
+ else
+ return -ENOSYS;
+}
+
+static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
+{
+ struct sh_mobile_sdhi *priv;
+ struct tmio_mmc_data *mmc_data;
+ struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
+ struct tmio_mmc_host *host;
+ char clk_name[8];
+ int ret;
+
+ priv = kzalloc(sizeof(struct sh_mobile_sdhi), GFP_KERNEL);
+ if (priv = NULL) {
+ dev_err(&pdev->dev, "kzalloc failed\n");
+ return -ENOMEM;
+ }
+
+ mmc_data = &priv->mmc_data;
+
+ snprintf(clk_name, sizeof(clk_name), "sdhi%d", pdev->id);
+ priv->clk = clk_get(&pdev->dev, clk_name);
+ if (IS_ERR(priv->clk)) {
+ dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
+ ret = PTR_ERR(priv->clk);
+ goto eclkget;
+ }
+
+ clk_enable(priv->clk);
+
+ mmc_data->hclk = clk_get_rate(priv->clk);
+ mmc_data->set_pwr = sh_mobile_sdhi_set_pwr;
+ mmc_data->get_cd = sh_mobile_sdhi_get_cd;
+ mmc_data->capabilities = MMC_CAP_MMC_HIGHSPEED;
+ if (p) {
+ mmc_data->flags = p->tmio_flags;
+ mmc_data->ocr_mask = p->tmio_ocr_mask;
+ mmc_data->capabilities |= p->tmio_caps;
+
+ if (p->dma_slave_tx >= 0 && p->dma_slave_rx >= 0) {
+ priv->param_tx.slave_id = p->dma_slave_tx;
+ priv->param_rx.slave_id = p->dma_slave_rx;
+ priv->dma_priv.chan_priv_tx = &priv->param_tx;
+ priv->dma_priv.chan_priv_rx = &priv->param_rx;
+ priv->dma_priv.alignment_shift = 1; /* 2-byte alignment */
+ mmc_data->dma = &priv->dma_priv;
+ }
+ }
+
+ /*
+ * All SDHI blocks support 2-byte and larger block sizes in 4-bit
+ * bus width mode.
+ */
+ mmc_data->flags |= TMIO_MMC_BLKSZ_2BYTES;
+
+ /*
+ * All SDHI blocks support SDIO IRQ signalling.
+ */
+ mmc_data->flags |= TMIO_MMC_SDIO_IRQ;
+
+ ret = tmio_mmc_host_probe(&host, pdev, mmc_data);
+ if (ret < 0)
+ goto eprobe;
+
+ pr_info("%s at 0x%08lx irq %d\n", mmc_hostname(host->mmc),
+ (unsigned long)host->ctl, host->irq);
+
+ return ret;
+
+eprobe:
+ clk_disable(priv->clk);
+ clk_put(priv->clk);
+eclkget:
+ kfree(priv);
+ return ret;
+}
+
+static int sh_mobile_sdhi_remove(struct platform_device *pdev)
+{
+ struct mmc_host *mmc = platform_get_drvdata(pdev);
+ struct tmio_mmc_host *host = mmc_priv(mmc);
+ struct sh_mobile_sdhi *priv = container_of(host->pdata, struct sh_mobile_sdhi, mmc_data);
+
+ tmio_mmc_host_remove(host);
+ clk_disable(priv->clk);
+ clk_put(priv->clk);
+ kfree(priv);
+
+ return 0;
+}
+
+static struct platform_driver sh_mobile_sdhi_driver = {
+ .driver = {
+ .name = "sh_mobile_sdhi",
+ .owner = THIS_MODULE,
+ },
+ .probe = sh_mobile_sdhi_probe,
+ .remove = __devexit_p(sh_mobile_sdhi_remove),
+};
+
+static int __init sh_mobile_sdhi_init(void)
+{
+ return platform_driver_register(&sh_mobile_sdhi_driver);
+}
+
+static void __exit sh_mobile_sdhi_exit(void)
+{
+ platform_driver_unregister(&sh_mobile_sdhi_driver);
+}
+
+module_init(sh_mobile_sdhi_init);
+module_exit(sh_mobile_sdhi_exit);
+
+MODULE_DESCRIPTION("SuperH Mobile SDHI driver");
+MODULE_AUTHOR("Magnus Damm");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:sh_mobile_sdhi");
diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h
index 8ae936b..677e2a5 100644
--- a/drivers/mmc/host/tmio_mmc.h
+++ b/drivers/mmc/host/tmio_mmc.h
@@ -92,7 +92,7 @@ struct tmio_mmc_host {
struct tasklet_struct dma_complete;
struct tasklet_struct dma_issue;
struct scatterlist bounce_sg;
-#ifdef CONFIG_TMIO_MMC_DMA
+#if defined(CONFIG_MMC_SDHI) || defined(CONFIG_MMC_SDHI_MODULE)
u8 bounce_buf[PAGE_CACHE_SIZE] __attribute__((aligned(TMIO_MAX_ALIGN)));
#else
u8 bounce_buf[1]; /* A dummy in no-DMA case */
@@ -127,7 +127,7 @@ static inline void tmio_mmc_kunmap_atomic(struct scatterlist *sg,
local_irq_restore(*flags);
}
-#ifdef CONFIG_TMIO_MMC_DMA
+#if defined(CONFIG_MMC_SDHI) || defined(CONFIG_MMC_SDHI_MODULE)
void tmio_mmc_start_dma(struct tmio_mmc_host *host, struct mmc_data *data);
void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdata);
void tmio_mmc_release_dma(struct tmio_mmc_host *host);
diff --git a/include/linux/mfd/sh_mobile_sdhi.h b/include/linux/mfd/sh_mobile_sdhi.h
index c981b95..10af7f9 100644
--- a/include/linux/mfd/sh_mobile_sdhi.h
+++ b/include/linux/mfd/sh_mobile_sdhi.h
@@ -1,16 +1,7 @@
-#ifndef __SH_MOBILE_SDHI_H__
-#define __SH_MOBILE_SDHI_H__
+#ifndef MFD_SH_MOBILE_SDHI_H
+#define MFD_SH_MOBILE_SDHI_H
-#include <linux/types.h>
+/* Compatibility header - will disappear once all platforms are converted */
+#include <linux/mmc/sh_mobile_sdhi.h>
-struct sh_mobile_sdhi_info {
- int dma_slave_tx;
- int dma_slave_rx;
- unsigned long tmio_flags;
- unsigned long tmio_caps;
- u32 tmio_ocr_mask; /* available MMC voltages */
- void (*set_pwr)(struct platform_device *pdev, int state);
- int (*get_cd)(struct platform_device *pdev);
-};
-
-#endif /* __SH_MOBILE_SDHI_H__ */
+#endif /* MFD_SH_MOBILE_SDHI_H */
diff --git a/include/linux/mmc/sh_mobile_sdhi.h b/include/linux/mmc/sh_mobile_sdhi.h
new file mode 100644
index 0000000..c981b95
--- /dev/null
+++ b/include/linux/mmc/sh_mobile_sdhi.h
@@ -0,0 +1,16 @@
+#ifndef __SH_MOBILE_SDHI_H__
+#define __SH_MOBILE_SDHI_H__
+
+#include <linux/types.h>
+
+struct sh_mobile_sdhi_info {
+ int dma_slave_tx;
+ int dma_slave_rx;
+ unsigned long tmio_flags;
+ unsigned long tmio_caps;
+ u32 tmio_ocr_mask; /* available MMC voltages */
+ void (*set_pwr)(struct platform_device *pdev, int state);
+ int (*get_cd)(struct platform_device *pdev);
+};
+
+#endif /* __SH_MOBILE_SDHI_H__ */
--
1.7.2.3
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 4/6] ARM: mach-shmobile: convert boards to use
2011-03-11 7:51 [PATCH 0/6] mmc: split the tmio driver into several modules Guennadi Liakhovetski
` (2 preceding siblings ...)
2011-03-11 7:52 ` [PATCH 3/6] mmc: tmio: convert the SDHI MMC driver from MFD to a Guennadi Liakhovetski
@ 2011-03-11 7:52 ` Guennadi Liakhovetski
2011-03-11 7:52 ` [PATCH 5/6] sh: convert boards to use linux/mmc/sh_mobile_sdhi.h Guennadi Liakhovetski
` (2 subsequent siblings)
6 siblings, 0 replies; 27+ messages in thread
From: Guennadi Liakhovetski @ 2011-03-11 7:52 UTC (permalink / raw)
To: linux-sh; +Cc: linux-mmc, Chris Ball, Ian Molton
Prepare to remove the temporary header.
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
---
arch/arm/mach-shmobile/board-ap4evb.c | 2 +-
arch/arm/mach-shmobile/board-g4evm.c | 2 +-
arch/arm/mach-shmobile/board-mackerel.c | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c
index 1a8118c..7ae9e3b 100644
--- a/arch/arm/mach-shmobile/board-ap4evb.c
+++ b/arch/arm/mach-shmobile/board-ap4evb.c
@@ -24,9 +24,9 @@
#include <linux/irq.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
-#include <linux/mfd/sh_mobile_sdhi.h>
#include <linux/mfd/tmio.h>
#include <linux/mmc/host.h>
+#include <linux/mmc/sh_mobile_sdhi.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/physmap.h>
diff --git a/arch/arm/mach-shmobile/board-g4evm.c b/arch/arm/mach-shmobile/board-g4evm.c
index dee3e92..cccdf2d 100644
--- a/arch/arm/mach-shmobile/board-g4evm.c
+++ b/arch/arm/mach-shmobile/board-g4evm.c
@@ -31,7 +31,7 @@
#include <linux/input.h>
#include <linux/input/sh_keysc.h>
#include <linux/mmc/host.h>
-#include <linux/mfd/sh_mobile_sdhi.h>
+#include <linux/mmc/sh_mobile_sdhi.h>
#include <linux/gpio.h>
#include <mach/sh7377.h>
#include <mach/common.h>
diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c
index bbfc167..05fc5ac 100644
--- a/arch/arm/mach-shmobile/board-mackerel.c
+++ b/arch/arm/mach-shmobile/board-mackerel.c
@@ -32,10 +32,10 @@
#include <linux/io.h>
#include <linux/i2c.h>
#include <linux/leds.h>
-#include <linux/mfd/sh_mobile_sdhi.h>
#include <linux/mfd/tmio.h>
#include <linux/mmc/host.h>
#include <linux/mmc/sh_mmcif.h>
+#include <linux/mmc/sh_mobile_sdhi.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/physmap.h>
--
1.7.2.3
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 5/6] sh: convert boards to use linux/mmc/sh_mobile_sdhi.h
2011-03-11 7:51 [PATCH 0/6] mmc: split the tmio driver into several modules Guennadi Liakhovetski
` (3 preceding siblings ...)
2011-03-11 7:52 ` [PATCH 4/6] ARM: mach-shmobile: convert boards to use Guennadi Liakhovetski
@ 2011-03-11 7:52 ` Guennadi Liakhovetski
2011-03-11 7:52 ` [PATCH 6/6] mfd: remove now redundant sh_mobile_sdhi.h header Guennadi Liakhovetski
2011-03-15 21:25 ` [PATCH 0/6] mmc: split the tmio driver into several modules Ian Molton
6 siblings, 0 replies; 27+ messages in thread
From: Guennadi Liakhovetski @ 2011-03-11 7:52 UTC (permalink / raw)
To: linux-sh; +Cc: linux-mmc, Chris Ball, Ian Molton
Prepare to remove the temporary header.
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
---
arch/sh/boards/mach-ap325rxa/setup.c | 2 +-
arch/sh/boards/mach-ecovec24/setup.c | 2 +-
arch/sh/boards/mach-kfr2r09/setup.c | 2 +-
arch/sh/boards/mach-migor/setup.c | 2 +-
arch/sh/boards/mach-se/7724/setup.c | 2 +-
5 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/arch/sh/boards/mach-ap325rxa/setup.c b/arch/sh/boards/mach-ap325rxa/setup.c
index 33bfebc..60d109f 100644
--- a/arch/sh/boards/mach-ap325rxa/setup.c
+++ b/arch/sh/boards/mach-ap325rxa/setup.c
@@ -14,8 +14,8 @@
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
-#include <linux/mfd/sh_mobile_sdhi.h>
#include <linux/mmc/host.h>
+#include <linux/mmc/sh_mobile_sdhi.h>
#include <linux/mtd/physmap.h>
#include <linux/mtd/sh_flctl.h>
#include <linux/delay.h>
diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c
index 37ad5dc..710be27c9 100644
--- a/arch/sh/boards/mach-ecovec24/setup.c
+++ b/arch/sh/boards/mach-ecovec24/setup.c
@@ -11,9 +11,9 @@
#include <linux/init.h>
#include <linux/device.h>
#include <linux/platform_device.h>
-#include <linux/mfd/sh_mobile_sdhi.h>
#include <linux/mmc/host.h>
#include <linux/mmc/sh_mmcif.h>
+#include <linux/mmc/sh_mobile_sdhi.h>
#include <linux/mtd/physmap.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
diff --git a/arch/sh/boards/mach-kfr2r09/setup.c b/arch/sh/boards/mach-kfr2r09/setup.c
index 7504daa..7021b59 100644
--- a/arch/sh/boards/mach-kfr2r09/setup.c
+++ b/arch/sh/boards/mach-kfr2r09/setup.c
@@ -10,8 +10,8 @@
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
-#include <linux/mfd/sh_mobile_sdhi.h>
#include <linux/mmc/host.h>
+#include <linux/mmc/sh_mobile_sdhi.h>
#include <linux/mfd/tmio.h>
#include <linux/mtd/physmap.h>
#include <linux/mtd/onenand.h>
diff --git a/arch/sh/boards/mach-migor/setup.c b/arch/sh/boards/mach-migor/setup.c
index 03a7ffe..37e64a6 100644
--- a/arch/sh/boards/mach-migor/setup.c
+++ b/arch/sh/boards/mach-migor/setup.c
@@ -12,8 +12,8 @@
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/input/sh_keysc.h>
-#include <linux/mfd/sh_mobile_sdhi.h>
#include <linux/mmc/host.h>
+#include <linux/mmc/sh_mobile_sdhi.h>
#include <linux/mtd/physmap.h>
#include <linux/mtd/nand.h>
#include <linux/i2c.h>
diff --git a/arch/sh/boards/mach-se/7724/setup.c b/arch/sh/boards/mach-se/7724/setup.c
index c8bcf6a..58cefd3 100644
--- a/arch/sh/boards/mach-se/7724/setup.c
+++ b/arch/sh/boards/mach-se/7724/setup.c
@@ -14,8 +14,8 @@
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
-#include <linux/mfd/sh_mobile_sdhi.h>
#include <linux/mmc/host.h>
+#include <linux/mmc/sh_mobile_sdhi.h>
#include <linux/mtd/physmap.h>
#include <linux/delay.h>
#include <linux/smc91x.h>
--
1.7.2.3
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 6/6] mfd: remove now redundant sh_mobile_sdhi.h header
2011-03-11 7:51 [PATCH 0/6] mmc: split the tmio driver into several modules Guennadi Liakhovetski
` (4 preceding siblings ...)
2011-03-11 7:52 ` [PATCH 5/6] sh: convert boards to use linux/mmc/sh_mobile_sdhi.h Guennadi Liakhovetski
@ 2011-03-11 7:52 ` Guennadi Liakhovetski
2011-03-15 21:25 ` [PATCH 0/6] mmc: split the tmio driver into several modules Ian Molton
6 siblings, 0 replies; 27+ messages in thread
From: Guennadi Liakhovetski @ 2011-03-11 7:52 UTC (permalink / raw)
To: linux-sh; +Cc: linux-mmc, Chris Ball, Ian Molton
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
---
include/linux/mfd/sh_mobile_sdhi.h | 7 -------
1 files changed, 0 insertions(+), 7 deletions(-)
delete mode 100644 include/linux/mfd/sh_mobile_sdhi.h
diff --git a/include/linux/mfd/sh_mobile_sdhi.h b/include/linux/mfd/sh_mobile_sdhi.h
deleted file mode 100644
index 10af7f9..0000000
--- a/include/linux/mfd/sh_mobile_sdhi.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef MFD_SH_MOBILE_SDHI_H
-#define MFD_SH_MOBILE_SDHI_H
-
-/* Compatibility header - will disappear once all platforms are converted */
-#include <linux/mmc/sh_mobile_sdhi.h>
-
-#endif /* MFD_SH_MOBILE_SDHI_H */
--
1.7.2.3
^ permalink raw reply related [flat|nested] 27+ messages in thread
* Re: [PATCH 1/6] mmc: tmio: split core functionality, DMA and MFD glue
2011-03-11 7:51 ` [PATCH 1/6] mmc: tmio: split core functionality, DMA and MFD glue Guennadi Liakhovetski
@ 2011-03-12 16:05 ` Magnus Damm
2011-03-12 22:48 ` [PATCH 1/6] mmc: tmio: split core functionality, DMA and MFD Guennadi Liakhovetski
0 siblings, 1 reply; 27+ messages in thread
From: Magnus Damm @ 2011-03-12 16:05 UTC (permalink / raw)
To: Guennadi Liakhovetski; +Cc: linux-sh, linux-mmc, Chris Ball, Ian Molton
On Fri, Mar 11, 2011 at 4:51 PM, Guennadi Liakhovetski
<g.liakhovetski@gmx.de> wrote:
> TMIO MMC chips contain an SD / SDIO IP core from Panasonic, similar to
> the one, used in MN5774 and other MN57xx controllers. These IP cores are
> included in many multifunction devices, in sh-mobile chips from Renesas,
> in the latter case they can also use DMA. Some sh-mobile implementations
> also have some other specialities, that MFD-based solutions don't have.
> This makes supporting all these features in a monolithic driver inconveniet
> and error-prone. This patch splits the driver into 3 parts: the core,
> the MFD glue and the DMA support. In case of a modular build, two modules
> will be built: mmc_tmio_core and mmc_tmio.
>
> Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> ---
Thanks for your work on this, I'm happy to see these patches because
they make it easier for me to add multi-interrupt source to the SDHI
portion - something that is needed for sh73a0.
> drivers/mmc/host/Kconfig | 4 +
> drivers/mmc/host/Makefile | 3 +
> drivers/mmc/host/tmio_mmc.c | 1303 +--------------------------------------
> drivers/mmc/host/tmio_mmc.h | 152 +++++
> drivers/mmc/host/tmio_mmc_dma.c | 302 +++++++++
> drivers/mmc/host/tmio_mmc_pio.c | 923 +++++++++++++++++++++++++++
> 6 files changed, 1402 insertions(+), 1285 deletions(-)
> create mode 100644 drivers/mmc/host/tmio_mmc.h
> create mode 100644 drivers/mmc/host/tmio_mmc_dma.c
> create mode 100644 drivers/mmc/host/tmio_mmc_pio.c
Something is wrong with this patch. The Makefile adds tmio_mmc_core.c
but it's not part of the diffstat above. Perhaps you're posting an
older version of the patch?
Thanks,
/ magnus
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 2/6] sh: ecovec: use the CONFIG_MMC_TMIO symbols instead
2011-03-11 7:52 ` [PATCH 2/6] sh: ecovec: use the CONFIG_MMC_TMIO symbols instead of Guennadi Liakhovetski
@ 2011-03-12 16:18 ` Magnus Damm
2011-03-12 23:00 ` Guennadi Liakhovetski
0 siblings, 1 reply; 27+ messages in thread
From: Magnus Damm @ 2011-03-12 16:18 UTC (permalink / raw)
To: Guennadi Liakhovetski; +Cc: linux-sh, linux-mmc, Chris Ball, Ian Molton
On Fri, Mar 11, 2011 at 4:52 PM, Guennadi Liakhovetski
<g.liakhovetski@gmx.de> wrote:
> The CONFIG_MFD_SH_MOBILE_SDHI Kconfig symbol is going to disappear soon,
> switch ecovec to using CONFIG_MMC_TMIO(_MODULE).
>
> Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> ---
> arch/sh/boards/mach-ecovec24/setup.c | 6 +++---
> 1 files changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c
> index 52751f0..37ad5dc 100644
> --- a/arch/sh/boards/mach-ecovec24/setup.c
> +++ b/arch/sh/boards/mach-ecovec24/setup.c
> @@ -462,7 +462,7 @@ static struct i2c_board_info ts_i2c_clients = {
> .irq = IRQ0,
> };
>
> -#ifdef CONFIG_MFD_SH_MOBILE_SDHI
> +#if defined(CONFIG_MMC_TMIO) || defined(CONFIG_MMC_TMIO_MODULE)
> /* SDHI0 */
What's wrong with CONFIG_MMC_SDHI? Too early in the patch series?
I can't really see what the ecovec board has in common with the tmio
mmc implementation. Or did you mean the CONFIG_MMC_TMIO_CORE?
Perhaps this is just a stop-gap solution and it is being fixed in V2 patch 7/7 ?
Thanks,
/ magnus
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 1/6] mmc: tmio: split core functionality, DMA and MFD
2011-03-12 16:05 ` Magnus Damm
@ 2011-03-12 22:48 ` Guennadi Liakhovetski
2011-03-13 3:57 ` [PATCH 1/6] mmc: tmio: split core functionality, DMA and MFD glue Magnus Damm
0 siblings, 1 reply; 27+ messages in thread
From: Guennadi Liakhovetski @ 2011-03-12 22:48 UTC (permalink / raw)
To: Magnus Damm; +Cc: linux-sh, linux-mmc, Chris Ball, Ian Molton
On Sun, 13 Mar 2011, Magnus Damm wrote:
> On Fri, Mar 11, 2011 at 4:51 PM, Guennadi Liakhovetski
> <g.liakhovetski@gmx.de> wrote:
> > TMIO MMC chips contain an SD / SDIO IP core from Panasonic, similar to
> > the one, used in MN5774 and other MN57xx controllers. These IP cores are
> > included in many multifunction devices, in sh-mobile chips from Renesas,
> > in the latter case they can also use DMA. Some sh-mobile implementations
> > also have some other specialities, that MFD-based solutions don't have.
> > This makes supporting all these features in a monolithic driver inconveniet
> > and error-prone. This patch splits the driver into 3 parts: the core,
> > the MFD glue and the DMA support. In case of a modular build, two modules
> > will be built: mmc_tmio_core and mmc_tmio.
> >
> > Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> > ---
>
> Thanks for your work on this, I'm happy to see these patches because
> they make it easier for me to add multi-interrupt source to the SDHI
> portion - something that is needed for sh73a0.
>
> > drivers/mmc/host/Kconfig | 4 +
> > drivers/mmc/host/Makefile | 3 +
> > drivers/mmc/host/tmio_mmc.c | 1303 +--------------------------------------
> > drivers/mmc/host/tmio_mmc.h | 152 +++++
> > drivers/mmc/host/tmio_mmc_dma.c | 302 +++++++++
> > drivers/mmc/host/tmio_mmc_pio.c | 923 +++++++++++++++++++++++++++
> > 6 files changed, 1402 insertions(+), 1285 deletions(-)
> > create mode 100644 drivers/mmc/host/tmio_mmc.h
> > create mode 100644 drivers/mmc/host/tmio_mmc_dma.c
> > create mode 100644 drivers/mmc/host/tmio_mmc_pio.c
>
> Something is wrong with this patch. The Makefile adds tmio_mmc_core.c
> but it's not part of the diffstat above. Perhaps you're posting an
> older version of the patch?
No, the Makefile is adding tmio_mmc_core.o:
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 30aa686..79c42dd 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -29,6 +29,9 @@ endif
obj-$(CONFIG_MMC_S3C) += s3cmci.o
obj-$(CONFIG_MMC_SDRICOH_CS) += sdricoh_cs.o
obj-$(CONFIG_MMC_TMIO) += tmio_mmc.o
+obj-$(CONFIG_MMC_TMIO_CORE) += tmio_mmc_core.o
+tmio_mmc_core-y := tmio_mmc_pio.o
+tmio_mmc_core-$(CONFIG_TMIO_MMC_DMA) += tmio_mmc_dma.o
obj-$(CONFIG_MMC_CB710) += cb710-mmc.o
obj-$(CONFIG_MMC_VIA_SDMMC) += via-sdmmc.o
obj-$(CONFIG_SDH_BFIN) += bfin_sdh.o
which is linked from two source files. Looks correct to me.
Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
^ permalink raw reply related [flat|nested] 27+ messages in thread
* Re: [PATCH 2/6] sh: ecovec: use the CONFIG_MMC_TMIO symbols instead
2011-03-12 16:18 ` [PATCH 2/6] sh: ecovec: use the CONFIG_MMC_TMIO symbols instead Magnus Damm
@ 2011-03-12 23:00 ` Guennadi Liakhovetski
0 siblings, 0 replies; 27+ messages in thread
From: Guennadi Liakhovetski @ 2011-03-12 23:00 UTC (permalink / raw)
To: Magnus Damm; +Cc: linux-sh, linux-mmc, Chris Ball, Ian Molton
On Sun, 13 Mar 2011, Magnus Damm wrote:
> On Fri, Mar 11, 2011 at 4:52 PM, Guennadi Liakhovetski
> <g.liakhovetski@gmx.de> wrote:
> > The CONFIG_MFD_SH_MOBILE_SDHI Kconfig symbol is going to disappear soon,
> > switch ecovec to using CONFIG_MMC_TMIO(_MODULE).
> >
> > Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> > ---
> > arch/sh/boards/mach-ecovec24/setup.c | 6 +++---
> > 1 files changed, 3 insertions(+), 3 deletions(-)
> >
> > diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c
> > index 52751f0..37ad5dc 100644
> > --- a/arch/sh/boards/mach-ecovec24/setup.c
> > +++ b/arch/sh/boards/mach-ecovec24/setup.c
> > @@ -462,7 +462,7 @@ static struct i2c_board_info ts_i2c_clients = {
> > .irq = IRQ0,
> > };
> >
> > -#ifdef CONFIG_MFD_SH_MOBILE_SDHI
> > +#if defined(CONFIG_MMC_TMIO) || defined(CONFIG_MMC_TMIO_MODULE)
> > /* SDHI0 */
>
> What's wrong with CONFIG_MMC_SDHI? Too early in the patch series?
>
> I can't really see what the ecovec board has in common with the tmio
> mmc implementation. Or did you mean the CONFIG_MMC_TMIO_CORE?
Right, sure, it must be CONFIG_MMC_TMIO_CORE. CONFIG_MFD_SH_MOBILE_SDHI
has to go, because it is removed in a future patch. Will resubmit, thanks!
Regards
Guennadi
>
> Perhaps this is just a stop-gap solution and it is being fixed in V2 patch 7/7 ?
>
> Thanks,
>
> / magnus
>
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 1/6] mmc: tmio: split core functionality, DMA and MFD glue
2011-03-12 22:48 ` [PATCH 1/6] mmc: tmio: split core functionality, DMA and MFD Guennadi Liakhovetski
@ 2011-03-13 3:57 ` Magnus Damm
2011-03-13 22:51 ` [PATCH 1/6] mmc: tmio: split core functionality, DMA and MFD Guennadi Liakhovetski
0 siblings, 1 reply; 27+ messages in thread
From: Magnus Damm @ 2011-03-13 3:57 UTC (permalink / raw)
To: Guennadi Liakhovetski; +Cc: linux-sh, linux-mmc, Chris Ball, Ian Molton
On Sun, Mar 13, 2011 at 7:48 AM, Guennadi Liakhovetski
<g.liakhovetski@gmx.de> wrote:
> On Sun, 13 Mar 2011, Magnus Damm wrote:
>
>> On Fri, Mar 11, 2011 at 4:51 PM, Guennadi Liakhovetski
>> <g.liakhovetski@gmx.de> wrote:
>> > TMIO MMC chips contain an SD / SDIO IP core from Panasonic, similar to
>> > the one, used in MN5774 and other MN57xx controllers. These IP cores are
>> > included in many multifunction devices, in sh-mobile chips from Renesas,
>> > in the latter case they can also use DMA. Some sh-mobile implementations
>> > also have some other specialities, that MFD-based solutions don't have.
>> > This makes supporting all these features in a monolithic driver inconveniet
>> > and error-prone. This patch splits the driver into 3 parts: the core,
>> > the MFD glue and the DMA support. In case of a modular build, two modules
>> > will be built: mmc_tmio_core and mmc_tmio.
>> >
>> > Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
>> > ---
>>
>> Thanks for your work on this, I'm happy to see these patches because
>> they make it easier for me to add multi-interrupt source to the SDHI
>> portion - something that is needed for sh73a0.
>>
>> > drivers/mmc/host/Kconfig | 4 +
>> > drivers/mmc/host/Makefile | 3 +
>> > drivers/mmc/host/tmio_mmc.c | 1303 +--------------------------------------
>> > drivers/mmc/host/tmio_mmc.h | 152 +++++
>> > drivers/mmc/host/tmio_mmc_dma.c | 302 +++++++++
>> > drivers/mmc/host/tmio_mmc_pio.c | 923 +++++++++++++++++++++++++++
>> > 6 files changed, 1402 insertions(+), 1285 deletions(-)
>> > create mode 100644 drivers/mmc/host/tmio_mmc.h
>> > create mode 100644 drivers/mmc/host/tmio_mmc_dma.c
>> > create mode 100644 drivers/mmc/host/tmio_mmc_pio.c
>>
>> Something is wrong with this patch. The Makefile adds tmio_mmc_core.c
>> but it's not part of the diffstat above. Perhaps you're posting an
>> older version of the patch?
>
> No, the Makefile is adding tmio_mmc_core.o:
>
> diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
> index 30aa686..79c42dd 100644
> --- a/drivers/mmc/host/Makefile
> +++ b/drivers/mmc/host/Makefile
> @@ -29,6 +29,9 @@ endif
> obj-$(CONFIG_MMC_S3C) += s3cmci.o
> obj-$(CONFIG_MMC_SDRICOH_CS) += sdricoh_cs.o
> obj-$(CONFIG_MMC_TMIO) += tmio_mmc.o
> +obj-$(CONFIG_MMC_TMIO_CORE) += tmio_mmc_core.o
> +tmio_mmc_core-y := tmio_mmc_pio.o
> +tmio_mmc_core-$(CONFIG_TMIO_MMC_DMA) += tmio_mmc_dma.o
> obj-$(CONFIG_MMC_CB710) += cb710-mmc.o
> obj-$(CONFIG_MMC_VIA_SDMMC) += via-sdmmc.o
> obj-$(CONFIG_SDH_BFIN) += bfin_sdh.o
>
> which is linked from two source files. Looks correct to me.
Ok, sorry, my mistake.
What's the reason behind creating tmio_mmc_core.o instead of simply
having tmio_mmc_pio.o + tmio_mmc_dma.o? That must be the most
straightforward solution, no?
Thanks,
/ magnus
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 3/6] mmc: tmio: convert the SDHI MMC driver from MFD to a
2011-03-11 7:52 ` [PATCH 3/6] mmc: tmio: convert the SDHI MMC driver from MFD to a Guennadi Liakhovetski
@ 2011-03-13 4:14 ` Magnus Damm
2011-03-14 8:01 ` [PATCH 3/6] mmc: tmio: convert the SDHI MMC driver from MFD to Guennadi Liakhovetski
0 siblings, 1 reply; 27+ messages in thread
From: Magnus Damm @ 2011-03-13 4:14 UTC (permalink / raw)
To: Guennadi Liakhovetski; +Cc: linux-sh, linux-mmc, Chris Ball, Ian Molton
On Fri, Mar 11, 2011 at 4:52 PM, Guennadi Liakhovetski
<g.liakhovetski@gmx.de> wrote:
> On sh-mobile platforms the SDHI driver was using the tmio_mmc SD/SDIO
> MFD cell driver. Now that the tmio_mmc driver has been split into a
> core and a separate MFD glue, we can support SDHI natively without the
> need to emulate an MFD controller. This also allows to support systems
> with an on-SoC SDHI controller and a separate MFD with a TMIO core.
>
> Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> ---
Nice, I believe this is the right direction..
> --- a/drivers/mmc/host/tmio_mmc.h
> +++ b/drivers/mmc/host/tmio_mmc.h
> @@ -92,7 +92,7 @@ struct tmio_mmc_host {
> struct tasklet_struct dma_complete;
> struct tasklet_struct dma_issue;
> struct scatterlist bounce_sg;
> -#ifdef CONFIG_TMIO_MMC_DMA
> +#if defined(CONFIG_MMC_SDHI) || defined(CONFIG_MMC_SDHI_MODULE)
> u8 bounce_buf[PAGE_CACHE_SIZE] __attribute__((aligned(TMIO_MAX_ALIGN)));
> #else
> u8 bounce_buf[1]; /* A dummy in no-DMA case */
... but it would be nice if all this #ifdeffery could be avoided somehow.
Is it possible to use devres to allocate the bounce buffer dynamically
in the dma portion of the code?
/ magnus
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 1/6] mmc: tmio: split core functionality, DMA and MFD
2011-03-13 3:57 ` [PATCH 1/6] mmc: tmio: split core functionality, DMA and MFD glue Magnus Damm
@ 2011-03-13 22:51 ` Guennadi Liakhovetski
2011-03-15 9:01 ` [PATCH 1/6] mmc: tmio: split core functionality, DMA and MFD glue Magnus Damm
0 siblings, 1 reply; 27+ messages in thread
From: Guennadi Liakhovetski @ 2011-03-13 22:51 UTC (permalink / raw)
To: Magnus Damm; +Cc: linux-sh, linux-mmc, Chris Ball, Ian Molton
On Sun, 13 Mar 2011, Magnus Damm wrote:
> On Sun, Mar 13, 2011 at 7:48 AM, Guennadi Liakhovetski
> <g.liakhovetski@gmx.de> wrote:
> > On Sun, 13 Mar 2011, Magnus Damm wrote:
> >
> >> On Fri, Mar 11, 2011 at 4:51 PM, Guennadi Liakhovetski
> >> <g.liakhovetski@gmx.de> wrote:
> >> > TMIO MMC chips contain an SD / SDIO IP core from Panasonic, similar to
> >> > the one, used in MN5774 and other MN57xx controllers. These IP cores are
> >> > included in many multifunction devices, in sh-mobile chips from Renesas,
> >> > in the latter case they can also use DMA. Some sh-mobile implementations
> >> > also have some other specialities, that MFD-based solutions don't have.
> >> > This makes supporting all these features in a monolithic driver inconveniet
> >> > and error-prone. This patch splits the driver into 3 parts: the core,
> >> > the MFD glue and the DMA support. In case of a modular build, two modules
> >> > will be built: mmc_tmio_core and mmc_tmio.
> >> >
> >> > Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> >> > ---
> >>
> >> Thanks for your work on this, I'm happy to see these patches because
> >> they make it easier for me to add multi-interrupt source to the SDHI
> >> portion - something that is needed for sh73a0.
> >>
> >> > drivers/mmc/host/Kconfig | 4 +
> >> > drivers/mmc/host/Makefile | 3 +
> >> > drivers/mmc/host/tmio_mmc.c | 1303 +--------------------------------------
> >> > drivers/mmc/host/tmio_mmc.h | 152 +++++
> >> > drivers/mmc/host/tmio_mmc_dma.c | 302 +++++++++
> >> > drivers/mmc/host/tmio_mmc_pio.c | 923 +++++++++++++++++++++++++++
> >> > 6 files changed, 1402 insertions(+), 1285 deletions(-)
> >> > create mode 100644 drivers/mmc/host/tmio_mmc.h
> >> > create mode 100644 drivers/mmc/host/tmio_mmc_dma.c
> >> > create mode 100644 drivers/mmc/host/tmio_mmc_pio.c
> >>
> >> Something is wrong with this patch. The Makefile adds tmio_mmc_core.c
> >> but it's not part of the diffstat above. Perhaps you're posting an
> >> older version of the patch?
> >
> > No, the Makefile is adding tmio_mmc_core.o:
> >
> > diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
> > index 30aa686..79c42dd 100644
> > --- a/drivers/mmc/host/Makefile
> > +++ b/drivers/mmc/host/Makefile
> > @@ -29,6 +29,9 @@ endif
> > obj-$(CONFIG_MMC_S3C) += s3cmci.o
> > obj-$(CONFIG_MMC_SDRICOH_CS) += sdricoh_cs.o
> > obj-$(CONFIG_MMC_TMIO) += tmio_mmc.o
> > +obj-$(CONFIG_MMC_TMIO_CORE) += tmio_mmc_core.o
> > +tmio_mmc_core-y := tmio_mmc_pio.o
> > +tmio_mmc_core-$(CONFIG_TMIO_MMC_DMA) += tmio_mmc_dma.o
> > obj-$(CONFIG_MMC_CB710) += cb710-mmc.o
> > obj-$(CONFIG_MMC_VIA_SDMMC) += via-sdmmc.o
> > obj-$(CONFIG_SDH_BFIN) += bfin_sdh.o
> >
> > which is linked from two source files. Looks correct to me.
>
> Ok, sorry, my mistake.
>
> What's the reason behind creating tmio_mmc_core.o instead of simply
> having tmio_mmc_pio.o + tmio_mmc_dma.o? That must be the most
> straightforward solution, no?
You mean two kernel modules ..._pio.ko and ..._dma.ko? but why?... I don't
see any advantages in such a split, besides, they are calling into each
other ATM.
Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 3/6] mmc: tmio: convert the SDHI MMC driver from MFD to
2011-03-13 4:14 ` Magnus Damm
@ 2011-03-14 8:01 ` Guennadi Liakhovetski
2011-03-15 9:09 ` [PATCH 3/6] mmc: tmio: convert the SDHI MMC driver from MFD to a Magnus Damm
0 siblings, 1 reply; 27+ messages in thread
From: Guennadi Liakhovetski @ 2011-03-14 8:01 UTC (permalink / raw)
To: Magnus Damm; +Cc: linux-sh, linux-mmc, Chris Ball, Ian Molton
On Sun, 13 Mar 2011, Magnus Damm wrote:
> On Fri, Mar 11, 2011 at 4:52 PM, Guennadi Liakhovetski
> <g.liakhovetski@gmx.de> wrote:
> > On sh-mobile platforms the SDHI driver was using the tmio_mmc SD/SDIO
> > MFD cell driver. Now that the tmio_mmc driver has been split into a
> > core and a separate MFD glue, we can support SDHI natively without the
> > need to emulate an MFD controller. This also allows to support systems
> > with an on-SoC SDHI controller and a separate MFD with a TMIO core.
> >
> > Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> > ---
>
> Nice, I believe this is the right direction..
>
> > --- a/drivers/mmc/host/tmio_mmc.h
> > +++ b/drivers/mmc/host/tmio_mmc.h
> > @@ -92,7 +92,7 @@ struct tmio_mmc_host {
> > struct tasklet_struct dma_complete;
> > struct tasklet_struct dma_issue;
> > struct scatterlist bounce_sg;
> > -#ifdef CONFIG_TMIO_MMC_DMA
> > +#if defined(CONFIG_MMC_SDHI) || defined(CONFIG_MMC_SDHI_MODULE)
> > u8 bounce_buf[PAGE_CACHE_SIZE] __attribute__((aligned(TMIO_MAX_ALIGN)));
> > #else
> > u8 bounce_buf[1]; /* A dummy in no-DMA case */
>
> ... but it would be nice if all this #ifdeffery could be avoided somehow.
>
> Is it possible to use devres to allocate the bounce buffer dynamically
> in the dma portion of the code?
Well, this #ifdef has been there before, it's not new. But sure, we could
get rid of it. Basically, what you're suggesting, is to allocate that
bounce buffer dynamically - whether or not using devres. Just calling
__get_free_page() in tmio_mmc_request_dma() and __free_pages() in
tmio_mmc_release_dma() should work without any memory-leaking too. Would
this be ok?
Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 1/6] mmc: tmio: split core functionality, DMA and MFD glue
2011-03-13 22:51 ` [PATCH 1/6] mmc: tmio: split core functionality, DMA and MFD Guennadi Liakhovetski
@ 2011-03-15 9:01 ` Magnus Damm
2011-03-16 11:09 ` Ian Molton
0 siblings, 1 reply; 27+ messages in thread
From: Magnus Damm @ 2011-03-15 9:01 UTC (permalink / raw)
To: Guennadi Liakhovetski; +Cc: linux-sh, linux-mmc, Chris Ball, Ian Molton
On Mon, Mar 14, 2011 at 7:51 AM, Guennadi Liakhovetski
<g.liakhovetski@gmx.de> wrote:
> On Sun, 13 Mar 2011, Magnus Damm wrote:
>> On Sun, Mar 13, 2011 at 7:48 AM, Guennadi Liakhovetski
>> <g.liakhovetski@gmx.de> wrote:
>> > On Sun, 13 Mar 2011, Magnus Damm wrote:
>> >> On Fri, Mar 11, 2011 at 4:51 PM, Guennadi Liakhovetski
>> >> <g.liakhovetski@gmx.de> wrote:
>> >> > TMIO MMC chips contain an SD / SDIO IP core from Panasonic, similar to
>> >> > the one, used in MN5774 and other MN57xx controllers. These IP cores are
>> >> > included in many multifunction devices, in sh-mobile chips from Renesas,
>> >> > in the latter case they can also use DMA. Some sh-mobile implementations
>> >> > also have some other specialities, that MFD-based solutions don't have.
>> >> > This makes supporting all these features in a monolithic driver inconveniet
>> >> > and error-prone. This patch splits the driver into 3 parts: the core,
>> >> > the MFD glue and the DMA support. In case of a modular build, two modules
>> >> > will be built: mmc_tmio_core and mmc_tmio.
>> >> >
>> >> > Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
>> >> > ---
>> What's the reason behind creating tmio_mmc_core.o instead of simply
>> having tmio_mmc_pio.o + tmio_mmc_dma.o? That must be the most
>> straightforward solution, no?
>
> You mean two kernel modules ..._pio.ko and ..._dma.ko? but why?... I don't
> see any advantages in such a split, besides, they are calling into each
> other ATM.
Yeah, two kernel modules. That would be the cleanest IMO. But it's not
such a big deal though, if you think this split is the best and
everyone else is happy then I'm fine as well.
Thanks,
/ magnus
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 3/6] mmc: tmio: convert the SDHI MMC driver from MFD to a
2011-03-14 8:01 ` [PATCH 3/6] mmc: tmio: convert the SDHI MMC driver from MFD to Guennadi Liakhovetski
@ 2011-03-15 9:09 ` Magnus Damm
0 siblings, 0 replies; 27+ messages in thread
From: Magnus Damm @ 2011-03-15 9:09 UTC (permalink / raw)
To: Guennadi Liakhovetski; +Cc: linux-sh, linux-mmc, Chris Ball, Ian Molton
On Mon, Mar 14, 2011 at 5:01 PM, Guennadi Liakhovetski
<g.liakhovetski@gmx.de> wrote:
> On Sun, 13 Mar 2011, Magnus Damm wrote:
>> On Fri, Mar 11, 2011 at 4:52 PM, Guennadi Liakhovetski
>> <g.liakhovetski@gmx.de> wrote:
>> > On sh-mobile platforms the SDHI driver was using the tmio_mmc SD/SDIO
>> > MFD cell driver. Now that the tmio_mmc driver has been split into a
>> > core and a separate MFD glue, we can support SDHI natively without the
>> > need to emulate an MFD controller. This also allows to support systems
>> > with an on-SoC SDHI controller and a separate MFD with a TMIO core.
>> >
>> > Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
>> > ---
>>
>> Nice, I believe this is the right direction..
>>
>> > --- a/drivers/mmc/host/tmio_mmc.h
>> > +++ b/drivers/mmc/host/tmio_mmc.h
>> > @@ -92,7 +92,7 @@ struct tmio_mmc_host {
>> > struct tasklet_struct dma_complete;
>> > struct tasklet_struct dma_issue;
>> > struct scatterlist bounce_sg;
>> > -#ifdef CONFIG_TMIO_MMC_DMA
>> > +#if defined(CONFIG_MMC_SDHI) || defined(CONFIG_MMC_SDHI_MODULE)
>> > u8 bounce_buf[PAGE_CACHE_SIZE] __attribute__((aligned(TMIO_MAX_ALIGN)));
>> > #else
>> > u8 bounce_buf[1]; /* A dummy in no-DMA case */
>>
>> ... but it would be nice if all this #ifdeffery could be avoided somehow.
>>
>> Is it possible to use devres to allocate the bounce buffer dynamically
>> in the dma portion of the code?
>
> Well, this #ifdef has been there before, it's not new. But sure, we could
> get rid of it. Basically, what you're suggesting, is to allocate that
> bounce buffer dynamically - whether or not using devres. Just calling
> __get_free_page() in tmio_mmc_request_dma() and __free_pages() in
> tmio_mmc_release_dma() should work without any memory-leaking too. Would
> this be ok?
Yes, tmio_mmc_request_dma() and tmio_mmc_free_dma() happen very
infrequently so that seems like a very good location for dynamic
allocation / free of the bounce buffer. Thanks!
/ magnus
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 0/6] mmc: split the tmio driver into several modules
2011-03-11 7:51 [PATCH 0/6] mmc: split the tmio driver into several modules Guennadi Liakhovetski
` (5 preceding siblings ...)
2011-03-11 7:52 ` [PATCH 6/6] mfd: remove now redundant sh_mobile_sdhi.h header Guennadi Liakhovetski
@ 2011-03-15 21:25 ` Ian Molton
2011-03-21 11:38 ` Guennadi Liakhovetski
6 siblings, 1 reply; 27+ messages in thread
From: Ian Molton @ 2011-03-15 21:25 UTC (permalink / raw)
To: Guennadi Liakhovetski; +Cc: linux-sh, linux-mmc, Chris Ball
Sounds like a good idea... Its possible that I could implement DMA on
the toshiba stuff too, can your code handle this?
(I havent had time to read this yet)
--
Ian Molton
Linux, Automotive, and other hacking:
http://www.mnementh.co.uk/
On 11 March 2011 07:51, Guennadi Liakhovetski <g.liakhovetski@gmx.de> wrote:
> Hi all
>
> The tmio_mmc SD/SDIO driver is serving very different hardware
> configurations: on the one hand multi-function style chips from Toshiba,
> Compaq, on the other hand SDHI units in ARM- and SuperH-based sh-mobile
> SoCs. Apart from the different native APIs: MFD for the former and
> platform-device in the latter, sh-mobile implementations also have a
> number of features, exclusive to them, which, if implemented in the common
> driver, clutter it needlessly and make its maintenance more difficult.
> This patch series simplifies the situation by splitting the driver up into
> 3 modules: the core, consisting of the main part and, on sh-mobile, of the
> DMA part; the mfd glue; and the platform glue. This way also (imaginary)
> sh-mobile systems with additional tmio mfd chips on them can be supported.
>
> Thanks
> Guennadi
> ---
> Guennadi Liakhovetski, Ph.D.
> Freelance Open-Source Software Developer
> http://www.open-technology.de/
>
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 1/6] mmc: tmio: split core functionality, DMA and MFD glue
2011-03-15 9:01 ` [PATCH 1/6] mmc: tmio: split core functionality, DMA and MFD glue Magnus Damm
@ 2011-03-16 11:09 ` Ian Molton
2011-03-16 12:37 ` Magnus Damm
0 siblings, 1 reply; 27+ messages in thread
From: Ian Molton @ 2011-03-16 11:09 UTC (permalink / raw)
To: Magnus Damm; +Cc: Guennadi Liakhovetski, linux-sh, linux-mmc, Chris Ball
Im fine with it as long as it doesnt complicate my plan to add PXA DMA
to the driver.
--
Ian Molton
Linux, Automotive, and other hacking:
http://www.mnementh.co.uk/
On 15 March 2011 09:01, Magnus Damm <magnus.damm@gmail.com> wrote:
> On Mon, Mar 14, 2011 at 7:51 AM, Guennadi Liakhovetski
> <g.liakhovetski@gmx.de> wrote:
>> On Sun, 13 Mar 2011, Magnus Damm wrote:
>>> On Sun, Mar 13, 2011 at 7:48 AM, Guennadi Liakhovetski
>>> <g.liakhovetski@gmx.de> wrote:
>>> > On Sun, 13 Mar 2011, Magnus Damm wrote:
>>> >> On Fri, Mar 11, 2011 at 4:51 PM, Guennadi Liakhovetski
>>> >> <g.liakhovetski@gmx.de> wrote:
>>> >> > TMIO MMC chips contain an SD / SDIO IP core from Panasonic, similar to
>>> >> > the one, used in MN5774 and other MN57xx controllers. These IP cores are
>>> >> > included in many multifunction devices, in sh-mobile chips from Renesas,
>>> >> > in the latter case they can also use DMA. Some sh-mobile implementations
>>> >> > also have some other specialities, that MFD-based solutions don't have.
>>> >> > This makes supporting all these features in a monolithic driver inconveniet
>>> >> > and error-prone. This patch splits the driver into 3 parts: the core,
>>> >> > the MFD glue and the DMA support. In case of a modular build, two modules
>>> >> > will be built: mmc_tmio_core and mmc_tmio.
>>> >> >
>>> >> > Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
>>> >> > ---
>
>>> What's the reason behind creating tmio_mmc_core.o instead of simply
>>> having tmio_mmc_pio.o + tmio_mmc_dma.o? That must be the most
>>> straightforward solution, no?
>>
>> You mean two kernel modules ..._pio.ko and ..._dma.ko? but why?... I don't
>> see any advantages in such a split, besides, they are calling into each
>> other ATM.
>
> Yeah, two kernel modules. That would be the cleanest IMO. But it's not
> such a big deal though, if you think this split is the best and
> everyone else is happy then I'm fine as well.
>
> Thanks,
>
> / magnus
>
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 1/6] mmc: tmio: split core functionality, DMA and MFD glue
2011-03-16 11:09 ` Ian Molton
@ 2011-03-16 12:37 ` Magnus Damm
2011-03-21 11:19 ` [PATCH 1/6] mmc: tmio: split core functionality, DMA and MFD Guennadi Liakhovetski
0 siblings, 1 reply; 27+ messages in thread
From: Magnus Damm @ 2011-03-16 12:37 UTC (permalink / raw)
To: Ian Molton; +Cc: Guennadi Liakhovetski, linux-sh, linux-mmc, Chris Ball
>>>> >> On Fri, Mar 11, 2011 at 4:51 PM, Guennadi Liakhovetski
>>>> >> <g.liakhovetski@gmx.de> wrote:
>>>> >> > TMIO MMC chips contain an SD / SDIO IP core from Panasonic, similar to
>>>> >> > the one, used in MN5774 and other MN57xx controllers. These IP cores are
>>>> >> > included in many multifunction devices, in sh-mobile chips from Renesas,
>>>> >> > in the latter case they can also use DMA. Some sh-mobile implementations
>>>> >> > also have some other specialities, that MFD-based solutions don't have.
>>>> >> > This makes supporting all these features in a monolithic driver inconveniet
>>>> >> > and error-prone. This patch splits the driver into 3 parts: the core,
>>>> >> > the MFD glue and the DMA support. In case of a modular build, two modules
>>>> >> > will be built: mmc_tmio_core and mmc_tmio.
>>>> >> >
>>>> >> > Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
On Wed, Mar 16, 2011 at 8:09 PM, Ian Molton <ian@mnementh.co.uk> wrote:
> Im fine with it as long as it doesnt complicate my plan to add PXA DMA
> to the driver.
Hi Ian,
Thanks for your email. I'm glad to hear that you have no objections to
this patch series.
Regarding PXA DMA, without knowing the PXA DMA hardware that well
(never recall using DMA on that platform), from a code reuse point of
view it would be absolutely best to share the DMA Engine interface in
the tmio mmc driver with the SDHI. But I'm not sure if any DMA Engine
driver exists for the PXA though.
Thanks,
/ magnus
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 1/6] mmc: tmio: split core functionality, DMA and MFD
2011-03-16 12:37 ` Magnus Damm
@ 2011-03-21 11:19 ` Guennadi Liakhovetski
0 siblings, 0 replies; 27+ messages in thread
From: Guennadi Liakhovetski @ 2011-03-21 11:19 UTC (permalink / raw)
To: Magnus Damm; +Cc: Ian Molton, linux-sh, linux-mmc, Chris Ball
Hi Ian
On Wed, 16 Mar 2011, Magnus Damm wrote:
> >>>> >> On Fri, Mar 11, 2011 at 4:51 PM, Guennadi Liakhovetski
> >>>> >> <g.liakhovetski@gmx.de> wrote:
> >>>> >> > TMIO MMC chips contain an SD / SDIO IP core from Panasonic, similar to
> >>>> >> > the one, used in MN5774 and other MN57xx controllers. These IP cores are
> >>>> >> > included in many multifunction devices, in sh-mobile chips from Renesas,
> >>>> >> > in the latter case they can also use DMA. Some sh-mobile implementations
> >>>> >> > also have some other specialities, that MFD-based solutions don't have.
> >>>> >> > This makes supporting all these features in a monolithic driver inconveniet
> >>>> >> > and error-prone. This patch splits the driver into 3 parts: the core,
> >>>> >> > the MFD glue and the DMA support. In case of a modular build, two modules
> >>>> >> > will be built: mmc_tmio_core and mmc_tmio.
> >>>> >> >
> >>>> >> > Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
>
> On Wed, Mar 16, 2011 at 8:09 PM, Ian Molton <ian@mnementh.co.uk> wrote:
> > Im fine with it as long as it doesnt complicate my plan to add PXA DMA
> > to the driver.
>
> Hi Ian,
>
> Thanks for your email. I'm glad to hear that you have no objections to
> this patch series.
>
> Regarding PXA DMA, without knowing the PXA DMA hardware that well
> (never recall using DMA on that platform), from a code reuse point of
> view it would be absolutely best to share the DMA Engine interface in
> the tmio mmc driver with the SDHI. But I'm not sure if any DMA Engine
> driver exists for the PXA though.
I presume you're talking about an external tmio MFD chip connected to a
PXA SoC. Concerning adding DMA to this configuration, just like Magnus, I
am not aware of any dmaengine implementations for PXA. I know, there is a
private PXA DMA API, used, e.g., in pxa_camera.c and defined in
arch/arm/plat-pxa/dma.c. I think, that's also what you would use for
external DMA.
There has been a discussion whether the dmaengine API should be used
universally, and the conclusion more or less was:
1. if your DMA engine can do standard operations like memcpy, xor, then
yes
2. if you use drivers for external hardware or built-in IP blocks, that
use the dmaengine API, then yes
3. otherwise it's not compulsory
So, until now PXA didn't have any of the (1) or (2) cases. Now, if you
want to use tmio on PXA you have a choice: either (1) to add a new DMA
glue to tmio for PXA, or (2) to add a dmaengine API to PXA DMA. The latter
seems to be preferred. But even if you decide to go the first route, this
driver split shall make your work easier.
Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 0/6] mmc: split the tmio driver into several modules
2011-03-15 21:25 ` [PATCH 0/6] mmc: split the tmio driver into several modules Ian Molton
@ 2011-03-21 11:38 ` Guennadi Liakhovetski
2011-03-22 5:31 ` Simon Horman
0 siblings, 1 reply; 27+ messages in thread
From: Guennadi Liakhovetski @ 2011-03-21 11:38 UTC (permalink / raw)
To: Ian Molton; +Cc: linux-sh, linux-mmc, Chris Ball, Magnus Damm
Hi Chris, Ian
AFAICS there are currently still a few tmio patch-series outstanding:
From: Guennadi Liakhovetski <g.liakhovetski <at> gmx.de>
Subject: [PATCH 0/2] tmio_mmc: improve DMA reliability
http://thread.gmane.org/gmane.linux.kernel.mmc/6485
From: Simon Horman <horms <at> verge.net.au>
Subject: [PATCH 0/4] [rfc v3] mmc, ARM: Add zboot from eSD support for SuperH Mobile ARM
http://thread.gmane.org/gmane.linux.kernel.mmc/6664
From: Guennadi Liakhovetski <g.liakhovetski <at> gmx.de>
Subject: [PATCH 0/6] mmc: split the tmio driver into several modules
http://thread.gmane.org/gmane.linux.ports.sh.devel/10304
From: Guennadi Liakhovetski <g.liakhovetski <at> gmx.de>
Subject: [PATCH 0/4 v2] mmc: tmio: don't access nonexisting registers
http://thread.gmane.org/gmane.linux.ports.sh.devel/10311
From: Guennadi Liakhovetski <g.liakhovetski <at> gmx.de>
Subject: [PATCH/RFC 0/2 v2] mmc: tmio: power management and clock gating
http://thread.gmane.org/gmane.linux.kernel.mmc/6627
Of those the first patchset shouldn't have any issues.
I haven't followed discussions regarding the second patchset from Simon -
is it going to be applied as is, or is a new revision required?
If it is going to be applied, shall I rebase my remaining patches on top
of it or would you prefer Simon to rebase his patches (I think, he has
only one patch, touching tmio: [PATCH 1/4])? As for the rest of the
patches, IIRC, the only remaining issue, that I'll be fixing today is
Magnus' wish to allocate the bounce buffer dynamically. Although, I could
imagine doing that incrementally, because the #ifdef, that Magnus would
like to get rid of is already now in the code, it is not introduced by
these my patches. But I can redo my patches too, no problem.
What would be the preferred approach?
Thanks
Guennadi
On Tue, 15 Mar 2011, Ian Molton wrote:
> Sounds like a good idea... Its possible that I could implement DMA on
> the toshiba stuff too, can your code handle this?
>
> (I havent had time to read this yet)
>
> --
> Ian Molton
> Linux, Automotive, and other hacking:
> http://www.mnementh.co.uk/
>
>
>
> On 11 March 2011 07:51, Guennadi Liakhovetski <g.liakhovetski@gmx.de> wrote:
> > Hi all
> >
> > The tmio_mmc SD/SDIO driver is serving very different hardware
> > configurations: on the one hand multi-function style chips from Toshiba,
> > Compaq, on the other hand SDHI units in ARM- and SuperH-based sh-mobile
> > SoCs. Apart from the different native APIs: MFD for the former and
> > platform-device in the latter, sh-mobile implementations also have a
> > number of features, exclusive to them, which, if implemented in the common
> > driver, clutter it needlessly and make its maintenance more difficult.
> > This patch series simplifies the situation by splitting the driver up into
> > 3 modules: the core, consisting of the main part and, on sh-mobile, of the
> > DMA part; the mfd glue; and the platform glue. This way also (imaginary)
> > sh-mobile systems with additional tmio mfd chips on them can be supported.
> >
> > Thanks
> > Guennadi
> > ---
> > Guennadi Liakhovetski, Ph.D.
> > Freelance Open-Source Software Developer
> > http://www.open-technology.de/
> >
>
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 0/6] mmc: split the tmio driver into several modules
2011-03-21 11:38 ` Guennadi Liakhovetski
@ 2011-03-22 5:31 ` Simon Horman
2011-03-22 12:28 ` Paul Mundt
0 siblings, 1 reply; 27+ messages in thread
From: Simon Horman @ 2011-03-22 5:31 UTC (permalink / raw)
To: Guennadi Liakhovetski
Cc: Ian Molton, linux-sh, linux-mmc, Chris Ball, Magnus Damm
On Mon, Mar 21, 2011 at 12:38:10PM +0100, Guennadi Liakhovetski wrote:
> Hi Chris, Ian
>
> AFAICS there are currently still a few tmio patch-series outstanding:
>
> From: Guennadi Liakhovetski <g.liakhovetski <at> gmx.de>
> Subject: [PATCH 0/2] tmio_mmc: improve DMA reliability
> http://thread.gmane.org/gmane.linux.kernel.mmc/6485
>
> From: Simon Horman <horms <at> verge.net.au>
> Subject: [PATCH 0/4] [rfc v3] mmc, ARM: Add zboot from eSD support for SuperH Mobile ARM
> http://thread.gmane.org/gmane.linux.kernel.mmc/6664
IMHO, Patch 1-3 are ready and can either be merged through the MMC
or one of Paul's trees. Although I should note that patches
2 and 3 include changes to arch/arm/boot/compressed/mmcif-sh7372.c and
arch/sh/boot/romimage/mmcif-sh7724.c.
Please wait on 4, which depends on 1-3, and I would like to do
one more round of testing. In any case it'll most likely need to go
through RMK's tree.
> From: Guennadi Liakhovetski <g.liakhovetski <at> gmx.de>
> Subject: [PATCH 0/6] mmc: split the tmio driver into several modules
> http://thread.gmane.org/gmane.linux.ports.sh.devel/10304
>
> From: Guennadi Liakhovetski <g.liakhovetski <at> gmx.de>
> Subject: [PATCH 0/4 v2] mmc: tmio: don't access nonexisting registers
> http://thread.gmane.org/gmane.linux.ports.sh.devel/10311
>
> From: Guennadi Liakhovetski <g.liakhovetski <at> gmx.de>
> Subject: [PATCH/RFC 0/2 v2] mmc: tmio: power management and clock gating
> http://thread.gmane.org/gmane.linux.kernel.mmc/6627
>
> Of those the first patchset shouldn't have any issues.
>
> I haven't followed discussions regarding the second patchset from Simon -
> is it going to be applied as is, or is a new revision required?
I do not currently have any plans to revise patches 1-3.
> If it is going to be applied, shall I rebase my remaining patches on top
> of it or would you prefer Simon to rebase his patches (I think, he has
> only one patch, touching tmio: [PATCH 1/4])?
1-3 include MMC changes but only patch 1 includes TMIO changes.
I am happy for either my patches to go in first or for me to re-base them
on top of yours. I'm also happy for you to re-base my patches (1 or 1-3)
and include them in a patchset if that works for you.
> As for the rest of the
> patches, IIRC, the only remaining issue, that I'll be fixing today is
> Magnus' wish to allocate the bounce buffer dynamically. Although, I could
> imagine doing that incrementally, because the #ifdef, that Magnus would
> like to get rid of is already now in the code, it is not introduced by
> these my patches. But I can redo my patches too, no problem.
>
> What would be the preferred approach?
>
> Thanks
> Guennadi
>
> On Tue, 15 Mar 2011, Ian Molton wrote:
>
> > Sounds like a good idea... Its possible that I could implement DMA on
> > the toshiba stuff too, can your code handle this?
> >
> > (I havent had time to read this yet)
> >
> > --
> > Ian Molton
> > Linux, Automotive, and other hacking:
> > http://www.mnementh.co.uk/
> >
> >
> >
> > On 11 March 2011 07:51, Guennadi Liakhovetski <g.liakhovetski@gmx.de> wrote:
> > > Hi all
> > >
> > > The tmio_mmc SD/SDIO driver is serving very different hardware
> > > configurations: on the one hand multi-function style chips from Toshiba,
> > > Compaq, on the other hand SDHI units in ARM- and SuperH-based sh-mobile
> > > SoCs. Apart from the different native APIs: MFD for the former and
> > > platform-device in the latter, sh-mobile implementations also have a
> > > number of features, exclusive to them, which, if implemented in the common
> > > driver, clutter it needlessly and make its maintenance more difficult.
> > > This patch series simplifies the situation by splitting the driver up into
> > > 3 modules: the core, consisting of the main part and, on sh-mobile, of the
> > > DMA part; the mfd glue; and the platform glue. This way also (imaginary)
> > > sh-mobile systems with additional tmio mfd chips on them can be supported.
> > >
> > > Thanks
> > > Guennadi
> > > ---
> > > Guennadi Liakhovetski, Ph.D.
> > > Freelance Open-Source Software Developer
> > > http://www.open-technology.de/
> > >
> >
>
> ---
> Guennadi Liakhovetski, Ph.D.
> Freelance Open-Source Software Developer
> http://www.open-technology.de/
> --
> To unsubscribe from this list: send the line "unsubscribe linux-sh" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 0/6] mmc: split the tmio driver into several modules
2011-03-22 5:31 ` Simon Horman
@ 2011-03-22 12:28 ` Paul Mundt
2011-03-22 22:06 ` Simon Horman
0 siblings, 1 reply; 27+ messages in thread
From: Paul Mundt @ 2011-03-22 12:28 UTC (permalink / raw)
To: Simon Horman
Cc: Guennadi Liakhovetski, Ian Molton, linux-sh, linux-mmc,
Chris Ball, Magnus Damm
On Tue, Mar 22, 2011 at 02:31:31PM +0900, Simon Horman wrote:
> On Mon, Mar 21, 2011 at 12:38:10PM +0100, Guennadi Liakhovetski wrote:
> > Hi Chris, Ian
> >
> > AFAICS there are currently still a few tmio patch-series outstanding:
> >
> > From: Guennadi Liakhovetski <g.liakhovetski <at> gmx.de>
> > Subject: [PATCH 0/2] tmio_mmc: improve DMA reliability
> > http://thread.gmane.org/gmane.linux.kernel.mmc/6485
> >
> > From: Simon Horman <horms <at> verge.net.au>
> > Subject: [PATCH 0/4] [rfc v3] mmc, ARM: Add zboot from eSD support for SuperH Mobile ARM
> > http://thread.gmane.org/gmane.linux.kernel.mmc/6664
>
> IMHO, Patch 1-3 are ready and can either be merged through the MMC
> or one of Paul's trees. Although I should note that patches
> 2 and 3 include changes to arch/arm/boot/compressed/mmcif-sh7372.c and
> arch/sh/boot/romimage/mmcif-sh7724.c.
>
I'm having a hard time working out what these arbitrary 1-3 numbers map
to in terms of actual series and patch numbers. As far as things with an
sh or rmobile impact I see:
sh: ecovec: use the CONFIG_MMC_TMIO symbols instead of MFD
and
[rfc v3] mmc, ARM: Add zboot from eSD support for SuperH Mobile ARM
although it's not obvious how the latter is tied to a TMIO dependency
(some SDHI header thing?).
I'm happy to take the ecovec patch whenever, since it doesn't really hurt
anything. Anything touching drivers/mmc I obviously prefer to go via Chris.
I got buried in the fbdev patch queue today, so I'll be catching up on sh and
rmobile stuff tomorrow. You're free to work out amongst yourselves what gets
applied where in which order, or I'll simply guess.
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 0/6] mmc: split the tmio driver into several modules
2011-03-22 12:28 ` Paul Mundt
@ 2011-03-22 22:06 ` Simon Horman
2011-03-23 14:54 ` Paul Mundt
0 siblings, 1 reply; 27+ messages in thread
From: Simon Horman @ 2011-03-22 22:06 UTC (permalink / raw)
To: Paul Mundt
Cc: Guennadi Liakhovetski, Ian Molton, linux-sh, linux-mmc,
Chris Ball, Magnus Damm
On Tue, Mar 22, 2011 at 09:28:50PM +0900, Paul Mundt wrote:
> On Tue, Mar 22, 2011 at 02:31:31PM +0900, Simon Horman wrote:
> > On Mon, Mar 21, 2011 at 12:38:10PM +0100, Guennadi Liakhovetski wrote:
> > > Hi Chris, Ian
> > >
> > > AFAICS there are currently still a few tmio patch-series outstanding:
> > >
> > > From: Guennadi Liakhovetski <g.liakhovetski <at> gmx.de>
> > > Subject: [PATCH 0/2] tmio_mmc: improve DMA reliability
> > > http://thread.gmane.org/gmane.linux.kernel.mmc/6485
> > >
> > > From: Simon Horman <horms <at> verge.net.au>
> > > Subject: [PATCH 0/4] [rfc v3] mmc, ARM: Add zboot from eSD support for SuperH Mobile ARM
> > > http://thread.gmane.org/gmane.linux.kernel.mmc/6664
> >
> > IMHO, Patch 1-3 are ready and can either be merged through the MMC
> > or one of Paul's trees. Although I should note that patches
> > 2 and 3 include changes to arch/arm/boot/compressed/mmcif-sh7372.c and
> > arch/sh/boot/romimage/mmcif-sh7724.c.
> >
> I'm having a hard time working out what these arbitrary 1-3 numbers map
> to in terms of actual series and patch numbers. As far as things with an
> sh or rmobile impact I see:
>
> sh: ecovec: use the CONFIG_MMC_TMIO symbols instead of MFD
>
> and
>
> [rfc v3] mmc, ARM: Add zboot from eSD support for SuperH Mobile ARM
>
> although it's not obvious how the latter is tied to a TMIO dependency
> (some SDHI header thing?).
>
> I'm happy to take the ecovec patch whenever, since it doesn't really hurt
> anything. Anything touching drivers/mmc I obviously prefer to go via Chris.
>
> I got buried in the fbdev patch queue today, so I'll be catching up on sh and
> rmobile stuff tomorrow. You're free to work out amongst yourselves what gets
> applied where in which order, or I'll simply guess.
Hi Paul,
By 1-3 I was referring to the first three patches of
[PATCH 0/4] [rfc v3] mmc, ARM: Add zboot from eSD support for SuperH Mobile ARM
That is:
[PATCH 1/4] mmc: tmio_mmc: Move some defines into a shared header
[PATCH 2/4] mmc, ARM: Rename SuperH Mobile ARM zboot helpers
[PATCH 3/4] mmc: Add MMC_PROGRESS_*
And by patch 4 I was referring to
[PATCH 4/4 v5] mmc, ARM: Add zboot from eSD support for SuperH Mobile
I apologise for that being as clear as mud.
Magnus raised a build issue with the series since my previous email.
I will investigate that and reply to him ASAP. Its probably best
to hold all the patches until then.
With regards to
[PATCH 2/6] sh: ecovec: use the CONFIG_MMC_TMIO symbols instead of MFD
it looks like Magnus raised a few issues and Guennadi is going to repost
the patch. But I could be wrong.
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 0/6] mmc: split the tmio driver into several modules
2011-03-22 22:06 ` Simon Horman
@ 2011-03-23 14:54 ` Paul Mundt
2011-03-23 22:42 ` Simon Horman
0 siblings, 1 reply; 27+ messages in thread
From: Paul Mundt @ 2011-03-23 14:54 UTC (permalink / raw)
To: Simon Horman
Cc: Guennadi Liakhovetski, Ian Molton, linux-sh, linux-mmc,
Chris Ball, Magnus Damm
On Wed, Mar 23, 2011 at 07:06:24AM +0900, Simon Horman wrote:
> By 1-3 I was referring to the first three patches of
> [PATCH 0/4] [rfc v3] mmc, ARM: Add zboot from eSD support for SuperH Mobile ARM
>
> That is:
> [PATCH 1/4] mmc: tmio_mmc: Move some defines into a shared header
> [PATCH 2/4] mmc, ARM: Rename SuperH Mobile ARM zboot helpers
> [PATCH 3/4] mmc: Add MMC_PROGRESS_*
>
> And by patch 4 I was referring to
> [PATCH 4/4 v5] mmc, ARM: Add zboot from eSD support for SuperH Mobile
>
> I apologise for that being as clear as mud.
>
Ok, that makes a bit more sense, thanks for clearing it up.
> Magnus raised a build issue with the series since my previous email.
> I will investigate that and reply to him ASAP. Its probably best
> to hold all the patches until then.
>
It looks like 1/4 is going to have to go through the MMC tree, and will
have to layer on top of Guennadi's current patch stack. He's done a good
job of summarizing the outstanding bits, so it should be trivial to build
on top of that.
Once 1/4 is merged I can easily merge 2 and 3/4 at pretty much any time
during the -rc window, although I'd prefer to have it sorted out by -rc2
or -rc3 at the latest. This will just leave 4/4 for rmk's patch tracker
and its respective scheduling.
For now I'll punt the series from patchwork and await a resend with 1/4
rebased in such a way that it can trivially be picked up by the MMC tree.
> With regards to
> [PATCH 2/6] sh: ecovec: use the CONFIG_MMC_TMIO symbols instead of MFD
> it looks like Magnus raised a few issues and Guennadi is going to repost
> the patch. But I could be wrong.
>
Yes, already dealt with separately.
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 0/6] mmc: split the tmio driver into several modules
2011-03-23 14:54 ` Paul Mundt
@ 2011-03-23 22:42 ` Simon Horman
0 siblings, 0 replies; 27+ messages in thread
From: Simon Horman @ 2011-03-23 22:42 UTC (permalink / raw)
To: Paul Mundt
Cc: Guennadi Liakhovetski, Ian Molton, linux-sh, linux-mmc,
Chris Ball, Magnus Damm
On Wed, Mar 23, 2011 at 11:54:53PM +0900, Paul Mundt wrote:
> On Wed, Mar 23, 2011 at 07:06:24AM +0900, Simon Horman wrote:
> > By 1-3 I was referring to the first three patches of
> > [PATCH 0/4] [rfc v3] mmc, ARM: Add zboot from eSD support for SuperH Mobile ARM
> >
> > That is:
> > [PATCH 1/4] mmc: tmio_mmc: Move some defines into a shared header
> > [PATCH 2/4] mmc, ARM: Rename SuperH Mobile ARM zboot helpers
> > [PATCH 3/4] mmc: Add MMC_PROGRESS_*
> >
> > And by patch 4 I was referring to
> > [PATCH 4/4 v5] mmc, ARM: Add zboot from eSD support for SuperH Mobile
> >
> > I apologise for that being as clear as mud.
> >
> Ok, that makes a bit more sense, thanks for clearing it up.
>
> > Magnus raised a build issue with the series since my previous email.
> > I will investigate that and reply to him ASAP. Its probably best
> > to hold all the patches until then.
> >
> It looks like 1/4 is going to have to go through the MMC tree, and will
> have to layer on top of Guennadi's current patch stack. He's done a good
> job of summarizing the outstanding bits, so it should be trivial to build
> on top of that.
>
> Once 1/4 is merged I can easily merge 2 and 3/4 at pretty much any time
> during the -rc window, although I'd prefer to have it sorted out by -rc2
> or -rc3 at the latest. This will just leave 4/4 for rmk's patch tracker
> and its respective scheduling.
>
> For now I'll punt the series from patchwork and await a resend with 1/4
> rebased in such a way that it can trivially be picked up by the MMC tree.
Understood. I'll rebase my work on top of Guennadi's current patch stack
and repost.
I also have some updates to patches 3 and 4 to resolve build issues
that Magnus alerted me to. So I'll include them in my re-post as well.
^ permalink raw reply [flat|nested] 27+ messages in thread
end of thread, other threads:[~2011-03-23 22:42 UTC | newest]
Thread overview: 27+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-03-11 7:51 [PATCH 0/6] mmc: split the tmio driver into several modules Guennadi Liakhovetski
2011-03-11 7:51 ` [PATCH 1/6] mmc: tmio: split core functionality, DMA and MFD glue Guennadi Liakhovetski
2011-03-12 16:05 ` Magnus Damm
2011-03-12 22:48 ` [PATCH 1/6] mmc: tmio: split core functionality, DMA and MFD Guennadi Liakhovetski
2011-03-13 3:57 ` [PATCH 1/6] mmc: tmio: split core functionality, DMA and MFD glue Magnus Damm
2011-03-13 22:51 ` [PATCH 1/6] mmc: tmio: split core functionality, DMA and MFD Guennadi Liakhovetski
2011-03-15 9:01 ` [PATCH 1/6] mmc: tmio: split core functionality, DMA and MFD glue Magnus Damm
2011-03-16 11:09 ` Ian Molton
2011-03-16 12:37 ` Magnus Damm
2011-03-21 11:19 ` [PATCH 1/6] mmc: tmio: split core functionality, DMA and MFD Guennadi Liakhovetski
2011-03-11 7:52 ` [PATCH 2/6] sh: ecovec: use the CONFIG_MMC_TMIO symbols instead of Guennadi Liakhovetski
2011-03-12 16:18 ` [PATCH 2/6] sh: ecovec: use the CONFIG_MMC_TMIO symbols instead Magnus Damm
2011-03-12 23:00 ` Guennadi Liakhovetski
2011-03-11 7:52 ` [PATCH 3/6] mmc: tmio: convert the SDHI MMC driver from MFD to a Guennadi Liakhovetski
2011-03-13 4:14 ` Magnus Damm
2011-03-14 8:01 ` [PATCH 3/6] mmc: tmio: convert the SDHI MMC driver from MFD to Guennadi Liakhovetski
2011-03-15 9:09 ` [PATCH 3/6] mmc: tmio: convert the SDHI MMC driver from MFD to a Magnus Damm
2011-03-11 7:52 ` [PATCH 4/6] ARM: mach-shmobile: convert boards to use Guennadi Liakhovetski
2011-03-11 7:52 ` [PATCH 5/6] sh: convert boards to use linux/mmc/sh_mobile_sdhi.h Guennadi Liakhovetski
2011-03-11 7:52 ` [PATCH 6/6] mfd: remove now redundant sh_mobile_sdhi.h header Guennadi Liakhovetski
2011-03-15 21:25 ` [PATCH 0/6] mmc: split the tmio driver into several modules Ian Molton
2011-03-21 11:38 ` Guennadi Liakhovetski
2011-03-22 5:31 ` Simon Horman
2011-03-22 12:28 ` Paul Mundt
2011-03-22 22:06 ` Simon Horman
2011-03-23 14:54 ` Paul Mundt
2011-03-23 22:42 ` Simon Horman
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).