* [PATCH 0/7] au1xmmc updates, #2
@ 2008-05-08 8:00 Manuel Lauss
2008-05-08 8:01 ` [PATCH 1/7] Alchemy: export get_au1x00_speed for modules Manuel Lauss
` (6 more replies)
0 siblings, 7 replies; 11+ messages in thread
From: Manuel Lauss @ 2008-05-08 8:00 UTC (permalink / raw)
To: linux-mips, linux-kernel
Hello,
The following set of patches remove demoboard-specific code from the
au1xmmc.c driver and add new features.
My main motivation was to let boards implement other carddetect schemes,
since on one of my boards the driver-implemented poll timer doesn't work
for some unknown reason. But this board does have a dedicated carddetect
IRQ and card-present/card-readonly indicators which are incompatible with
the Db1200 implementation. I also took the opportunity to clean up the
drivers probe() and irq() handlers to make it a "proper" platform device
(patches #3 and #4).
Patch #1 is required to get the driver to build as a module.
Patch #2 is required to be able to load/unload the driver > 16 times.
Patches #5 and #6 implement new features.
Patch #7 does a little codingstyle cleanup, no functional changes.
Change since V1:
- fix a bug in patch #6: SDIO irq should be checked for independently
from other irq events.
- more trivial cleanups
Db1200 users, please test! I verified the poll timer works on one of
older boards, however since I don't have Db1200 and Pb1200 boards I'm
not sure whether the driver still works with both SD controllers enabled!
Thanks!
Manuel Lauss
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 1/7] Alchemy: export get_au1x00_speed for modules
2008-05-08 8:00 [PATCH 0/7] au1xmmc updates, #2 Manuel Lauss
@ 2008-05-08 8:01 ` Manuel Lauss
2008-05-08 8:02 ` [PATCH 2/7] Alchemy: dbdma: add API to delete custom DDMA device ids Manuel Lauss
` (5 subsequent siblings)
6 siblings, 0 replies; 11+ messages in thread
From: Manuel Lauss @ 2008-05-08 8:01 UTC (permalink / raw)
To: linux-mips, linux-kernel
>From 9c59794676b21768624335cc21a7f455b4e69057 Mon Sep 17 00:00:00 2001
From: Manuel Lauss <mlau@msc-ge.com>
Date: Wed, 7 May 2008 13:42:55 +0200
Subject: [PATCH] Alchemy: export get_au1x00_speed for modules
au1xmmc.c driver depends on it, so export it for modules.
Signed-off-by: Manuel Lauss <mano@roarinelk.homelinux.net>
---
arch/mips/au1000/common/clocks.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/arch/mips/au1000/common/clocks.c b/arch/mips/au1000/common/clocks.c
index 3ce6cac..6dbc87a 100644
--- a/arch/mips/au1000/common/clocks.c
+++ b/arch/mips/au1000/common/clocks.c
@@ -46,7 +46,7 @@ unsigned int get_au1x00_speed(void)
{
return au1x00_clock;
}
-
+EXPORT_SYMBOL(get_au1x00_speed);
/*
--
1.5.5.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 2/7] Alchemy: dbdma: add API to delete custom DDMA device ids
2008-05-08 8:00 [PATCH 0/7] au1xmmc updates, #2 Manuel Lauss
2008-05-08 8:01 ` [PATCH 1/7] Alchemy: export get_au1x00_speed for modules Manuel Lauss
@ 2008-05-08 8:02 ` Manuel Lauss
2008-05-08 8:03 ` [PATCH 3/7] au1xmmc: remove db1x00 board-specific functions from driver Manuel Lauss
` (4 subsequent siblings)
6 siblings, 0 replies; 11+ messages in thread
From: Manuel Lauss @ 2008-05-08 8:02 UTC (permalink / raw)
To: linux-mips, linux-kernel
>From 41ebbbe49861a65f28947768db7945a5099673d3 Mon Sep 17 00:00:00 2001
From: Manuel Lauss <mlau@msc-ge.com>
Date: Wed, 7 May 2008 13:45:23 +0200
Subject: [PATCH] Alchemy: dbdma: add API to delete custom DDMA device ids.
Add API to delete custom DDMA device ids create with
au1xxx_ddma_device_add().
Signed-off-by: Manuel Lauss <mano@roarinelk.homelinux.net>
---
arch/mips/au1000/common/dbdma.c | 10 ++++++++++
include/asm-mips/mach-au1x00/au1xxx_dbdma.h | 1 +
2 files changed, 11 insertions(+), 0 deletions(-)
diff --git a/arch/mips/au1000/common/dbdma.c b/arch/mips/au1000/common/dbdma.c
index 53377df..69171c6 100644
--- a/arch/mips/au1000/common/dbdma.c
+++ b/arch/mips/au1000/common/dbdma.c
@@ -220,6 +220,16 @@ au1xxx_ddma_add_device(dbdev_tab_t *dev)
}
EXPORT_SYMBOL(au1xxx_ddma_add_device);
+void au1xxx_ddma_del_device(u32 devid)
+{
+ dbdev_tab_t *p = find_dbdev_id(devid);
+ if (p != NULL) {
+ memset(p, 0, sizeof(dbdev_tab_t));
+ p->dev_id = ~0;
+ }
+}
+EXPORT_SYMBOL(au1xxx_ddma_del_device);
+
/* Allocate a channel and return a non-zero descriptor if successful.
*/
u32
diff --git a/include/asm-mips/mach-au1x00/au1xxx_dbdma.h b/include/asm-mips/mach-au1x00/au1xxx_dbdma.h
index 93d507c..5e33ff0 100644
--- a/include/asm-mips/mach-au1x00/au1xxx_dbdma.h
+++ b/include/asm-mips/mach-au1x00/au1xxx_dbdma.h
@@ -367,6 +367,7 @@ void au1xxx_dbdma_dump(u32 chanid);
u32 au1xxx_dbdma_put_dscr(u32 chanid, au1x_ddma_desc_t *dscr );
u32 au1xxx_ddma_add_device( dbdev_tab_t *dev );
+void au1xxx_ddma_del_device(u32 devid);
void * au1xxx_ddma_get_nextptr_virt(au1x_ddma_desc_t *dp);
/*
--
1.5.5.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 3/7] au1xmmc: remove db1x00 board-specific functions from driver
2008-05-08 8:00 [PATCH 0/7] au1xmmc updates, #2 Manuel Lauss
2008-05-08 8:01 ` [PATCH 1/7] Alchemy: export get_au1x00_speed for modules Manuel Lauss
2008-05-08 8:02 ` [PATCH 2/7] Alchemy: dbdma: add API to delete custom DDMA device ids Manuel Lauss
@ 2008-05-08 8:03 ` Manuel Lauss
2008-05-12 11:36 ` Sergei Shtylyov
2008-05-13 9:27 ` Sergei Shtylyov
2008-05-08 8:03 ` [PATCH 4/7] Alchemy: register mmc platform device for db1200/pb1200 boards Manuel Lauss
` (3 subsequent siblings)
6 siblings, 2 replies; 11+ messages in thread
From: Manuel Lauss @ 2008-05-08 8:03 UTC (permalink / raw)
To: linux-mips, linux-kernel
>From 47ecf116465ed850d2202880f7795fcee4826184 Mon Sep 17 00:00:00 2001
From: Manuel Lauss <mlau@msc-ge.com>
Date: Wed, 7 May 2008 14:57:01 +0200
Subject: [PATCH] au1xmmc: remove db1x00 board-specific functions from driver
Remove the DB1200 board-specific functions (card present, read-only
methods) and instead add platform data which is passed to the driver.
This allows for platforms to implement other carddetect schemes
(e.g. dedicated irq) without having to pollute the driver code.
The poll timer (used for pb1200) is kept for compatibility.
With the board-specific stuff gone, the driver no longer needs to know
how many physical controllers the silicon actually has; every device
can be registered as needed, update the code to reflect that.
Signed-off-by: Manuel Lauss <mano@roarinelk.homelinux.net>
---
drivers/mmc/host/au1xmmc.c | 504 ++++++++++++++++++-----------
drivers/mmc/host/au1xmmc.h | 96 ------
include/asm-mips/mach-au1x00/au1100_mmc.h | 43 +++-
3 files changed, 346 insertions(+), 297 deletions(-)
delete mode 100644 drivers/mmc/host/au1xmmc.h
diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c
index cc5f7bc..8660f86 100644
--- a/drivers/mmc/host/au1xmmc.c
+++ b/drivers/mmc/host/au1xmmc.c
@@ -49,7 +49,6 @@
#include <asm/mach-au1x00/au1100_mmc.h>
#include <au1xxx.h>
-#include "au1xmmc.h"
#define DRIVER_NAME "au1xxx-mmc"
@@ -61,31 +60,73 @@
#define DBG(fmt, idx, args...)
#endif
-const struct {
- u32 iobase;
- u32 tx_devid, rx_devid;
- u16 bcsrpwr;
- u16 bcsrstatus;
- u16 wpstatus;
-} au1xmmc_card_table[] = {
- { SD0_BASE, DSCR_CMD0_SDMS_TX0, DSCR_CMD0_SDMS_RX0,
- BCSR_BOARD_SD0PWR, BCSR_INT_SD0INSERT, BCSR_STATUS_SD0WP },
-#ifndef CONFIG_MIPS_DB1200
- { SD1_BASE, DSCR_CMD0_SDMS_TX1, DSCR_CMD0_SDMS_RX1,
- BCSR_BOARD_DS1PWR, BCSR_INT_SD1INSERT, BCSR_STATUS_SD1WP }
-#endif
-};
+#define AU1XMMC_DESCRIPTOR_COUNT 1
+#define AU1XMMC_DESCRIPTOR_SIZE 4096
+
+#define AU1XMMC_OCR (MMC_VDD_27_28 | MMC_VDD_28_29 | MMC_VDD_29_30 | \
+ MMC_VDD_30_31 | MMC_VDD_31_32 | MMC_VDD_32_33 | \
+ MMC_VDD_33_34 | MMC_VDD_34_35 | MMC_VDD_35_36)
+
+/* Easy access macros */
+
+#define HOST_STATUS(h) ((h)->iobase + SD_STATUS)
+#define HOST_CONFIG(h) ((h)->iobase + SD_CONFIG)
+#define HOST_ENABLE(h) ((h)->iobase + SD_ENABLE)
+#define HOST_TXPORT(h) ((h)->iobase + SD_TXPORT)
+#define HOST_RXPORT(h) ((h)->iobase + SD_RXPORT)
+#define HOST_CMDARG(h) ((h)->iobase + SD_CMDARG)
+#define HOST_BLKSIZE(h) ((h)->iobase + SD_BLKSIZE)
+#define HOST_CMD(h) ((h)->iobase + SD_CMD)
+#define HOST_CONFIG2(h) ((h)->iobase + SD_CONFIG2)
+#define HOST_TIMEOUT(h) ((h)->iobase + SD_TIMEOUT)
+#define HOST_DEBUG(h) ((h)->iobase + SD_DEBUG)
+
+#define DMA_CHANNEL(h) \
+ (((h)->flags & HOST_F_XMIT) ? (h)->dma.tx_chan : (h)->dma.rx_chan)
+
+/* This gives us a hard value for the stop command that we can write directly
+ * to the command register
+ */
+
+#define STOP_CMD (SD_CMD_RT_1B | SD_CMD_CT_7 | \
+ (0xC << SD_CMD_CI_SHIFT) | SD_CMD_GO)
-#define AU1XMMC_CONTROLLER_COUNT (ARRAY_SIZE(au1xmmc_card_table))
+/* This is the set of interrupts that we configure by default */
+#define AU1XMMC_INTERRUPTS (SD_CONFIG_SC | SD_CONFIG_DT | \
+ SD_CONFIG_RAT | SD_CONFIG_CR | SD_CONFIG_I)
+
+/* The poll event (looking for insert/remove events runs twice a second */
+#define AU1XMMC_DETECT_TIMEOUT (HZ/2)
+
+/* Status flags used by the host structure */
+#define HOST_F_XMIT 0x0001
+#define HOST_F_RECV 0x0002
+#define HOST_F_DMA 0x0010
+#define HOST_F_ACTIVE 0x0100
+#define HOST_F_STOP 0x1000
+
+#define HOST_S_IDLE 0x0001
+#define HOST_S_CMD 0x0002
+#define HOST_S_DATA 0x0003
+#define HOST_S_STOP 0x0004
-/* This array stores pointers for the hosts (used by the IRQ handler) */
-struct au1xmmc_host *au1xmmc_hosts[AU1XMMC_CONTROLLER_COUNT];
static int dma = 1;
-#ifdef MODULE
module_param(dma, bool, 0);
MODULE_PARM_DESC(dma, "Use DMA engine for data transfers (0 = disabled)");
-#endif
+
+/* 8bit memory device */
+static dbdev_tab_t au1xmmc_mem_dbdev = {
+ .dev_id = DSCR_CMD0_ALWAYS,
+ .dev_flags = DEV_FLAGS_ANYUSE,
+ .dev_tsize = 0,
+ .dev_devwidth = 8,
+ .dev_physaddr = 0x00000000,
+ .dev_intlevel = 0,
+ .dev_intpolarity = 0,
+};
+static int memid;
+
static inline void IRQ_ON(struct au1xmmc_host *host, u32 mask)
{
@@ -135,31 +176,37 @@ static inline void SEND_STOP(struct au1xmmc_host *host)
static void au1xmmc_set_power(struct au1xmmc_host *host, int state)
{
-
- u32 val = au1xmmc_card_table[host->id].bcsrpwr;
-
- bcsr->board &= ~val;
- if (state) bcsr->board |= val;
-
- au_sync_delay(1);
+ if (host->platdata && host->platdata->set_power)
+ host->platdata->set_power(host->mmc, state);
}
-static inline int au1xmmc_card_inserted(struct au1xmmc_host *host)
+static int au1xmmc_card_inserted(struct au1xmmc_host *host)
{
- return (bcsr->sig_status & au1xmmc_card_table[host->id].bcsrstatus)
- ? 1 : 0;
+ int ret;
+
+ if (host->platdata && host->platdata->card_inserted)
+ ret = host->platdata->card_inserted(host->mmc);
+ else
+ ret = 1; /* assume there is a card */
+
+ return ret;
}
static int au1xmmc_card_readonly(struct mmc_host *mmc)
{
struct au1xmmc_host *host = mmc_priv(mmc);
- return (bcsr->status & au1xmmc_card_table[host->id].wpstatus)
- ? 1 : 0;
+ int ret;
+
+ if (host->platdata && host->platdata->card_readonly)
+ ret = host->platdata->card_readonly(mmc);
+ else
+ ret = 1; /* assume card is read-only */
+
+ return ret;
}
static void au1xmmc_finish_request(struct au1xmmc_host *host)
{
-
struct mmc_request *mrq = host->mrq;
host->mrq = NULL;
@@ -174,8 +221,6 @@ static void au1xmmc_finish_request(struct au1xmmc_host *host)
host->status = HOST_S_IDLE;
- bcsr->disk_leds |= (1 << 8);
-
mmc_request_done(host->mmc, mrq);
}
@@ -663,7 +708,9 @@ static void au1xmmc_request(struct mmc_host* mmc, struct mmc_request* mrq)
host->mrq = mrq;
host->status = HOST_S_CMD;
- bcsr->disk_leds &= ~(1 << 8);
+ au_writel(0, HOST_STATUS(host));
+ au_sync();
+ FLUSH_FIFO(host);
if (mrq->data) {
FLUSH_FIFO(host);
@@ -749,118 +796,87 @@ static void au1xmmc_dma_callback(int irq, void *dev_id)
static irqreturn_t au1xmmc_irq(int irq, void *dev_id)
{
-
+ struct au1xmmc_host *host = dev_id;
u32 status;
- int i, ret = 0;
- disable_irq(AU1100_SD_IRQ);
+ status = au_readl(HOST_STATUS(host));
- for(i = 0; i < AU1XMMC_CONTROLLER_COUNT; i++) {
- struct au1xmmc_host * host = au1xmmc_hosts[i];
- u32 handled = 1;
+ if (!(status & (1 << 15)))
+ return IRQ_NONE; /* not ours */
- status = au_readl(HOST_STATUS(host));
+ if (host->mrq && (status & STATUS_TIMEOUT)) {
+ if (status & SD_STATUS_RAT)
+ host->mrq->cmd->error = -ETIMEDOUT;
+ else if (status & SD_STATUS_DT)
+ host->mrq->data->error = -ETIMEDOUT;
- if (host->mrq && (status & STATUS_TIMEOUT)) {
- if (status & SD_STATUS_RAT)
- host->mrq->cmd->error = -ETIMEDOUT;
+ /* In PIO mode, interrupts might still be enabled */
+ IRQ_OFF(host, SD_CONFIG_NE | SD_CONFIG_TH);
- else if (status & SD_STATUS_DT)
- host->mrq->data->error = -ETIMEDOUT;
-
- /* In PIO mode, interrupts might still be enabled */
- IRQ_OFF(host, SD_CONFIG_NE | SD_CONFIG_TH);
-
- //IRQ_OFF(host, SD_CONFIG_TH|SD_CONFIG_RA|SD_CONFIG_RF);
- tasklet_schedule(&host->finish_task);
- }
+ //IRQ_OFF(host, SD_CONFIG_TH|SD_CONFIG_RA|SD_CONFIG_RF);
+ tasklet_schedule(&host->finish_task);
+ }
#if 0
- else if (status & SD_STATUS_DD) {
-
- /* Sometimes we get a DD before a NE in PIO mode */
-
- if (!(host->flags & HOST_F_DMA) &&
- (status & SD_STATUS_NE))
- au1xmmc_receive_pio(host);
- else {
- au1xmmc_data_complete(host, status);
- //tasklet_schedule(&host->data_task);
- }
+ else if (status & SD_STATUS_DD) {
+ /* Sometimes we get a DD before a NE in PIO mode */
+ if (!(host->flags & HOST_F_DMA) && (status & SD_STATUS_NE))
+ au1xmmc_receive_pio(host);
+ else {
+ au1xmmc_data_complete(host, status);
+ //tasklet_schedule(&host->data_task);
}
-#endif
- else if (status & (SD_STATUS_CR)) {
- if (host->status == HOST_S_CMD)
- au1xmmc_cmd_complete(host,status);
- }
- else if (!(host->flags & HOST_F_DMA)) {
- if ((host->flags & HOST_F_XMIT) &&
- (status & STATUS_DATA_OUT))
- au1xmmc_send_pio(host);
- else if ((host->flags & HOST_F_RECV) &&
- (status & STATUS_DATA_IN))
- au1xmmc_receive_pio(host);
- }
- else if (status & 0x203FBC70) {
- DBG("Unhandled status %8.8x\n", host->id, status);
- handled = 0;
- }
-
- au_writel(status, HOST_STATUS(host));
- au_sync();
-
- ret |= handled;
}
+#endif
+ else if (status & (SD_STATUS_CR)) {
+ if (host->status == HOST_S_CMD)
+ au1xmmc_cmd_complete(host,status);
- enable_irq(AU1100_SD_IRQ);
- return ret;
-}
-
-static void au1xmmc_poll_event(unsigned long arg)
-{
- struct au1xmmc_host *host = (struct au1xmmc_host *) arg;
-
- int card = au1xmmc_card_inserted(host);
- int controller = (host->flags & HOST_F_ACTIVE) ? 1 : 0;
+ } else if (!(host->flags & HOST_F_DMA)) {
+ if ((host->flags & HOST_F_XMIT) && (status & STATUS_DATA_OUT))
+ au1xmmc_send_pio(host);
+ else if ((host->flags & HOST_F_RECV) && (status & STATUS_DATA_IN))
+ au1xmmc_receive_pio(host);
- if (card != controller) {
- host->flags &= ~HOST_F_ACTIVE;
- if (card) host->flags |= HOST_F_ACTIVE;
- mmc_detect_change(host->mmc, 0);
+ } else if (status & 0x203FBC70) {
+ DBG("Unhandled status %8.8x\n", host->id, status);
}
- if (host->mrq != NULL) {
- u32 status = au_readl(HOST_STATUS(host));
- DBG("PENDING - %8.8x\n", host->id, status);
- }
+ au_writel(status, HOST_STATUS(host));
+ au_sync();
- mod_timer(&host->timer, jiffies + AU1XMMC_DETECT_TIMEOUT);
+ return IRQ_HANDLED;
}
-static dbdev_tab_t au1xmmc_mem_dbdev =
-{
- DSCR_CMD0_ALWAYS, DEV_FLAGS_ANYUSE, 0, 8, 0x00000000, 0, 0
-};
-
-static void au1xmmc_init_dma(struct au1xmmc_host *host)
+static int au1xmmc_init_dma(struct au1xmmc_host *host)
{
-
+ struct resource *res;
u32 rxchan, txchan;
+ int txid, rxid;
- int txid = au1xmmc_card_table[host->id].tx_devid;
- int rxid = au1xmmc_card_table[host->id].rx_devid;
-
- /* DSCR_CMD0_ALWAYS has a stride of 32 bits, we need a stride
- of 8 bits. And since devices are shared, we need to create
- our own to avoid freaking out other devices
- */
+ res = platform_get_resource(host->pdev, IORESOURCE_DMA, 0);
+ if (!res)
+ return -ENODEV;
+ txid = res->start;
- int memid = au1xxx_ddma_add_device(&au1xmmc_mem_dbdev);
+ res = platform_get_resource(host->pdev, IORESOURCE_DMA, 1);
+ if (!res)
+ return -ENODEV;
+ rxid = res->start;
txchan = au1xxx_dbdma_chan_alloc(memid, txid,
- au1xmmc_dma_callback, (void *) host);
+ au1xmmc_dma_callback, (void *)host);
+ if (!txchan) {
+ dev_err(&host->pdev->dev, "cannot allocate TX DMA\n");
+ return -ENODEV;
+ }
rxchan = au1xxx_dbdma_chan_alloc(rxid, memid,
- au1xmmc_dma_callback, (void *) host);
+ au1xmmc_dma_callback, (void *)host);
+ if (!rxchan) {
+ dev_err(&host->pdev->dev, "cannot allocate RX DMA\n");
+ au1xxx_dbdma_chan_free(txchan);
+ return -ENODEV;
+ }
au1xxx_dbdma_set_devwidth(txchan, 8);
au1xxx_dbdma_set_devwidth(rxchan, 8);
@@ -868,8 +884,10 @@ static void au1xmmc_init_dma(struct au1xmmc_host *host)
au1xxx_dbdma_ring_alloc(txchan, AU1XMMC_DESCRIPTOR_COUNT);
au1xxx_dbdma_ring_alloc(rxchan, AU1XMMC_DESCRIPTOR_COUNT);
- host->tx_chan = txchan;
- host->rx_chan = rxchan;
+ host->dma.tx_chan = txchan;
+ host->dma.rx_chan = rxchan;
+
+ return 0;
}
static const struct mmc_host_ops au1xmmc_ops = {
@@ -878,116 +896,201 @@ static const struct mmc_host_ops au1xmmc_ops = {
.get_ro = au1xmmc_card_readonly,
};
-static int __devinit au1xmmc_probe(struct platform_device *pdev)
+static void au1xmmc_poll_event(unsigned long arg)
{
+ struct au1xmmc_host *host = (struct au1xmmc_host *)arg;
- int i, ret = 0;
+ int card = au1xmmc_card_inserted(host);
+ int controller = (host->flags & HOST_F_ACTIVE) ? 1 : 0;
- /* THe interrupt is shared among all controllers */
- ret = request_irq(AU1100_SD_IRQ, au1xmmc_irq, IRQF_DISABLED, "MMC", 0);
+ if (card != controller) {
+ host->flags &= ~HOST_F_ACTIVE;
+ if (card)
+ host->flags |= HOST_F_ACTIVE;
+ mmc_detect_change(host->mmc, 0);
+ }
- if (ret) {
- printk(DRIVER_NAME "ERROR: Couldn't get int %d: %d\n",
- AU1100_SD_IRQ, ret);
- return -ENXIO;
+#ifdef DEBUG
+ if (host->mrq != NULL) {
+ u32 status = au_readl(HOST_STATUS(host));
+ DBG("PENDING - %8.8x\n", host->id, status);
}
+#endif
+ mod_timer(&host->timer, jiffies + AU1XMMC_DETECT_TIMEOUT);
+}
- disable_irq(AU1100_SD_IRQ);
+static void au1xmmc_init_cd_poll_timer(struct au1xmmc_host *host)
+{
+ init_timer(&host->timer);
+ host->timer.function = au1xmmc_poll_event;
+ host->timer.data = (unsigned long)host;
+ host->timer.expires = jiffies + AU1XMMC_DETECT_TIMEOUT;
+}
- for(i = 0; i < AU1XMMC_CONTROLLER_COUNT; i++) {
- struct mmc_host *mmc = mmc_alloc_host(sizeof(struct au1xmmc_host), &pdev->dev);
- struct au1xmmc_host *host = 0;
+static int __devinit au1xmmc_probe(struct platform_device *pdev)
+{
+ struct mmc_host *mmc;
+ struct au1xmmc_host *host;
+ struct resource *r;
+ int ret;
+
+ mmc = mmc_alloc_host(sizeof(struct au1xmmc_host), &pdev->dev);
+ if (!mmc) {
+ dev_err(&pdev->dev, "no memory for mmc host\n");
+ ret = -ENOMEM;
+ goto out0;
+ }
- if (!mmc) {
- printk(DRIVER_NAME "ERROR: no mem for host %d\n", i);
- au1xmmc_hosts[i] = 0;
- continue;
- }
+ host = mmc_priv(mmc);
+ host->mmc = mmc;
+ host->platdata = pdev->dev.platform_data;
+ host->pdev = pdev;
- mmc->ops = &au1xmmc_ops;
+ ret = -ENODEV;
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!r) {
+ dev_err(&pdev->dev, "no mmio defined\n");
+ goto out1;
+ }
+ host->iobase = (unsigned long)ioremap(r->start, 0xff);
+ if (!host->iobase) {
+ dev_err(&pdev->dev, "cannot remap mmio\n");
+ goto out1;
+ }
- mmc->f_min = 450000;
- mmc->f_max = 24000000;
+ r = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!r) {
+ dev_err(&pdev->dev, "no IRQ defined\n");
+ goto out2;
+ }
- mmc->max_seg_size = AU1XMMC_DESCRIPTOR_SIZE;
- mmc->max_phys_segs = AU1XMMC_DESCRIPTOR_COUNT;
+ host->irq = r->start;
+ /* IRQ is shared among both SD controllers */
+ ret = request_irq(host->irq, au1xmmc_irq, IRQF_SHARED,
+ DRIVER_NAME, host);
+ if (ret) {
+ dev_err(&pdev->dev, "cannot grab IRQ\n");
+ goto out2;
+ }
- mmc->max_blk_size = 2048;
- mmc->max_blk_count = 512;
+ mmc->ops = &au1xmmc_ops;
- mmc->ocr_avail = AU1XMMC_OCR;
+ mmc->f_min = 450000;
+ mmc->f_max = 24000000;
- host = mmc_priv(mmc);
- host->mmc = mmc;
+ mmc->max_seg_size = AU1XMMC_DESCRIPTOR_SIZE;
+ mmc->max_phys_segs = AU1XMMC_DESCRIPTOR_COUNT;
- host->id = i;
- host->iobase = au1xmmc_card_table[host->id].iobase;
- host->clock = 0;
- host->power_mode = MMC_POWER_OFF;
+ mmc->max_blk_size = 2048;
+ mmc->max_blk_count = 512;
- host->flags = au1xmmc_card_inserted(host) ? HOST_F_ACTIVE : 0;
- host->status = HOST_S_IDLE;
+ mmc->ocr_avail = AU1XMMC_OCR;
+ mmc->caps = 0;
- init_timer(&host->timer);
+ host->id = pdev->id;
+ host->status = HOST_S_IDLE;
- host->timer.function = au1xmmc_poll_event;
- host->timer.data = (unsigned long) host;
- host->timer.expires = jiffies + AU1XMMC_DETECT_TIMEOUT;
+ /* board-specific carddetect setup, if any */
+ if (host->platdata && host->platdata->cd_setup) {
+ ret = host->platdata->cd_setup(mmc, 1);
+ if (ret) {
+ dev_err(&pdev->dev, "board CD setup failed\n");
+ goto out3;
+ }
+ } else {
+ /* poll the board-specific card-is-in-socket method */
+ au1xmmc_init_cd_poll_timer(host);
+ }
- tasklet_init(&host->data_task, au1xmmc_tasklet_data,
- (unsigned long) host);
+ tasklet_init(&host->data_task, au1xmmc_tasklet_data,
+ (unsigned long)host);
- tasklet_init(&host->finish_task, au1xmmc_tasklet_finish,
- (unsigned long) host);
+ tasklet_init(&host->finish_task, au1xmmc_tasklet_finish,
+ (unsigned long)host);
- spin_lock_init(&host->lock);
+ if (dma) {
+ ret = au1xmmc_init_dma(host);
+ if (ret)
+ goto out4;
+ }
- if (dma != 0)
- au1xmmc_init_dma(host);
+ au1xmmc_reset_controller(host);
- au1xmmc_reset_controller(host);
+ ret = mmc_add_host(mmc);
+ if (ret) {
+ dev_err(&pdev->dev, "cannot add mmc host\n");
+ goto out5;
+ }
- mmc_add_host(mmc);
- au1xmmc_hosts[i] = host;
+ platform_set_drvdata(pdev, mmc);
+ /* start the carddetect poll timer */
+ if (!(host->platdata && host->platdata->cd_setup))
add_timer(&host->timer);
- printk(KERN_INFO DRIVER_NAME ": MMC Controller %d set up at %8.8X (mode=%s)\n",
- host->id, host->iobase, dma ? "dma" : "pio");
- }
+ printk(KERN_INFO DRIVER_NAME ": MMC Controller %d set up at %8.8X (mode=%s)\n",
+ pdev->id, host->iobase, dma ? "dma" : "pio");
- enable_irq(AU1100_SD_IRQ);
+ return 0; /* all ok */
- return 0;
+out5:
+ au_writel(0, HOST_ENABLE(host));
+ au_writel(0, HOST_CONFIG(host));
+ au_sync();
+
+ if (dma) {
+ au1xxx_dbdma_chan_free(host->dma.tx_chan);
+ au1xxx_dbdma_chan_free(host->dma.rx_chan);
+ }
+out4:
+ tasklet_kill(&host->data_task);
+ tasklet_kill(&host->finish_task);
+
+ if (host->platdata && host->platdata->cd_setup)
+ host->platdata->cd_setup(mmc, 0);
+out3:
+ free_irq(host->irq, host);
+out2:
+ iounmap((void *)host->iobase);
+out1:
+ mmc_free_host(mmc);
+out0:
+ return ret;
}
static int __devexit au1xmmc_remove(struct platform_device *pdev)
{
+ struct mmc_host *mmc = platform_get_drvdata(pdev);
+ struct au1xmmc_host *host;
- int i;
+ if (mmc) {
+ host = mmc_priv(mmc);
- disable_irq(AU1100_SD_IRQ);
+ mmc_remove_host(mmc);
- for(i = 0; i < AU1XMMC_CONTROLLER_COUNT; i++) {
- struct au1xmmc_host *host = au1xmmc_hosts[i];
- if (!host) continue;
+ if (host->platdata && host->platdata->cd_setup)
+ host->platdata->cd_setup(mmc, 0);
+ else
+ del_timer_sync(&host->timer);
+
+ au_writel(0, HOST_ENABLE(host));
+ au_writel(0, HOST_CONFIG(host));
+ au_sync();
tasklet_kill(&host->data_task);
tasklet_kill(&host->finish_task);
- del_timer_sync(&host->timer);
- au1xmmc_set_power(host, 0);
+ if (dma) {
+ au1xxx_dbdma_chan_free(host->dma.tx_chan);
+ au1xxx_dbdma_chan_free(host->dma.rx_chan);
+ }
- mmc_remove_host(host->mmc);
+ au1xmmc_set_power(host, 0);
- au1xxx_dbdma_chan_free(host->tx_chan);
- au1xxx_dbdma_chan_free(host->rx_chan);
+ free_irq(host->irq, host);
- au_writel(0x0, HOST_ENABLE(host));
- au_sync();
+ mmc_free_host(mmc);
}
-
- free_irq(AU1100_SD_IRQ, 0);
return 0;
}
@@ -1004,21 +1107,32 @@ static struct platform_driver au1xmmc_driver = {
static int __init au1xmmc_init(void)
{
+ if (dma) {
+ /* DSCR_CMD0_ALWAYS has a stride of 32 bits, we need a stride
+ * of 8 bits. And since devices are shared, we need to create
+ * our own to avoid freaking out other devices
+ */
+ if (!memid)
+ memid = au1xxx_ddma_add_device(&au1xmmc_mem_dbdev);
+ if (!memid) {
+ printk(KERN_ERR "au1xmmc: cannot add memory dma dev\n");
+ return -ENODEV;
+ }
+ }
return platform_driver_register(&au1xmmc_driver);
}
static void __exit au1xmmc_exit(void)
{
+ if (dma && memid)
+ au1xxx_ddma_del_device(memid);
platform_driver_unregister(&au1xmmc_driver);
}
module_init(au1xmmc_init);
module_exit(au1xmmc_exit);
-#ifdef MODULE
MODULE_AUTHOR("Advanced Micro Devices, Inc");
MODULE_DESCRIPTION("MMC/SD driver for the Alchemy Au1XXX");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:au1xxx-mmc");
-#endif
-
diff --git a/drivers/mmc/host/au1xmmc.h b/drivers/mmc/host/au1xmmc.h
deleted file mode 100644
index 341cbdf..0000000
--- a/drivers/mmc/host/au1xmmc.h
+++ /dev/null
@@ -1,96 +0,0 @@
-#ifndef _AU1XMMC_H_
-#define _AU1XMMC_H_
-
-/* Hardware definitions */
-
-#define AU1XMMC_DESCRIPTOR_COUNT 1
-#define AU1XMMC_DESCRIPTOR_SIZE 2048
-
-#define AU1XMMC_OCR ( MMC_VDD_27_28 | MMC_VDD_28_29 | MMC_VDD_29_30 | \
- MMC_VDD_30_31 | MMC_VDD_31_32 | MMC_VDD_32_33 | \
- MMC_VDD_33_34 | MMC_VDD_34_35 | MMC_VDD_35_36)
-
-/* Easy access macros */
-
-#define HOST_STATUS(h) ((h)->iobase + SD_STATUS)
-#define HOST_CONFIG(h) ((h)->iobase + SD_CONFIG)
-#define HOST_ENABLE(h) ((h)->iobase + SD_ENABLE)
-#define HOST_TXPORT(h) ((h)->iobase + SD_TXPORT)
-#define HOST_RXPORT(h) ((h)->iobase + SD_RXPORT)
-#define HOST_CMDARG(h) ((h)->iobase + SD_CMDARG)
-#define HOST_BLKSIZE(h) ((h)->iobase + SD_BLKSIZE)
-#define HOST_CMD(h) ((h)->iobase + SD_CMD)
-#define HOST_CONFIG2(h) ((h)->iobase + SD_CONFIG2)
-#define HOST_TIMEOUT(h) ((h)->iobase + SD_TIMEOUT)
-#define HOST_DEBUG(h) ((h)->iobase + SD_DEBUG)
-
-#define DMA_CHANNEL(h) \
- ( ((h)->flags & HOST_F_XMIT) ? (h)->tx_chan : (h)->rx_chan)
-
-/* This gives us a hard value for the stop command that we can write directly
- * to the command register
- */
-
-#define STOP_CMD (SD_CMD_RT_1B|SD_CMD_CT_7|(0xC << SD_CMD_CI_SHIFT)|SD_CMD_GO)
-
-/* This is the set of interrupts that we configure by default */
-
-#if 0
-#define AU1XMMC_INTERRUPTS (SD_CONFIG_SC | SD_CONFIG_DT | SD_CONFIG_DD | \
- SD_CONFIG_RAT | SD_CONFIG_CR | SD_CONFIG_I)
-#endif
-
-#define AU1XMMC_INTERRUPTS (SD_CONFIG_SC | SD_CONFIG_DT | \
- SD_CONFIG_RAT | SD_CONFIG_CR | SD_CONFIG_I)
-/* The poll event (looking for insert/remove events runs twice a second */
-#define AU1XMMC_DETECT_TIMEOUT (HZ/2)
-
-struct au1xmmc_host {
- struct mmc_host *mmc;
- struct mmc_request *mrq;
-
- u32 id;
-
- u32 flags;
- u32 iobase;
- u32 clock;
- u32 bus_width;
- u32 power_mode;
-
- int status;
-
- struct {
- int len;
- int dir;
- } dma;
-
- struct {
- int index;
- int offset;
- int len;
- } pio;
-
- u32 tx_chan;
- u32 rx_chan;
-
- struct timer_list timer;
- struct tasklet_struct finish_task;
- struct tasklet_struct data_task;
-
- spinlock_t lock;
-};
-
-/* Status flags used by the host structure */
-
-#define HOST_F_XMIT 0x0001
-#define HOST_F_RECV 0x0002
-#define HOST_F_DMA 0x0010
-#define HOST_F_ACTIVE 0x0100
-#define HOST_F_STOP 0x1000
-
-#define HOST_S_IDLE 0x0001
-#define HOST_S_CMD 0x0002
-#define HOST_S_DATA 0x0003
-#define HOST_S_STOP 0x0004
-
-#endif
diff --git a/include/asm-mips/mach-au1x00/au1100_mmc.h b/include/asm-mips/mach-au1x00/au1100_mmc.h
index 9e0028f..6474fac 100644
--- a/include/asm-mips/mach-au1x00/au1100_mmc.h
+++ b/include/asm-mips/mach-au1x00/au1100_mmc.h
@@ -38,15 +38,46 @@
#ifndef __ASM_AU1100_MMC_H
#define __ASM_AU1100_MMC_H
-
-#define NUM_AU1100_MMC_CONTROLLERS 2
-
-#if defined(CONFIG_SOC_AU1100)
-#define AU1100_SD_IRQ AU1100_SD_INT
-#elif defined(CONFIG_SOC_AU1200)
-#define AU1100_SD_IRQ AU1200_SD_INT
-#endif
-
+struct au1xmmc_platdata {
+ int(*cd_setup)(void *mmc_host, int on);
+ int(*card_inserted)(void *mmc_host);
+ int(*card_readonly)(void *mmc_host);
+ void(*set_power)(void *mmc_host, int state);
+};
+
+struct au1xmmc_host {
+ struct mmc_host *mmc;
+ struct mmc_request *mrq;
+
+ u32 id;
+
+ u32 flags;
+ u32 iobase;
+ u32 clock;
+
+ int status;
+
+ struct {
+ int len;
+ int dir;
+ u32 tx_chan;
+ u32 rx_chan;
+ } dma;
+
+ struct {
+ int index;
+ int offset;
+ int len;
+ } pio;
+
+ struct timer_list timer;
+ struct tasklet_struct finish_task;
+ struct tasklet_struct data_task;
+
+ struct platform_device *pdev;
+ struct au1xmmc_platdata *platdata;
+ int irq;
+};
#define SD0_BASE 0xB0600000
#define SD1_BASE 0xB0680000
--
1.5.5.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 4/7] Alchemy: register mmc platform device for db1200/pb1200 boards
2008-05-08 8:00 [PATCH 0/7] au1xmmc updates, #2 Manuel Lauss
` (2 preceding siblings ...)
2008-05-08 8:03 ` [PATCH 3/7] au1xmmc: remove db1x00 board-specific functions from driver Manuel Lauss
@ 2008-05-08 8:03 ` Manuel Lauss
2008-05-08 8:04 ` [PATCH 5/7] au1xmmc: 4 bit transfer mode Manuel Lauss
` (2 subsequent siblings)
6 siblings, 0 replies; 11+ messages in thread
From: Manuel Lauss @ 2008-05-08 8:03 UTC (permalink / raw)
To: linux-mips, linux-kernel
>From a2ecbdb747a53792dd90c83d48235ae2fddfb95e Mon Sep 17 00:00:00 2001
From: Manuel Lauss <mlau@msc-ge.com>
Date: Wed, 7 May 2008 14:59:45 +0200
Subject: [PATCH] Alchemy: register mmc platform device for db1200/pb1200 boards
register the mmc platform device for db1200/pb1200 boards, with
board-specific card detect/readonly facilities wrapped in platform data.
Signed-off-by: Manuel Lauss <mano@roarinelk.homelinux.net>
---
arch/mips/au1000/common/platform.c | 32 ---------
arch/mips/au1000/pb1200/platform.c | 128 +++++++++++++++++++++++++++++++++++-
2 files changed, 127 insertions(+), 33 deletions(-)
diff --git a/arch/mips/au1000/common/platform.c b/arch/mips/au1000/common/platform.c
index 31d2a22..08a5900 100644
--- a/arch/mips/au1000/common/platform.c
+++ b/arch/mips/au1000/common/platform.c
@@ -162,24 +162,6 @@ static struct resource au1xxx_usb_gdt_resources[] = {
},
};
-static struct resource au1xxx_mmc_resources[] = {
- [0] = {
- .start = SD0_PHYS_ADDR,
- .end = SD0_PHYS_ADDR + 0x40,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = SD1_PHYS_ADDR,
- .end = SD1_PHYS_ADDR + 0x40,
- .flags = IORESOURCE_MEM,
- },
- [2] = {
- .start = AU1200_SD_INT,
- .end = AU1200_SD_INT,
- .flags = IORESOURCE_IRQ,
- }
-};
-
static u64 udc_dmamask = ~(u32)0;
static struct platform_device au1xxx_usb_gdt_device = {
@@ -245,19 +227,6 @@ static struct platform_device au1200_lcd_device = {
.num_resources = ARRAY_SIZE(au1200_lcd_resources),
.resource = au1200_lcd_resources,
};
-
-static u64 au1xxx_mmc_dmamask = ~(u32)0;
-
-static struct platform_device au1xxx_mmc_device = {
- .name = "au1xxx-mmc",
- .id = 0,
- .dev = {
- .dma_mask = &au1xxx_mmc_dmamask,
- .coherent_dma_mask = 0xffffffff,
- },
- .num_resources = ARRAY_SIZE(au1xxx_mmc_resources),
- .resource = au1xxx_mmc_resources,
-};
#endif /* #ifdef CONFIG_SOC_AU1200 */
static struct platform_device au1x00_pcmcia_device = {
@@ -295,7 +264,6 @@ static struct platform_device *au1xxx_platform_devices[] __initdata = {
&au1xxx_usb_gdt_device,
&au1xxx_usb_otg_device,
&au1200_lcd_device,
- &au1xxx_mmc_device,
#endif
#ifdef SMBUS_PSC_BASE
&pbdb_smbus_device,
diff --git a/arch/mips/au1000/pb1200/platform.c b/arch/mips/au1000/pb1200/platform.c
index 5930110..c87c173 100644
--- a/arch/mips/au1000/pb1200/platform.c
+++ b/arch/mips/au1000/pb1200/platform.c
@@ -20,8 +20,17 @@
#include <linux/init.h>
#include <linux/platform_device.h>
+#include <linux/mmc/host.h>
#include <asm/mach-au1x00/au1xxx.h>
+#include <asm/mach-au1x00/au1xxx_dbdma.h>
+#include <asm/mach-au1x00/au1100_mmc.h>
+
+#if defined(CONFIG_MIPS_PB1200)
+#include <asm/mach-pb1x00/pb1200.h>
+#elif defined(CONFIG_MIPS_DB1200)
+#include <asm/mach-db1x00/db1200.h>
+#endif
static struct resource ide_resources[] = {
[0] = {
@@ -70,9 +79,126 @@ static struct platform_device smc91c111_device = {
.resource = smc91c111_resources
};
+
+static const struct {
+ u16 bcsrpwr;
+ u16 bcsrstatus;
+ u16 wpstatus;
+} au1xmmc_card_table[] = {
+ { BCSR_BOARD_SD0PWR, BCSR_INT_SD0INSERT, BCSR_STATUS_SD0WP },
+#ifndef CONFIG_MIPS_DB1200
+ { BCSR_BOARD_SD1PWR, BCSR_INT_SD1INSERT, BCSR_STATUS_SD1WP }
+#endif
+};
+
+static void pb1200mmc_set_power(void *mmc_host, int state)
+{
+ struct au1xmmc_host *host = mmc_priv((struct mmc_host *)mmc_host);
+ u32 val = au1xmmc_card_table[host->id].bcsrpwr;
+
+ if (state)
+ bcsr->board |= val;
+ else
+ bcsr->board &= ~val;
+
+ au_sync_delay(1);
+}
+
+static int pb1200mmc_card_readonly(void *mmc_host)
+{
+ struct au1xmmc_host *host = mmc_priv((struct mmc_host *)mmc_host);
+ return (bcsr->status & au1xmmc_card_table[host->id].wpstatus) ? 1 : 0;
+}
+
+static int pb1200mmc_card_inserted(void *mmc_host)
+{
+ struct au1xmmc_host *host = mmc_priv((struct mmc_host *)mmc_host);
+ return (bcsr->sig_status & au1xmmc_card_table[host->id].bcsrstatus)
+ ? 1 : 0;
+}
+
+static struct au1xmmc_platdata db1xmmcpd = {
+ .set_power = pb1200mmc_set_power,
+ .card_inserted = pb1200mmc_card_inserted,
+ .card_readonly = pb1200mmc_card_readonly,
+ .cd_setup = NULL, /* use poll-timer in driver */
+};
+
+static u64 au1xxx_mmc_dmamask = ~(u32)0;
+
+struct resource au1200_sd0_res[] = {
+ [0] = {
+ .start = CPHYSADDR(SD0_BASE),
+ .end = CPHYSADDR(SD0_BASE) + 0x40,
+ .flags = IORESOURCE_MEM,
+ },
+ [2] = {
+ .start = AU1200_SD_INT,
+ .flags = IORESOURCE_IRQ,
+ },
+ [3] = {
+ .start = DSCR_CMD0_SDMS_TX0,
+ .flags = IORESOURCE_DMA,
+ },
+ [4] = {
+ .start = DSCR_CMD0_SDMS_RX0,
+ .flags = IORESOURCE_DMA,
+ },
+};
+
+static struct platform_device au1xxx_sd0_device = {
+ .name = "au1xxx-mmc",
+ .id = 0, /* index into au1xmmc_card_table[] */
+ .dev = {
+ .dma_mask = &au1xxx_mmc_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ .platform_data = &db1xmmcpd,
+ },
+ .num_resources = ARRAY_SIZE(au1200_sd0_res),
+ .resource = au1200_sd0_res,
+};
+
+#ifndef CONFIG_MIPS_DB1200
+struct resource au1200_sd1_res[] = {
+ [0] = {
+ .start = CPHYSADDR(SD1_BASE),
+ .end = CPHYSADDR(SD1_BASE) + 0x40,
+ .flags = IORESOURCE_MEM,
+ },
+ [2] = {
+ .start = AU1200_SD_INT,
+ .flags = IORESOURCE_IRQ,
+ },
+ [3] = {
+ .start = DSCR_CMD0_SDMS_TX1,
+ .flags = IORESOURCE_DMA,
+ },
+ [4] = {
+ .start = DSCR_CMD0_SDMS_RX1,
+ .flags = IORESOURCE_DMA,
+ },
+};
+
+static struct platform_device au1xxx_sd1_device = {
+ .name = "au1xxx-mmc",
+ .id = 1, /* index into au1xmmc_card_table[] */
+ .dev = {
+ .dma_mask = &au1xxx_mmc_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ .platform_data = &db1xmmcpd,
+ },
+ .num_resources = ARRAY_SIZE(au1200_sd1_res),
+ .resource = au1200_sd1_res,
+};
+#endif
+
static struct platform_device *board_platform_devices[] __initdata = {
&ide_device,
- &smc91c111_device
+ &smc91c111_device,
+ &au1xxx_sd0_device,
+#ifndef CONFIG_MIPS_DB1200
+ &au1xxx_sd1_device,
+#endif
};
static int __init board_register_devices(void)
--
1.5.5.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 5/7] au1xmmc: 4 bit transfer mode
2008-05-08 8:00 [PATCH 0/7] au1xmmc updates, #2 Manuel Lauss
` (3 preceding siblings ...)
2008-05-08 8:03 ` [PATCH 4/7] Alchemy: register mmc platform device for db1200/pb1200 boards Manuel Lauss
@ 2008-05-08 8:04 ` Manuel Lauss
2008-05-08 8:04 ` [PATCH 6/7] au1xmmc: wire up SDIO interrupt Manuel Lauss
2008-05-08 8:05 ` [PATCH 7/7] au1xmmc: codingstyle tidying Manuel Lauss
6 siblings, 0 replies; 11+ messages in thread
From: Manuel Lauss @ 2008-05-08 8:04 UTC (permalink / raw)
To: linux-mips, linux-kernel
>From f850f29297156c673fe3453c4c1c4642c46567e2 Mon Sep 17 00:00:00 2001
From: Manuel Lauss <mlau@msc-ge.com>
Date: Wed, 7 May 2008 15:04:51 +0200
Subject: [PATCH] au1xmmc: 4 bit transfer mode
Add 4 Bit transfer mode support.
Signed-off-by: Manuel Lauss <mano@roarinelk.homelinux.net>
---
drivers/mmc/host/au1xmmc.c | 21 +++++++++++++++++----
1 files changed, 17 insertions(+), 4 deletions(-)
diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c
index 8660f86..d9e334f 100644
--- a/drivers/mmc/host/au1xmmc.c
+++ b/drivers/mmc/host/au1xmmc.c
@@ -161,13 +161,13 @@ static inline void IRQ_OFF(struct au1xmmc_host *host, u32 mask)
static inline void SEND_STOP(struct au1xmmc_host *host)
{
- /* We know the value of CONFIG2, so avoid a read we don't need */
- u32 mask = SD_CONFIG2_EN;
+ u32 config2;
WARN_ON(host->status != HOST_S_DATA);
host->status = HOST_S_STOP;
- au_writel(mask | SD_CONFIG2_DF, HOST_CONFIG2(host));
+ config2 = au_readl(HOST_CONFIG2(host));
+ au_writel(config2 | SD_CONFIG2_DF, HOST_CONFIG2(host));
au_sync();
/* Send the stop commmand */
@@ -762,6 +762,7 @@ static void au1xmmc_reset_controller(struct au1xmmc_host *host)
static void au1xmmc_set_ios(struct mmc_host* mmc, struct mmc_ios* ios)
{
struct au1xmmc_host *host = mmc_priv(mmc);
+ u32 config;
if (ios->power_mode == MMC_POWER_OFF)
au1xmmc_set_power(host, 0);
@@ -773,6 +774,18 @@ static void au1xmmc_set_ios(struct mmc_host* mmc, struct mmc_ios* ios)
au1xmmc_set_clock(host, ios->clock);
host->clock = ios->clock;
}
+
+ config = au_readl(HOST_CONFIG2(host));
+ switch (ios->bus_width) {
+ case MMC_BUS_WIDTH_4:
+ config |= (1 << 8);
+ break;
+ case MMC_BUS_WIDTH_1:
+ config &= ~(1 << 8);
+ break;
+ }
+ au_writel(config, HOST_CONFIG2(host));
+ au_sync();
}
static void au1xmmc_dma_callback(int irq, void *dev_id)
@@ -985,7 +998,7 @@ static int __devinit au1xmmc_probe(struct platform_device *pdev)
mmc->max_blk_count = 512;
mmc->ocr_avail = AU1XMMC_OCR;
- mmc->caps = 0;
+ mmc->caps = MMC_CAP_4_BIT_DATA;
host->id = pdev->id;
host->status = HOST_S_IDLE;
--
1.5.5.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 6/7] au1xmmc: wire up SDIO interrupt
2008-05-08 8:00 [PATCH 0/7] au1xmmc updates, #2 Manuel Lauss
` (4 preceding siblings ...)
2008-05-08 8:04 ` [PATCH 5/7] au1xmmc: 4 bit transfer mode Manuel Lauss
@ 2008-05-08 8:04 ` Manuel Lauss
2008-05-08 8:05 ` [PATCH 7/7] au1xmmc: codingstyle tidying Manuel Lauss
6 siblings, 0 replies; 11+ messages in thread
From: Manuel Lauss @ 2008-05-08 8:04 UTC (permalink / raw)
To: linux-mips, linux-kernel
>From 53260bd4727f9d809c23578e7cbf0d1df47bc236 Mon Sep 17 00:00:00 2001
From: Manuel Lauss <mlau@msc-ge.com>
Date: Wed, 7 May 2008 15:18:14 +0200
Subject: [PATCH] au1xmmc: wire up SDIO interrupt
Signed-off-by: Manuel Lauss <mano@roarinelk.homelinux.net>
---
drivers/mmc/host/au1xmmc.c | 16 +++++++++++++++-
1 files changed, 15 insertions(+), 1 deletions(-)
diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c
index d9e334f..8b60509 100644
--- a/drivers/mmc/host/au1xmmc.c
+++ b/drivers/mmc/host/au1xmmc.c
@@ -817,6 +817,9 @@ static irqreturn_t au1xmmc_irq(int irq, void *dev_id)
if (!(status & (1 << 15)))
return IRQ_NONE; /* not ours */
+ if (status & 0x80000000) /* SDIO */
+ mmc_signal_sdio_irq(host->mmc);
+
if (host->mrq && (status & STATUS_TIMEOUT)) {
if (status & SD_STATUS_RAT)
host->mrq->cmd->error = -ETIMEDOUT;
@@ -903,10 +906,21 @@ static int au1xmmc_init_dma(struct au1xmmc_host *host)
return 0;
}
+static void au1xmmc_enable_sdio_irq(struct mmc_host *mmc, int en)
+{
+ struct au1xmmc_host *host = mmc_priv(mmc);
+
+ if (en)
+ IRQ_ON(host, (1 << 31));
+ else
+ IRQ_OFF(host, (1 << 31));
+}
+
static const struct mmc_host_ops au1xmmc_ops = {
.request = au1xmmc_request,
.set_ios = au1xmmc_set_ios,
.get_ro = au1xmmc_card_readonly,
+ .enable_sdio_irq = au1xmmc_enable_sdio_irq,
};
static void au1xmmc_poll_event(unsigned long arg)
@@ -998,7 +1012,7 @@ static int __devinit au1xmmc_probe(struct platform_device *pdev)
mmc->max_blk_count = 512;
mmc->ocr_avail = AU1XMMC_OCR;
- mmc->caps = MMC_CAP_4_BIT_DATA;
+ mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
host->id = pdev->id;
host->status = HOST_S_IDLE;
--
1.5.5.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 7/7] au1xmmc: codingstyle tidying
2008-05-08 8:00 [PATCH 0/7] au1xmmc updates, #2 Manuel Lauss
` (5 preceding siblings ...)
2008-05-08 8:04 ` [PATCH 6/7] au1xmmc: wire up SDIO interrupt Manuel Lauss
@ 2008-05-08 8:05 ` Manuel Lauss
6 siblings, 0 replies; 11+ messages in thread
From: Manuel Lauss @ 2008-05-08 8:05 UTC (permalink / raw)
To: linux-mips, linux-kernel
>From 4e439a8b70c5ab0ca36e7a653fbb1c19605e0ea6 Mon Sep 17 00:00:00 2001
From: Manuel Lauss <mlau@msc-ge.com>
Date: Wed, 7 May 2008 15:30:14 +0200
Subject: [PATCH] au1xmmc: codingstyle tidying
Make the driver source a bit easier on the eyes;
no functional changes.
Signed-off-by: Manuel Lauss <mano@roarinelk.homelinux.net>
---
drivers/mmc/host/au1xmmc.c | 139 ++++++++++++++++---------------------------
1 files changed, 52 insertions(+), 87 deletions(-)
diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c
index 8b60509..3b9833f 100644
--- a/drivers/mmc/host/au1xmmc.c
+++ b/drivers/mmc/host/au1xmmc.c
@@ -160,7 +160,6 @@ static inline void IRQ_OFF(struct au1xmmc_host *host, u32 mask)
static inline void SEND_STOP(struct au1xmmc_host *host)
{
-
u32 config2;
WARN_ON(host->status != HOST_S_DATA);
@@ -280,18 +279,14 @@ static int au1xmmc_send_command(struct au1xmmc_host *host, int wait,
au_sync();
/* Wait for the command to go on the line */
-
- while(1) {
- if (!(au_readl(HOST_CMD(host)) & SD_CMD_GO))
- break;
- }
+ while (au_readl(HOST_CMD(host)) & SD_CMD_GO)
+ /* nop */;
/* Wait for the command to come back */
-
if (wait) {
u32 status = au_readl(HOST_STATUS(host));
- while(!(status & SD_STATUS_CR))
+ while (!(status & SD_STATUS_CR))
status = au_readl(HOST_STATUS(host));
/* Clear the CR status */
@@ -305,12 +300,11 @@ static int au1xmmc_send_command(struct au1xmmc_host *host, int wait,
static void au1xmmc_data_complete(struct au1xmmc_host *host, u32 status)
{
-
struct mmc_request *mrq = host->mrq;
struct mmc_data *data;
u32 crc;
- WARN_ON(host->status != HOST_S_DATA && host->status != HOST_S_STOP);
+ WARN_ON((host->status != HOST_S_DATA) && (host->status != HOST_S_STOP));
if (host->mrq == NULL)
return;
@@ -321,15 +315,13 @@ static void au1xmmc_data_complete(struct au1xmmc_host *host, u32 status)
status = au_readl(HOST_STATUS(host));
/* The transaction is really over when the SD_STATUS_DB bit is clear */
-
- while((host->flags & HOST_F_XMIT) && (status & SD_STATUS_DB))
+ while ((host->flags & HOST_F_XMIT) && (status & SD_STATUS_DB))
status = au_readl(HOST_STATUS(host));
data->error = 0;
dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, host->dma.dir);
/* Process any errors */
-
crc = (status & (SD_STATUS_WC | SD_STATUS_RC));
if (host->flags & HOST_F_XMIT)
crc |= ((status & 0x07) == 0x02) ? 0 : 1;
@@ -346,11 +338,10 @@ static void au1xmmc_data_complete(struct au1xmmc_host *host, u32 status)
if (host->flags & HOST_F_DMA) {
u32 chan = DMA_CHANNEL(host);
- chan_tab_t *c = *((chan_tab_t **) chan);
+ chan_tab_t *c = *((chan_tab_t **)chan);
au1x_dma_chan_t *cp = c->chan_ptr;
data->bytes_xfered = cp->ddma_bytecnt;
- }
- else
+ } else
data->bytes_xfered =
(data->blocks * data->blksz) -
host->pio.len;
@@ -361,7 +352,7 @@ static void au1xmmc_data_complete(struct au1xmmc_host *host, u32 status)
static void au1xmmc_tasklet_data(unsigned long param)
{
- struct au1xmmc_host *host = (struct au1xmmc_host *) param;
+ struct au1xmmc_host *host = (struct au1xmmc_host *)param;
u32 status = au_readl(HOST_STATUS(host));
au1xmmc_data_complete(host, status);
@@ -371,11 +362,10 @@ static void au1xmmc_tasklet_data(unsigned long param)
static void au1xmmc_send_pio(struct au1xmmc_host *host)
{
-
- struct mmc_data *data = 0;
- int sg_len, max, count = 0;
- unsigned char *sg_ptr;
- u32 status = 0;
+ struct mmc_data *data;
+ int sg_len, max, count;
+ unsigned char *sg_ptr, val;
+ u32 status;
struct scatterlist *sg;
data = host->mrq->data;
@@ -390,22 +380,19 @@ static void au1xmmc_send_pio(struct au1xmmc_host *host)
/* This is the space left inside the buffer */
sg_len = data->sg[host->pio.index].length - host->pio.offset;
- /* Check to if we need less then the size of the sg_buffer */
-
+ /* Check if we need less than the size of the sg_buffer */
max = (sg_len > host->pio.len) ? host->pio.len : sg_len;
- if (max > AU1XMMC_MAX_TRANSFER) max = AU1XMMC_MAX_TRANSFER;
-
- for(count = 0; count < max; count++ ) {
- unsigned char val;
+ if (max > AU1XMMC_MAX_TRANSFER)
+ max = AU1XMMC_MAX_TRANSFER;
+ for (count = 0; count < max; count++) {
status = au_readl(HOST_STATUS(host));
-
if (!(status & SD_STATUS_TH))
break;
val = *sg_ptr++;
- au_writel((unsigned long) val, HOST_TXPORT(host));
+ au_writel((unsigned long)val, HOST_TXPORT(host));
au_sync();
}
@@ -429,11 +416,10 @@ static void au1xmmc_send_pio(struct au1xmmc_host *host)
static void au1xmmc_receive_pio(struct au1xmmc_host *host)
{
-
- struct mmc_data *data = 0;
- int sg_len = 0, max = 0, count = 0;
- unsigned char *sg_ptr = 0;
- u32 status = 0;
+ struct mmc_data *data;
+ int sg_len = 0, max, count;
+ unsigned char *sg_ptr = NULL;
+ u32 status;
struct scatterlist *sg;
data = host->mrq->data;
@@ -451,13 +437,14 @@ static void au1xmmc_receive_pio(struct au1xmmc_host *host)
sg_len = sg_dma_len(&data->sg[host->pio.index]) - host->pio.offset;
/* Check to if we need less then the size of the sg_buffer */
- if (sg_len < max) max = sg_len;
+ if (sg_len < max)
+ max = sg_len;
}
if (max > AU1XMMC_MAX_TRANSFER)
max = AU1XMMC_MAX_TRANSFER;
- for(count = 0; count < max; count++ ) {
+ for (count = 0; count < max; count++) {
u32 val;
status = au_readl(HOST_STATUS(host));
@@ -474,8 +461,7 @@ static void au1xmmc_receive_pio(struct au1xmmc_host *host)
DBG("RX Overrun [%d + %d]\n", host->id,
host->pio.len, count);
break;
- }
- else if (status & SD_STATUS_RU) {
+ } else if (status & SD_STATUS_RU) {
DBG("RX Underrun [%d + %d]\n", host->id,
host->pio.len, count);
break;
@@ -490,13 +476,13 @@ static void au1xmmc_receive_pio(struct au1xmmc_host *host)
host->pio.len -= count;
host->pio.offset += count;
- if (sg_len && count == sg_len) {
+ if (sg_len && (count == sg_len)) {
host->pio.index++;
host->pio.offset = 0;
}
if (host->pio.len == 0) {
- //IRQ_OFF(host, SD_CONFIG_RA | SD_CONFIG_RF);
+ /* IRQ_OFF(host, SD_CONFIG_RA | SD_CONFIG_RF); */
IRQ_OFF(host, SD_CONFIG_NE);
if (host->flags & HOST_F_STOP)
@@ -506,14 +492,11 @@ static void au1xmmc_receive_pio(struct au1xmmc_host *host)
}
}
-/* static void au1xmmc_cmd_complete
- This is called when a command has been completed - grab the response
- and check for errors. Then start the data transfer if it is indicated.
-*/
-
+/* This is called when a command has been completed - grab the response
+ * and check for errors. Then start the data transfer if it is indicated.
+ */
static void au1xmmc_cmd_complete(struct au1xmmc_host *host, u32 status)
{
-
struct mmc_request *mrq = host->mrq;
struct mmc_command *cmd;
int trans;
@@ -538,7 +521,6 @@ static void au1xmmc_cmd_complete(struct au1xmmc_host *host, u32 status)
* we only got 120 bytes, but the engine expects
* 128 bits, so we have to shift things up
*/
-
for(i = 0; i < 4; i++) {
cmd->resp[i] = (r[i] & 0x00FFFFFF) << 8;
if (i != 3)
@@ -557,15 +539,13 @@ static void au1xmmc_cmd_complete(struct au1xmmc_host *host, u32 status)
}
/* Figure out errors */
-
if (status & (SD_STATUS_SC | SD_STATUS_WC | SD_STATUS_RC))
cmd->error = -EILSEQ;
trans = host->flags & (HOST_F_XMIT | HOST_F_RECV);
if (!trans || cmd->error) {
-
- IRQ_OFF(host, SD_CONFIG_TH | SD_CONFIG_RA|SD_CONFIG_RF);
+ IRQ_OFF(host, SD_CONFIG_TH | SD_CONFIG_RA | SD_CONFIG_RF);
tasklet_schedule(&host->finish_task);
return;
}
@@ -576,29 +556,25 @@ static void au1xmmc_cmd_complete(struct au1xmmc_host *host, u32 status)
u32 channel = DMA_CHANNEL(host);
/* Start the DMA as soon as the buffer gets something in it */
-
if (host->flags & HOST_F_RECV) {
u32 mask = SD_STATUS_DB | SD_STATUS_NE;
- while((status & mask) != mask)
+ while ((status & mask) != mask)
status = au_readl(HOST_STATUS(host));
}
-
au1xxx_dbdma_start(channel);
}
}
static void au1xmmc_set_clock(struct au1xmmc_host *host, int rate)
{
-
unsigned int pbus = get_au1x00_speed();
unsigned int divisor;
u32 config;
/* From databook:
- divisor = ((((cpuclock / sbus_divisor) / 2) / mmcclock) / 2) - 1
- */
-
+ * divisor = ((((cpuclock / sbus_divisor) / 2) / mmcclock) / 2) - 1
+ */
pbus /= ((au_readl(SYS_POWERCTRL) & 0x3) + 2);
pbus /= 2;
@@ -616,7 +592,6 @@ static void au1xmmc_set_clock(struct au1xmmc_host *host, int rate)
static int
au1xmmc_prepare_data(struct au1xmmc_host *host, struct mmc_data *data)
{
-
int datalen = data->blocks * data->blksz;
if (dma != 0)
@@ -647,32 +622,31 @@ au1xmmc_prepare_data(struct au1xmmc_host *host, struct mmc_data *data)
au1xxx_dbdma_stop(channel);
for(i = 0; i < host->dma.len; i++) {
- u32 ret = 0, flags = DDMA_FLAGS_NOIE;
+ u32 ret, flags;
struct scatterlist *sg = &data->sg[i];
int sg_len = sg->length;
int len = (datalen > sg_len) ? sg_len : datalen;
- if (i == host->dma.len - 1)
+ if (i == (host->dma.len - 1))
flags = DDMA_FLAGS_IE;
-
- if (host->flags & HOST_F_XMIT){
- ret = au1xxx_dbdma_put_source_flags(channel,
- (void *) sg_virt(sg), len, flags);
- }
- else {
- ret = au1xxx_dbdma_put_dest_flags(channel,
- (void *) sg_virt(sg),
- len, flags);
+ else
+ flags = DDMA_FLAGS_NOIE;
+
+ if (host->flags & HOST_F_XMIT){
+ ret = au1xxx_dbdma_put_source_flags(channel,
+ (void *)sg_virt(sg), len, flags);
+ } else {
+ ret = au1xxx_dbdma_put_dest_flags(channel,
+ (void *)sg_virt(sg), len, flags);
}
- if (!ret)
+ if (!ret)
goto dataerr;
datalen -= len;
}
- }
- else {
+ } else {
host->pio.index = 0;
host->pio.offset = 0;
host->pio.len = datalen;
@@ -681,25 +655,19 @@ au1xmmc_prepare_data(struct au1xmmc_host *host, struct mmc_data *data)
IRQ_ON(host, SD_CONFIG_TH);
else
IRQ_ON(host, SD_CONFIG_NE);
- //IRQ_ON(host, SD_CONFIG_RA|SD_CONFIG_RF);
+ /* IRQ_ON(host, SD_CONFIG_RA|SD_CONFIG_RF); */
}
return 0;
- dataerr:
+dataerr:
dma_unmap_sg(mmc_dev(host->mmc),data->sg,data->sg_len,host->dma.dir);
return -ETIMEDOUT;
}
-/* static void au1xmmc_request
- This actually starts a command or data transaction
-*/
-
static void au1xmmc_request(struct mmc_host* mmc, struct mmc_request* mrq)
{
-
struct au1xmmc_host *host = mmc_priv(mmc);
- unsigned int flags = 0;
int ret = 0;
WARN_ON(irqs_disabled());
@@ -714,7 +682,6 @@ static void au1xmmc_request(struct mmc_host* mmc, struct mmc_request* mrq)
if (mrq->data) {
FLUSH_FIFO(host);
- flags = mrq->data->flags;
ret = au1xmmc_prepare_data(host, mrq->data);
}
@@ -729,7 +696,6 @@ static void au1xmmc_request(struct mmc_host* mmc, struct mmc_request* mrq)
static void au1xmmc_reset_controller(struct au1xmmc_host *host)
{
-
/* Apply the clock */
au_writel(SD_ENABLE_CE, HOST_ENABLE(host));
au_sync_delay(1);
@@ -759,7 +725,7 @@ static void au1xmmc_reset_controller(struct au1xmmc_host *host)
}
-static void au1xmmc_set_ios(struct mmc_host* mmc, struct mmc_ios* ios)
+static void au1xmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct au1xmmc_host *host = mmc_priv(mmc);
u32 config;
@@ -790,10 +756,9 @@ static void au1xmmc_set_ios(struct mmc_host* mmc, struct mmc_ios* ios)
static void au1xmmc_dma_callback(int irq, void *dev_id)
{
- struct au1xmmc_host *host = (struct au1xmmc_host *) dev_id;
+ struct au1xmmc_host *host = (struct au1xmmc_host *)dev_id;
/* Avoid spurious interrupts */
-
if (!host->mrq)
return;
@@ -845,7 +810,7 @@ static irqreturn_t au1xmmc_irq(int irq, void *dev_id)
#endif
else if (status & (SD_STATUS_CR)) {
if (host->status == HOST_S_CMD)
- au1xmmc_cmd_complete(host,status);
+ au1xmmc_cmd_complete(host, status);
} else if (!(host->flags & HOST_F_DMA)) {
if ((host->flags & HOST_F_XMIT) && (status & STATUS_DATA_OUT))
--
1.5.5.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH 3/7] au1xmmc: remove db1x00 board-specific functions from driver
2008-05-08 8:03 ` [PATCH 3/7] au1xmmc: remove db1x00 board-specific functions from driver Manuel Lauss
@ 2008-05-12 11:36 ` Sergei Shtylyov
2008-05-14 8:37 ` Manuel Lauss
2008-05-13 9:27 ` Sergei Shtylyov
1 sibling, 1 reply; 11+ messages in thread
From: Sergei Shtylyov @ 2008-05-12 11:36 UTC (permalink / raw)
To: Manuel Lauss; +Cc: linux-mips, linux-kernel
Hello.
Manuel Lauss wrote:
> From 47ecf116465ed850d2202880f7795fcee4826184 Mon Sep 17 00:00:00 2001
> From: Manuel Lauss <mlau@msc-ge.com>
> Date: Wed, 7 May 2008 14:57:01 +0200
> Subject: [PATCH] au1xmmc: remove db1x00 board-specific functions from driver
>
> Remove the DB1200 board-specific functions (card present, read-only
> methods) and instead add platform data which is passed to the driver.
> This allows for platforms to implement other carddetect schemes
> (e.g. dedicated irq) without having to pollute the driver code.
> The poll timer (used for pb1200) is kept for compatibility.
>
> With the board-specific stuff gone, the driver no longer needs to know
> how many physical controllers the silicon actually has; every device
> can be registered as needed, update the code to reflect that.
>
> Signed-off-by: Manuel Lauss <mano@roarinelk.homelinux.net>
>
[...]
> diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c
> index cc5f7bc..8660f86 100644
> --- a/drivers/mmc/host/au1xmmc.c
> +++ b/drivers/mmc/host/au1xmmc.c
> @@ -49,7 +49,6 @@
> #include <asm/mach-au1x00/au1100_mmc.h>
>
> #include <au1xxx.h>
> -#include "au1xmmc.h"
>
I think you should merge the header to the driver in a separate patch.
> @@ -174,8 +221,6 @@ static void au1xmmc_finish_request(struct au1xmmc_host *host)
>
> host->status = HOST_S_IDLE;
>
> - bcsr->disk_leds |= (1 << 8);
> -
>
So, the LED support is gone with your patch? You should at least
document this...
> mmc_request_done(host->mmc, mrq);
> }
>
> @@ -663,7 +708,9 @@ static void au1xmmc_request(struct mmc_host* mmc, struct mmc_request* mrq)
> host->mrq = mrq;
> host->status = HOST_S_CMD;
>
> - bcsr->disk_leds &= ~(1 << 8);
> + au_writel(0, HOST_STATUS(host));
> + au_sync();
> + FLUSH_FIFO(host);
>
Hm, not an obvious change...
>
> if (mrq->data) {
> FLUSH_FIFO(host);
> @@ -749,118 +796,87 @@ static void au1xmmc_dma_callback(int irq, void *dev_id)
>
> static irqreturn_t au1xmmc_irq(int irq, void *dev_id)
> {
> -
> + struct au1xmmc_host *host = dev_id;
> u32 status;
> - int i, ret = 0;
>
> - disable_irq(AU1100_SD_IRQ);
> + status = au_readl(HOST_STATUS(host));
>
> - for(i = 0; i < AU1XMMC_CONTROLLER_COUNT; i++) {
> - struct au1xmmc_host * host = au1xmmc_hosts[i];
> - u32 handled = 1;
> + if (!(status & (1 << 15)))
>
Why not SD_STATUS_I?
> + //IRQ_OFF(host, SD_CONFIG_TH|SD_CONFIG_RA|SD_CONFIG_RF);
>
No C99 // comments please -- checkpatch.pl would have given you error
about them...
> + } else if (status & 0x203FBC70) {
>
I think the mask should be changed to 0x203F3C70 since you're
handling SD_STATUS_I but maybe I'm wrong...
> -static void au1xmmc_init_dma(struct au1xmmc_host *host)
> +static int au1xmmc_init_dma(struct au1xmmc_host *host)
>
I'd have called it au1xmmc_init_dbdma() instead since in Au1100 the
controller works with its "old-style" DMA... though maybe the difference
could be handled within this function via #ifdef...
> @@ -878,116 +896,201 @@ static const struct mmc_host_ops au1xmmc_ops = {
> .get_ro = au1xmmc_card_readonly,
> };
>
> -static int __devinit au1xmmc_probe(struct platform_device *pdev)
> +static void au1xmmc_poll_event(unsigned long arg)
> {
> + struct au1xmmc_host *host = (struct au1xmmc_host *)arg;
>
Don't need new line here...
>
> - int i, ret = 0;
> + int card = au1xmmc_card_inserted(host);
> + int controller = (host->flags & HOST_F_ACTIVE) ? 1 : 0;
>
Remove extra space please. And what does this variable actually mean?
> + host->iobase = (unsigned long)ioremap(r->start, 0xff);
>
You have the r->end specifying the resource end, why 0xff (well,
actually 0x3c is enough)
> @@ -1004,21 +1107,32 @@ static struct platform_driver au1xmmc_driver = {
>
> static int __init au1xmmc_init(void)
> {
> + if (dma) {
> + /* DSCR_CMD0_ALWAYS has a stride of 32 bits, we need a stride
> + * of 8 bits. And since devices are shared, we need to create
> + * our own to avoid freaking out other devices
>
Missing period at end of statement.
> + */
> + if (!memid)
>
Hm, is there a chance that it won't be NULL?
> + memid = au1xxx_ddma_add_device(&au1xmmc_mem_dbdev);
> + if (!memid) {
> + printk(KERN_ERR "au1xmmc: cannot add memory dma dev\n");
> + return -ENODEV;
> + }
> + }
> return platform_driver_register(&au1xmmc_driver);
> }
[...]
> diff --git a/include/asm-mips/mach-au1x00/au1100_mmc.h b/include/asm-mips/mach-au1x00/au1100_mmc.h
> index 9e0028f..6474fac 100644
> --- a/include/asm-mips/mach-au1x00/au1100_mmc.h
> +++ b/include/asm-mips/mach-au1x00/au1100_mmc.h
> @@ -38,15 +38,46 @@
> #ifndef __ASM_AU1100_MMC_H
> #define __ASM_AU1100_MMC_H
>
>
[...]
> +struct au1xmmc_platdata {
>
I'd suggest au1xmmc_platform_data.
> + int(*cd_setup)(void *mmc_host, int on);
> + int(*card_inserted)(void *mmc_host);
> + int(*card_readonly)(void *mmc_host);
> + void(*set_power)(void *mmc_host, int state);
> +};
> +
> +struct au1xmmc_host {
> + struct mmc_host *mmc;
> + struct mmc_request *mrq;
> +
> + u32 id;
> +
> + u32 flags;
> + u32 iobase;
> + u32 clock;
> +
> + int status;
> +
> + struct {
> + int len;
> + int dir;
> + u32 tx_chan;
> + u32 rx_chan;
> + } dma;
> +
> + struct {
> + int index;
> + int offset;
> + int len;
> + } pio;
> +
> + struct timer_list timer;
> + struct tasklet_struct finish_task;
> + struct tasklet_struct data_task;
> +
> + struct platform_device *pdev;
> + struct au1xmmc_platdata *platdata;
> + int irq;
> +};
Hm, do you need the above structure to be visible from the platform code?
WBR, Sergei
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 3/7] au1xmmc: remove db1x00 board-specific functions from driver
2008-05-08 8:03 ` [PATCH 3/7] au1xmmc: remove db1x00 board-specific functions from driver Manuel Lauss
2008-05-12 11:36 ` Sergei Shtylyov
@ 2008-05-13 9:27 ` Sergei Shtylyov
1 sibling, 0 replies; 11+ messages in thread
From: Sergei Shtylyov @ 2008-05-13 9:27 UTC (permalink / raw)
To: Manuel Lauss; +Cc: linux-mips, linux-kernel
Hello.
Manuel Lauss wrote:
> Remove the DB1200 board-specific functions (card present, read-only
> methods) and instead add platform data which is passed to the driver.
> This allows for platforms to implement other carddetect schemes
> (e.g. dedicated irq) without having to pollute the driver code.
> The poll timer (used for pb1200) is kept for compatibility.
>
> With the board-specific stuff gone, the driver no longer needs to know
> how many physical controllers the silicon actually has; every device
> can be registered as needed, update the code to reflect that.
>
> Signed-off-by: Manuel Lauss <mano@roarinelk.homelinux.net>
[...]
> diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c
> index cc5f7bc..8660f86 100644
> --- a/drivers/mmc/host/au1xmmc.c
> +++ b/drivers/mmc/host/au1xmmc.c
[...]
> +static int __devinit au1xmmc_probe(struct platform_device *pdev)
> +{
> + struct mmc_host *mmc;
> + struct au1xmmc_host *host;
> + struct resource *r;
> + int ret;
> +
> + mmc = mmc_alloc_host(sizeof(struct au1xmmc_host), &pdev->dev);
> + if (!mmc) {
> + dev_err(&pdev->dev, "no memory for mmc host\n");
> + ret = -ENOMEM;
> + goto out0;
> + }
>
> - if (!mmc) {
> - printk(DRIVER_NAME "ERROR: no mem for host %d\n", i);
> - au1xmmc_hosts[i] = 0;
> - continue;
> - }
> + host = mmc_priv(mmc);
> + host->mmc = mmc;
> + host->platdata = pdev->dev.platform_data;
> + host->pdev = pdev;
>
> - mmc->ops = &au1xmmc_ops;
> + ret = -ENODEV;
> + r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + if (!r) {
> + dev_err(&pdev->dev, "no mmio defined\n");
> + goto out1;
> + }
>
I forgot to mention that the driver should be calling
request_mem_region() here...
WBR, Sergei
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 3/7] au1xmmc: remove db1x00 board-specific functions from driver
2008-05-12 11:36 ` Sergei Shtylyov
@ 2008-05-14 8:37 ` Manuel Lauss
0 siblings, 0 replies; 11+ messages in thread
From: Manuel Lauss @ 2008-05-14 8:37 UTC (permalink / raw)
To: Sergei Shtylyov; +Cc: linux-mips, linux-kernel
Hello Sergei,
>> #include <asm/mach-au1x00/au1100_mmc.h>
>> #include <au1xxx.h>
>> -#include "au1xmmc.h"
>>
> I think you should merge the header to the driver in a separate patch.
Okay...
>> @@ -174,8 +221,6 @@ static void au1xmmc_finish_request(struct au1xmmc_host
>> *host)
>> host->status = HOST_S_IDLE;
>> - bcsr->disk_leds |= (1 << 8);
>> -
>>
> So, the LED support is gone with your patch? You should at least document
> this...
Okay...
>> mmc_request_done(host->mmc, mrq);
>> }
>> @@ -663,7 +708,9 @@ static void au1xmmc_request(struct mmc_host* mmc,
>> struct mmc_request* mrq)
>> host->mrq = mrq;
>> host->status = HOST_S_CMD;
>> - bcsr->disk_leds &= ~(1 << 8);
>> + au_writel(0, HOST_STATUS(host));
>> + au_sync();
>> + FLUSH_FIFO(host);
>>
> Hm, not an obvious change...
Gone (leftovers from debugging MMC and other non-working cards)
>> if (mrq->data) {
>> FLUSH_FIFO(host);
>> @@ -749,118 +796,87 @@ static void au1xmmc_dma_callback(int irq, void
>> *dev_id)
>> static irqreturn_t au1xmmc_irq(int irq, void *dev_id)
>> {
>> -
>> + struct au1xmmc_host *host = dev_id;
>> u32 status;
>> - int i, ret = 0;
>> - disable_irq(AU1100_SD_IRQ);
>> + status = au_readl(HOST_STATUS(host));
>> - for(i = 0; i < AU1XMMC_CONTROLLER_COUNT; i++) {
>> - struct au1xmmc_host * host = au1xmmc_hosts[i];
>> - u32 handled = 1;
>> + if (!(status & (1 << 15)))
>>
> Why not SD_STATUS_I?
Good point, I'll add named constants for other values as well.
>> + //IRQ_OFF(host, SD_CONFIG_TH|SD_CONFIG_RA|SD_CONFIG_RF);
>>
> No C99 // comments please -- checkpatch.pl would have given you error
> about them...
It did-- but since I was just shuffling code around I was hesitant to do
these changes as well in this particular patch (the i2c maintainer for
instance wants functional and cosmetic changes in separate patches;
and every maintainer has different preferences, so I left those lines
untouched to not add additional noise).
>> + } else if (status & 0x203FBC70) {
>>
> I think the mask should be changed to 0x203F3C70 since you're handling
> SD_STATUS_I but maybe I'm wrong...
Yes you're right (but this line never triggered while testing so it's
harmless).
>> -static void au1xmmc_init_dma(struct au1xmmc_host *host)
>> +static int au1xmmc_init_dma(struct au1xmmc_host *host)
>>
> I'd have called it au1xmmc_init_dbdma() instead since in Au1100 the
> controller works with its "old-style" DMA... though maybe the difference
> could be handled within this function via #ifdef...
I like the renamed function, but again, I was just shuffling code around
(more or less) so I didn't touch the name(s).
For the time being, I'll leave it as-is, and if someday Au1100 DMA is added
the functions can be renamed or beautified with tons of ifdefs.
What do you think?
>> @@ -878,116 +896,201 @@ static const struct mmc_host_ops au1xmmc_ops = {
>> .get_ro = au1xmmc_card_readonly,
>> };
>> -static int __devinit au1xmmc_probe(struct platform_device *pdev)
>> +static void au1xmmc_poll_event(unsigned long arg)
>> {
>> + struct au1xmmc_host *host = (struct au1xmmc_host *)arg;
>>
> Don't need new line here...
Okay...
>> - int i, ret = 0;
>> + int card = au1xmmc_card_inserted(host);
>> + int controller = (host->flags & HOST_F_ACTIVE) ? 1 : 0;
>>
> Remove extra space please. And what does this variable actually mean?
Based on HOST_F_ACTIVE the driver determines if it is possible that there's
a card in the socket. Again, I just did code shuffling here.
>> + host->iobase = (unsigned long)ioremap(r->start, 0xff);
>>
> You have the r->end specifying the resource end, why 0xff (well, actually
> 0x3c is enough)
Okay...
>> @@ -1004,21 +1107,32 @@ static struct platform_driver au1xmmc_driver = {
>> static int __init au1xmmc_init(void)
>> {
>> + if (dma) {
>> + /* DSCR_CMD0_ALWAYS has a stride of 32 bits, we need a stride
>> + * of 8 bits. And since devices are shared, we need to create
>> + * our own to avoid freaking out other devices
>>
> Missing period at end of statement.
Okay...
>> + */
>> + if (!memid)
>>
> Hm, is there a chance that it won't be NULL?
Are global vars initialized to zero on module load? Then it can go away of
course.
>> + memid = au1xxx_ddma_add_device(&au1xmmc_mem_dbdev);
>> + if (!memid) {
>> + printk(KERN_ERR "au1xmmc: cannot add memory dma dev\n");
>> + return -ENODEV;
>> + }
>> + }
>> return platform_driver_register(&au1xmmc_driver);
>> }
> [...]
>> diff --git a/include/asm-mips/mach-au1x00/au1100_mmc.h
>> b/include/asm-mips/mach-au1x00/au1100_mmc.h
>> index 9e0028f..6474fac 100644
>> --- a/include/asm-mips/mach-au1x00/au1100_mmc.h
>> +++ b/include/asm-mips/mach-au1x00/au1100_mmc.h
>> @@ -38,15 +38,46 @@
>> #ifndef __ASM_AU1100_MMC_H
>> #define __ASM_AU1100_MMC_H
>>
> [...]
>> +struct au1xmmc_platdata {
>>
> I'd suggest au1xmmc_platform_data.
Too much to type for my taste, but okay, changed.
>> + int(*cd_setup)(void *mmc_host, int on);
>> + int(*card_inserted)(void *mmc_host);
>> + int(*card_readonly)(void *mmc_host);
>> + void(*set_power)(void *mmc_host, int state);
>> +};
>> +
>> +struct au1xmmc_host {
>> + struct mmc_host *mmc;
>> + struct mmc_request *mrq;
>> +
>> + u32 id;
>> +
>> + u32 flags;
>> + u32 iobase;
>> + u32 clock;
>> +
>> + int status;
>> +
>> + struct {
>> + int len;
>> + int dir;
>> + u32 tx_chan;
>> + u32 rx_chan;
>> + } dma;
>> +
>> + struct {
>> + int index;
>> + int offset;
>> + int len;
>> + } pio;
>> +
>> + struct timer_list timer;
>> + struct tasklet_struct finish_task;
>> + struct tasklet_struct data_task;
>> +
>> + struct platform_device *pdev;
>> + struct au1xmmc_platdata *platdata;
>> + int irq;
>> +};
> Hm, do you need the above structure to be visible from the platform code?
The db1200 board stuff references the ->id member to determine which BCSR
bits it should pay attention to. It can go into the driver code if you are
okay with adding platform data for every one of both SD controllers on the
PB1200 (which means lots of duplicated code which only differs in BCSR
constants). I'm okay with eiher solution, which do you prefer?
> WBR, Sergei
Thanks for having a look!
Manuel Lauss
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2008-05-14 8:37 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-05-08 8:00 [PATCH 0/7] au1xmmc updates, #2 Manuel Lauss
2008-05-08 8:01 ` [PATCH 1/7] Alchemy: export get_au1x00_speed for modules Manuel Lauss
2008-05-08 8:02 ` [PATCH 2/7] Alchemy: dbdma: add API to delete custom DDMA device ids Manuel Lauss
2008-05-08 8:03 ` [PATCH 3/7] au1xmmc: remove db1x00 board-specific functions from driver Manuel Lauss
2008-05-12 11:36 ` Sergei Shtylyov
2008-05-14 8:37 ` Manuel Lauss
2008-05-13 9:27 ` Sergei Shtylyov
2008-05-08 8:03 ` [PATCH 4/7] Alchemy: register mmc platform device for db1200/pb1200 boards Manuel Lauss
2008-05-08 8:04 ` [PATCH 5/7] au1xmmc: 4 bit transfer mode Manuel Lauss
2008-05-08 8:04 ` [PATCH 6/7] au1xmmc: wire up SDIO interrupt Manuel Lauss
2008-05-08 8:05 ` [PATCH 7/7] au1xmmc: codingstyle tidying Manuel Lauss
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox