📄 mmc.patch
字号:
+}++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) {+ + u32 rxchan, txchan;+ + 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+ */+ + int memid = au1xxx_ddma_add_device(&au1xmmc_mem_dbdev);+ + txchan = au1xxx_dbdma_chan_alloc(memid, txid, + au1xmmc_dma_callback, (void *) host);++ rxchan = au1xxx_dbdma_chan_alloc(rxid, memid, + au1xmmc_dma_callback, (void *) host);++ au1xxx_dbdma_set_devwidth(txchan, 8);+ au1xxx_dbdma_set_devwidth(rxchan, 8);++ au1xxx_dbdma_ring_alloc(txchan, AU1XMMC_DESCRIPTOR_COUNT);+ au1xxx_dbdma_ring_alloc(rxchan, AU1XMMC_DESCRIPTOR_COUNT);++ host->tx_chan = txchan;+ host->rx_chan = rxchan;+}++struct mmc_host_ops au1xmmc_ops = {+ .request = au1xmmc_request,+ .set_ios = au1xmmc_set_ios,+};++static int au1xmmc_probe(struct device *dev) {++ int i, ret = 0;++ /* THe interrupt is shared among all controllers */+ ret = request_irq(AU1100_SD_IRQ, au1xmmc_irq, SA_INTERRUPT, "MMC", 0);+ + if (ret) {+ printk(DRIVER_NAME " ERROR: Couldn't get the interrupt %d: %d\n", AU1100_SD_IRQ, ret);+ return -ENXIO;+ }++ disable_irq(AU1100_SD_IRQ);++ for(i = 0; i < AU1XMMC_CONTROLLER_COUNT; i++) {+ struct mmc_host *mmc = mmc_alloc_host(sizeof(struct au1xmmc_host), dev);+ struct au1xmmc_host *host = 0;++ if (!mmc) {+ printk(DRIVER_NAME " ERROR: Unable to allocate enough memory for host %d\n", i);+ au1xmmc_hosts[i] = 0;+ continue;+ }++ mmc->ops = &au1xmmc_ops;+ + mmc->f_min = 450000;+ mmc->f_max = 24000000;++ mmc->max_seg_size = AU1XMMC_DESCRIPTOR_SIZE;+ mmc->max_phys_segs = AU1XMMC_DESCRIPTOR_COUNT; ++ mmc->ocr_avail = AU1XMMC_OCR;++ host = mmc_priv(mmc);+ host->mmc = mmc;++ host->id = i;+ host->iobase = au1xmmc_card_table[host->id].iobase;+ host->clock = 0;+ host->power_mode = MMC_POWER_OFF;+ + host->flags = au1xmmc_card_inserted(host) ? HOST_F_ACTIVE : 0;+ host->status = HOST_S_IDLE;++ init_timer(&host->timer);++ host->timer.function = au1xmmc_poll_event;+ host->timer.data = (unsigned long) host;+ host->timer.expires = jiffies + AU1XMMC_DETECT_TIMEOUT;++ tasklet_init(&host->data_task, au1xmmc_tasklet_data, + (unsigned long) host);++ tasklet_init(&host->finish_task, au1xmmc_tasklet_finish, + (unsigned long) host);++ spin_lock_init(&host->lock);++ if (dma != 0)+ au1xmmc_init_dma(host);++ au1xmmc_reset_controller(host);++ mmc_add_host(mmc);+ au1xmmc_hosts[i] = host;++ 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");+ }+ + enable_irq(AU1100_SD_IRQ);++ return 0;+}+ +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);+ au1xmmc_set_power(host, 0);+ + 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(); + } ++ free_irq(AU1100_SD_IRQ, 0);+ return 0;+}++static struct device_driver au1xmmc_driver = {+ .name = DRIVER_NAME,+ .bus = &platform_bus_type,+ .probe = au1xmmc_probe,+ .remove = au1xmmc_remove,+ .suspend = NULL,+ .resume = NULL+};++#ifdef CONFIG_PM+int au1xmmc_pm_callback(au1xxx_power_dev_t *dev, + au1xxx_request_t request, + void *data) {+ int retval = -1;+ unsigned int addr = 0;++ DEBUG("Entering au1xmmc_pm_callback to service request type: %d\n", request);+ + struct au1xmmc_host *host=au1xmmc_hosts[0];+ + if (request == AU1XXX_PM_SLEEP) {+ /* Save the SD/MMC registers */+ /* Slot 0*/+ addr = SD0_BASE;+ sleep_sd0[0] = au_readl(addr + SD_CONFIG);+ sleep_sd0[1] = au_readl(addr + SD_ENABLE);+ sleep_sd0[2] = au_readl(addr + SD_CONFIG2);+ sleep_sd0[3] = au_readl(addr + SD_BLKSIZE);+ sleep_sd0[4] = au_readl(addr + SD_STATUS);+ sleep_sd0[5] = au_readl(addr + SD_CMD);+ sleep_sd0[6] = au_readl(addr + SD_CMDARG);+ sleep_sd0[7] = au_readl(addr + SD_TIMEOUT);+ + /* Slot 1 */+#if defined (CONFIG_MIPS_PB1200)+ addr = SD1_BASE;+ sleep_sd1[0] = au_readl(addr + SD_CONFIG);+ sleep_sd1[1] = au_readl(addr + SD_ENABLE);+ sleep_sd1[2] = au_readl(addr + SD_CONFIG2);+ sleep_sd1[3] = au_readl(addr + SD_BLKSIZE);+ sleep_sd1[4] = au_readl(addr + SD_STATUS);+ sleep_sd1[5] = au_readl(addr + SD_CMD);+ sleep_sd1[6] = au_readl(addr + SD_CMDARG);+ sleep_sd1[7] = au_readl(addr + SD_TIMEOUT);+#endif+ card_inserted = au1xmmc_card_inserted(host);+ + if(card_inserted){ + mmc_suspend_host(host->mmc, NULL);+ }+ }+ else if (request == AU1XXX_PM_WAKEUP) {+ if(dev->prev_state == SLEEP_STATE)+ {+ /* Restoring MMSC/SD registers */+ /* Slot 0*/+ addr = SD0_BASE;+ au_writel(sleep_sd0[0], addr + SD_CONFIG);+ au_writel(sleep_sd0[1], addr + SD_ENABLE);+ au_writel(sleep_sd0[2], addr + SD_CONFIG2);+ au_writel(sleep_sd0[3], addr + SD_BLKSIZE);+ au_writel(sleep_sd0[4], addr + SD_STATUS);+ au_writel(sleep_sd0[5], addr + SD_CMD);+ au_writel(sleep_sd0[6], addr + SD_CMDARG);+ au_writel(sleep_sd0[7], addr + SD_TIMEOUT);+ + /* Slot 1 */+#if defined (CONFIG_MIPS_PB1200)+ addr = SD1_BASE;+ au_writel(sleep_sd1[0], addr + SD_CONFIG);+ au_writel(sleep_sd1[1], addr + SD_ENABLE);+ au_writel(sleep_sd1[2], addr + SD_CONFIG2);+ au_writel(sleep_sd1[3], addr + SD_BLKSIZE);+ au_writel(sleep_sd1[4], addr + SD_STATUS);+ au_writel(sleep_sd1[5], addr + SD_CMD);+ au_writel(sleep_sd1[6], addr + SD_CMDARG);+ au_writel(sleep_sd1[7], addr + SD_TIMEOUT);+#endif+ card_detected = au1xmmc_card_inserted(host);+ + if(card_detected !=card_inserted){+ struct mmc_request *mrq = host->mrq;+ + host->mrq=NULL; + host->flags &= HOST_F_ACTIVE; + host->dma.len = 0;+ host->dma.dir = 0;+ host->status = HOST_S_IDLE;+ bcsr->disk_leds |= (1 << 8);+ mmc_request_done(host->mmc, mrq);++ }+ mmc_resume_host(host->mmc);++ host->clock = 0;+ }+ }+ else if (request == AU1XXX_PM_GETSTATUS) {+ return dev->cur_state;+ }+ else if (request == AU1XXX_PM_ACCESS) {+ if (dev->cur_state != SLEEP_STATE)+ return retval;+ else {+ /* Restoring MMSC/SD registers */+ /* Slot 0*/+ addr = SD0_BASE;+ au_writel(sleep_sd0[0], addr + SD_CONFIG);+ au_writel(sleep_sd0[1], addr + SD_ENABLE);+ au_writel(sleep_sd0[2], addr + SD_CONFIG2);+ au_writel(sleep_sd0[3], addr + SD_BLKSIZE);+ au_writel(sleep_sd0[4], addr + SD_STATUS);+ au_writel(sleep_sd0[5], addr + SD_CMD);+ au_writel(sleep_sd0[6], addr + SD_CMDARG);+ au_writel(sleep_sd0[7], addr + SD_TIMEOUT);+ + /* Slot 1 */+#if defined (CONFIG_MIPS_PB1200)+ addr = SD1_BASE;+ au_writel(sleep_sd1[0], addr + SD_CONFIG);+ au_writel(sleep_sd1[1], addr + SD_ENABLE);+ au_writel(sleep_sd1[2], addr + SD_CONFIG2);+ au_writel(sleep_sd1[3], addr + SD_BLKSIZE);+ au_writel(sleep_sd1[4], addr + SD_STATUS);+ au_writel(sleep_sd1[5], addr + SD_CMD);+ au_writel(sleep_sd1[6], addr + SD_CMDARG);+ au_writel(sleep_sd1[7], addr + SD_TIMEOUT);+#endif + mmc_resume_host(host->mmc); + }+ }+ else if (request == AU1XXX_PM_IDLE) {+ /* do nothing */+ }+ else if (request == AU1XXX_PM_CLEANUP) {+ /* do nothing */+ }++ return retval; +}+#endif+++static int __init au1xmmc_init(void) {+#ifdef CONFIG_PM+ mmc_pm_dev = new_au1xxx_power_device("mmc", &au1xmmc_pm_callback, NULL);+ if ( mmc_pm_dev == NULL)+ printk(KERN_INFO "Unable to create a power management device entry for the au1xmmc.\n");+ else+ printk(KERN_INFO "Power management device entry for the au1xmmc loaded.\n");+#endif++ return driver_register(&au1xmmc_driver);+}++static void __exit au1xmmc_exit(void) {+ 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");+#endif+diff -Nbur linux26-cvs/drivers/mmc/au1xmmc.h linux26-cvs.PMMMC/drivers/mmc/au1xmmc.h--- linux26-cvs/drivers/mmc/au1xmmc.h 1969-12-31 18:00:00.000000000 -0600+++ linux26-cvs.PMMMC/drivers/mmc/au1xmmc.h 2005-08-16 10:58:38.000000000 -0500@@ -0,0 +1,96 @@+#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++#endifdiff -Nbur linux26-cvs/drivers/mmc/Kconfig linux26-cvs.PMMMC/drivers/mmc/Kconfig--- linux26-cvs/drivers/mmc/Kconfig 2005-08-16 12:33:40.000000000 -0500+++ linux26-cvs.PMMMC/drivers/mmc/Kconfig 2005-08-16 10:58:38.000000000 -0500@@ -60,4 +60,13 @@ If unsure, say N. +config MMC_AU1X+ tristate "Alchemy AU1XX0 MMC Card Interface support"+ depends on SOC_AU1X00 && MMC+ help+ This selects the AMD Alchemy(R) Multimedia card interface.+ iIf you have a Alchemy platform with a MMC slot, say Y or M here.++ If unsure, say N.+ endmenudiff -Nbur linux26-cvs/drivers/mmc/Makefile linux26-cvs.PMMMC/drivers/mmc/Makefile--- linux26-cvs/drivers/mmc/Makefile 2005-08-16 12:33:40.000000000 -0500+++ linux26-cvs.PMMMC/drivers/mmc/Makefile 2005-08-16 10:58:38.000000000 -0500@@ -18,5 +18,6 @@ obj-$(CONFIG_MMC_ARMMMCI) += mmci.o obj-$(CONFIG_MMC_PXA) += pxamci.o obj-$(CONFIG_MMC_WBSD) += wbsd.o+obj-$(CONFIG_MMC_AU1X) += au1xmmc.o mmc_core-y := mmc.o mmc_queue.o mmc_sysfs.o
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -