📄 sdio.patch
字号:
diff -Naur -x '.*' -x '*~' -x '*.o' -x '*.ko' -x '*.mod.c' -x '*.cmd' linux26-cvs.BOM/drivers/mmc/au1xmmc.c linux26-cvs.sdio/drivers/mmc/au1xmmc.c--- linux26-cvs.BOM/drivers/mmc/au1xmmc.c 2005-10-20 18:17:10.000000000 +0200+++ linux26-cvs.sdio/drivers/mmc/au1xmmc.c 2005-10-20 18:19:25.000000000 +0200@@ -15,6 +15,9 @@ * (drivers/mmc/pxa.c) Copyright (C) 2003 Russell King, * All Rights Reserved. + * SDIO support: Copyright 2005 ADVANCED MICRO DEVICES, INC. All Rights Reserved.+ * by Robert Richter+ * 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.@@ -49,6 +52,8 @@ #include <asm/mach-au1x00/au1100_mmc.h> #include <asm/scatterlist.h> +#undef CONFIG_PM+ #ifdef CONFIG_MIPS_PB1200 #include <asm/mach-pb1x00/pb1200.h> #endif@@ -62,6 +67,7 @@ #endif +#include <linux/mmc/sdiohost.h> #include "au1xmmc.h" #define DRIVER_NAME "au1xxx-mmc"@@ -75,10 +81,10 @@ /* Set this to enable special debugging macros */ /* #define MMC_DEBUG */ -#ifdef MMC_DEBUG-#define DEBUG(fmt, idx, args...) printk("au1xx(%d): DEBUG: " fmt, idx, ##args)+#ifdef CONFIG_MMC_DEBUG+#define DBG(fmt, x...) printk("%s:%4d: " fmt, "AU1XMMC", __LINE__, ##x) #else-#define DEBUG(fmt, idx, args...)+#define DBG(fmt, args...) do { } while (0) #endif #ifdef CONFIG_PM @@ -224,14 +230,17 @@ u32 mmccmd = (cmd->opcode << SD_CMD_CI_SHIFT); - switch(cmd->flags) {+ switch(cmd->flags & MMC_RSP_BITS) {+ case MMC_RSP_NONE:+ mmccmd |= SD_CMD_RT_0;+ break; case MMC_RSP_R1: #ifdef AU1XMMC_DO_SD if (cmd->opcode == 0x03 && host->mmc->mode == MMC_MODE_SD) mmccmd |= SD_CMD_RT_6; else #endif- mmccmd |= SD_CMD_RT_1;+ mmccmd |= SD_CMD_RT_1; break; case MMC_RSP_R1B: mmccmd |= SD_CMD_RT_1B;@@ -242,6 +251,15 @@ case MMC_RSP_R3: mmccmd |= SD_CMD_RT_3; break;+ case SDIO_RSP_R4:+ mmccmd |= SD_CMD_RT_4;+ break;+ case SDIO_RSP_R5:+ mmccmd |= SD_CMD_RT_5;+ break;+ default:+ return MMC_ERR_INVALID;+ break; } switch(cmd->opcode) {@@ -255,13 +273,40 @@ case MMC_WRITE_BLOCK: mmccmd |= SD_CMD_CT_1; break;- case MMC_WRITE_MULTIPLE_BLOCK: mmccmd |= SD_CMD_CT_3; break;+ case SD_IO_SEND_OP_COND:+ case SD_IO_RW_DIRECT:+ case SD_IO_RW_EXTENDED:+ switch (cmd->flags & SDIO_DAT_MASK) {+ case SDIO_DAT_WR_BLK:+ mmccmd |= SD_CMD_CT_1;+ break;+ case SDIO_DAT_RD_BLK:+ mmccmd |= SD_CMD_CT_2;+ break;+ case SDIO_DAT_WR_MULTI_BLK:+ mmccmd |= SD_CMD_CT_3;+ break;+ case SDIO_DAT_RD_MULTI_BLK:+ mmccmd |= SD_CMD_CT_4;+ break;+ case SDIO_DAT_STOP:+ mmccmd |= SD_CMD_CT_7;+ break;+ case SDIO_DAT_NONE:+ default:+ mmccmd |= SD_CMD_CT_0;+ break;+ }+ break; case MMC_STOP_TRANSMISSION: mmccmd |= SD_CMD_CT_7; break;+ default:+ mmccmd |= SD_CMD_CT_0;+ break; } au_writel(cmd->arg, HOST_CMDARG(host));@@ -275,6 +320,7 @@ /* Wait for the command to go on the line */ + /* FIXME: This may end in an infinite loop */ while(1) { if (!(au_readl(HOST_CMD(host)) & SD_CMD_GO)) break;@@ -285,6 +331,7 @@ if (wait) { u32 status = au_readl(HOST_STATUS(host)); + /* FIXME: This may end in an infinite loop */ while(!(status & SD_STATUS_CR)) status = au_readl(HOST_STATUS(host)); @@ -315,6 +362,7 @@ /* The transaction is really over when the SD_STATUS_DB bit is clear */ + /* FIXME: This may end in an infinite loop */ while((host->flags & HOST_F_XMIT) && (status & SD_STATUS_DB)) status = au_readl(HOST_STATUS(host)); @@ -340,7 +388,7 @@ u32 chan = DMA_CHANNEL(host); chan_tab_t *c = *((chan_tab_t **) chan);- volatile au1x_dma_chan_t *cp = c->chan_ptr;+ au1x_dma_chan_t *cp = c->chan_ptr; data->bytes_xfered = cp->ddma_bytecnt; } else @@ -452,18 +500,18 @@ break; if (status & SD_STATUS_RC) {- DEBUG("RX CRC Error [%d + %d].\n", host->id, + DBG("#%d: RX CRC Error [%d + %d].\n", host->id, host->pio.len, count); break; } if (status & SD_STATUS_RO) {- DEBUG("RX Overrun [%d + %d]\n", host->id, + DBG("#%d: RX Overrun [%d + %d]\n", host->id, host->pio.len, count); break; } else if (status & SD_STATUS_RU) {- DEBUG("RX Underrun [%d + %d]\n", host->id, + DBG("#%d: RX Underrun [%d + %d]\n", host->id, host->pio.len, count); break; }@@ -562,6 +610,7 @@ /* Start the DMA as soon as the buffer gets something in it */ + /* FIXME: This may end in an infinite loop */ if (host->flags & HOST_F_RECV) { u32 mask = SD_STATUS_DB | SD_STATUS_NE; @@ -647,12 +696,12 @@ if (i == (host->dma.len - 1)) flags = DDMA_FLAGS_IE; - if (host->flags & HOST_F_XMIT)- ret = au1xxx_dbdma_put_source_flags(channel, + if (host->flags & HOST_F_XMIT)+ ret = au1xxx_dbdma_put_source_flags(channel, (void *) phys_to_virt(sg_addr), len, flags);- else- ret = au1xxx_dbdma_put_dest_flags(channel, + else+ ret = au1xxx_dbdma_put_dest_flags(channel, (void *) phys_to_virt(sg_addr), len, flags); @@ -661,10 +710,11 @@ datalen -= len; }-+ return MMC_ERR_NONE; dataerr:+ DBG("Data error\n"); dma_unmap_sg(mmc_dev(host->mmc),data->sg,data->sg_len,host->dma.dir); return MMC_ERR_TIMEOUT; } @@ -726,7 +776,7 @@ au_sync(); /* Configure interrupts */- au_writel(AU1XMMC_INTERRUPTS, HOST_CONFIG(host));+ au_writel(AU1XMMC_INTERRUPTS | SD_CONFIG_SI, HOST_CONFIG(host)); au_sync(); } @@ -734,7 +784,7 @@ static void au1xmmc_set_ios(struct mmc_host* mmc, struct mmc_ios* ios) { struct au1xmmc_host *host = mmc_priv(mmc); - DEBUG("set_ios (power=%u, clock=%uHz, vdd=%u, mode=%u)\n",+ DBG("#%d: set_ios (power=%u, clock=%uHz, vdd=%u, mode=%u)\n", host->id, ios->power_mode, ios->clock, ios->vdd, ios->bus_mode); @@ -798,12 +848,17 @@ status = au_readl(HOST_STATUS(host)); if (host->mrq && (status & STATUS_TIMEOUT)) {- if (status & SD_STATUS_RAT) + if (status & SD_STATUS_RAT) {+ DBG("Response access timeout\n"); host->mrq->cmd->error = MMC_ERR_TIMEOUT;+ }+ else if (status & SD_STATUS_DT) {+ DBG("Data access timeout\n");+ if (host->mrq->data != NULL)+ host->mrq->data->error =+ MMC_ERR_TIMEOUT;+ } - else if (status & SD_STATUS_DT) - host->mrq->data->error = MMC_ERR_TIMEOUT;- /* In PIO mode, interrupts might still be enabled */ IRQ_OFF(host, SD_CONFIG_NE | SD_CONFIG_TH); tasklet_schedule(&host->finish_task);@@ -820,8 +875,11 @@ (status & STATUS_DATA_IN)) au1xmmc_receive_pio(host); }+ else if (status & (SD_STATUS_SI)) {+ sdio_host_irq_handler(host->mmc);+ } else if (status & 0x203FBC70) {- DEBUG("Unhandled status %8.8x\n", host->id, status);+ DBG("#%d: Unhandled status %8.8x\n", host->id, status); handled = 0; } @@ -850,8 +908,8 @@ #ifdef MMC_DEBUG if (host->mrq != NULL) {- u32 status = au_readl(HOST_STATUS(host));- DEBUG("PENDING - %8.8x\n", host->id, status);+ DBG("#%d: PENDING - %8.8x\n", host->id, + au_readl(HOST_STATUS(host))); } #endif @@ -911,7 +969,7 @@ int i, ret = 0; - /* THe interrupt is shared among all controllers */+ /* The interrupt is shared among all controllers */ ret = request_irq(AU1100_SD_IRQ, au1xmmc_irq, SA_INTERRUPT, "MMC", 0); if (ret) {@@ -922,6 +980,7 @@ disable_irq(AU1100_SD_IRQ); for(i = 0; i < AU1XMMC_CONTROLLER_COUNT; i++) {+ int err = 0; struct mmc_host *mmc = mmc_alloc_host(sizeof(struct au1xmmc_host), dev); struct au1xmmc_host *host = 0; @@ -930,9 +989,17 @@ au1xmmc_hosts[i] = 0; continue; }-+ + err = sdio_host_alloc(mmc);+ if (err != 0) {+ mmc_free_host(mmc);+ printk(DRIVER_NAME " ERROR: Failed to initialize SDIO host %d\n", i);+ au1xmmc_hosts[i] = 0;+ continue;+ }+ mmc->ops = &au1xmmc_ops;- + mmc->f_min = 450000; mmc->f_max = 24000000; @@ -975,6 +1042,10 @@ if (dma != 0) au1xmmc_init_dma(host); + /* Since au1xmmc_reset_controller() enables the SDIO + interrupt, it has to be called after sdio_host_alloc() that + prepares the SDIO ISR.+ */ au1xmmc_reset_controller(host); mmc_add_host(mmc);@@ -992,31 +1063,33 @@ } static int au1xmmc_remove(struct device *dev) {- int i;-+ disable_irq(AU1100_SD_IRQ);- + for(i = 0; i < AU1XMMC_CONTROLLER_COUNT; i++) { struct au1xmmc_host *host = au1xmmc_hosts[i]; if (!host) continue;-- tasklet_kill(&host->data_task);- tasklet_kill(&host->finish_task);-+ del_timer_sync(&host->timer);+ mmc_remove_host(host->mmc);+ au1xmmc_set_power(host, 0);+ au_writel(0x0, HOST_ENABLE(host));+ au_sync(); - mmc_remove_host(host->mmc);- au1xxx_dbdma_chan_free(host->tx_chan); au1xxx_dbdma_chan_free(host->rx_chan);- - au_writel(0x0, HOST_ENABLE(host));- au_sync(); - } -+ + tasklet_kill(&host->finish_task);+ tasklet_kill(&host->data_task);+ + sdio_host_free(host->mmc);+ mmc_free_host(host->mmc);+ }+ free_irq(AU1100_SD_IRQ, 0);+ return 0; } @@ -1036,7 +1109,7 @@ int retval = -1; unsigned int addr = 0; - DEBUG("Entering au1xmmc_pm_callback to service request type: %d\n", request);+ DBG("Entering au1xmmc_pm_callback to service request type: %d\n", request); struct au1xmmc_host *host=au1xmmc_hosts[0]; diff -Naur -x '.*' -x '*~' -x '*.o' -x '*.ko' -x '*.mod.c' -x '*.cmd' linux26-cvs.BOM/drivers/mmc/Kconfig linux26-cvs.sdio/drivers/mmc/Kconfig--- linux26-cvs.BOM/drivers/mmc/Kconfig 2005-10-20 18:17:10.000000000 +0200+++ linux26-cvs.sdio/drivers/mmc/Kconfig 2005-10-18 13:00:40.000000000 +0200@@ -2,7 +2,7 @@ # MMC subsystem configuration # -menu "MMC/SD Card support"+menu "MMC/SD/SDIO Card support" config MMC tristate "MMC support"@@ -19,6 +19,14 @@ This is an option for use by developers; most people should say N here. This enables MMC core and driver debugging. +config SDIO_EXT+ bool "Use external SDIO functions"+ depends on MMC != n+ help+ This option enables the usage of external SDIO function. This is + useful if there are SDIO features of builtin functions that are not+ fully supported.+ config MMC_BLOCK tristate "MMC block device driver" depends on MMC@@ -81,7 +89,7 @@ in the iPAQ hx4700 and others. config MMC_AU1X- tristate "Alchemy AU1XX0 MMC Card Interface support"+ tristate "Alchemy AU1XX0 MMC/SD/SDIO Host Controller support" depends on SOC_AU1X00 && MMC help This selects the AMD Alchemy(R) Multimedia card interface.diff -Naur -x '.*' -x '*~' -x '*.o' -x '*.ko' -x '*.mod.c' -x '*.cmd' linux26-cvs.BOM/drivers/mmc/Makefile linux26-cvs.sdio/drivers/mmc/Makefile--- linux26-cvs.BOM/drivers/mmc/Makefile 2005-10-20 18:17:10.000000000 +0200+++ linux26-cvs.sdio/drivers/mmc/Makefile 2005-10-18 17:42:46.000000000 +0200@@ -5,7 +5,7 @@ # # Core #-obj-$(CONFIG_MMC) += mmc_core.o+obj-$(CONFIG_MMC) += mmc_core.o sdio_core.o # # Media drivers@@ -24,3 +24,4 @@ obj-$(CONFIG_MMC_AU1X) += au1xmmc.o mmc_core-y := mmc.o mmc_queue.o mmc_sysfs.o+sdio_core-y := sdio.o sdiobus.odiff -Naur -x '.*' -x '*~' -x '*.o' -x '*.ko' -x '*.mod.c' -x '*.cmd' linux26-cvs.BOM/drivers/mmc/mmc.c linux26-cvs.sdio/drivers/mmc/mmc.c--- linux26-cvs.BOM/drivers/mmc/mmc.c 2005-10-20 18:17:10.000000000 +0200+++ linux26-cvs.sdio/drivers/mmc/mmc.c 2005-10-20 18:01:40.000000000 +0200@@ -5,6 +5,9 @@ * * SD support (c) 2004 Ian Molton. *+ * SDIO support: Copyright 2005 ADVANCED MICRO DEVICES, INC. All Rights Reserved.+ * by Robert Richter+ * * 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.@@ -27,16 +30,15 @@ #include <linux/mmc/host.h> #include <linux/mmc/protocol.h> +#include "sdio.h" #include "mmc.h" #ifdef CONFIG_MMC_DEBUG-#define DBG(x...) printk(KERN_DEBUG x)+#define DBG(fmt, x...) printk("%s:%4d: " fmt, "MMC", __LINE__, ##x) #else #define DBG(x...) do { } while (0) #endif -#define CMD_RETRIES 3- /* * OCR Bit positions to 10s of Vdd mV. */@@ -65,6 +67,72 @@ 35, 40, 45, 50, 55, 60, 70, 80, }; +/* SDIO functions */++static inline+struct sd_card* sdio_card_alloc(struct mmc_host* host) {+ struct sd_card* card = NULL;+ + if (host->sdio_host != NULL)+ card = host->sdio_host->ops->sdio_card_alloc();+ + return card;+}++static inline+void sdio_card_free(struct mmc_host* host, struct sd_card * card) {+ if (host->sdio_host != NULL)+ host->sdio_host->ops->sdio_card_free(card);+}++static inline +int sdio_card_register (struct mmc_host* host, struct sd_card *card) {+ int err = MMC_ERR_NONE;+ + if (host->sdio_host != NULL)+ err = host->sdio_host->ops->sdio_card_register(card);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -