From: Jai Dhar <[EMAIL PROTECTED]>
Works with 1.0 of nios_mmc core.
Signed-off-by: Jai Dhar <[EMAIL PROTECTED]>
Signed-off-by: Thomas Chou <[EMAIL PROTECTED]>
---
linux-2.6.x/arch/nios2nommu/drivers/Kconfig | 6 +
linux-2.6.x/arch/nios2nommu/kernel/setup.c | 29 ++
linux-2.6.x/drivers/mmc/host/Kconfig | 18 +
linux-2.6.x/drivers/mmc/host/Makefile | 1 +
linux-2.6.x/drivers/mmc/host/nios_mmc.c | 480 ++++++++++++++++++++++
linux-2.6.x/drivers/mmc/host/nios_mmc.h | 68 +++
linux-2.6.x/include/asm-nios2nommu/scatterlist.h | 3 +
7 files changed, 605 insertions(+), 0 deletions(-)
create mode 100755 linux-2.6.x/drivers/mmc/host/nios_mmc.c
create mode 100755 linux-2.6.x/drivers/mmc/host/nios_mmc.h
diff --git a/linux-2.6.x/arch/nios2nommu/drivers/Kconfig
b/linux-2.6.x/arch/nios2nommu/drivers/Kconfig
index 2fde3a8..68ac0b8 100644
--- a/linux-2.6.x/arch/nios2nommu/drivers/Kconfig
+++ b/linux-2.6.x/arch/nios2nommu/drivers/Kconfig
@@ -43,3 +43,9 @@ config NIOS_SPI
help
This driver supports the Nios softcore SPI device.
+config NIOS_SD_HOST
+ tristate "NIOS SD/SDIO/MMC Host"
+ depends on NIOS || NIOS2
+ help
+ This driver supports the FPS-Tech SD/SDIO/MMC Host IP
+
diff --git a/linux-2.6.x/arch/nios2nommu/kernel/setup.c
b/linux-2.6.x/arch/nios2nommu/kernel/setup.c
index d22556c..7fc61d3 100644
--- a/linux-2.6.x/arch/nios2nommu/kernel/setup.c
+++ b/linux-2.6.x/arch/nios2nommu/kernel/setup.c
@@ -682,3 +682,32 @@ static int __init i2c_gpio_device_init(void)
arch_initcall(i2c_gpio_device_init);
#endif // CONFIG_I2C_NIOS2_GPIO
+
+
+#if defined(CONFIG_NIOS_SD_HOST) && defined(na_sdio_host_inst)
+static struct resource nios_mmc_resources[] = {
+ [0] = {
+ .start = na_sdio_host_inst,
+ .end = na_sdio_host_inst + (16*4-1),
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = na_sdio_host_inst_irq,
+ .end = na_sdio_host_inst_irq,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+static struct platform_device nios_mmc_device = {
+ .name = "nios_mmc",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(nios_mmc_resources),
+ .resource = nios_mmc_resources,
+};
+
+static int __init nios_mmc_device_init(void)
+{
+ return platform_device_register(&nios_mmc_device);
+}
+arch_initcall(nios_mmc_device_init);
+#endif // CONFIG_NIOS_SD_HOST
+
diff --git a/linux-2.6.x/drivers/mmc/host/Kconfig
b/linux-2.6.x/drivers/mmc/host/Kconfig
index 5fef678..c041d5d 100644
--- a/linux-2.6.x/drivers/mmc/host/Kconfig
+++ b/linux-2.6.x/drivers/mmc/host/Kconfig
@@ -130,3 +130,21 @@ config MMC_SPI
If unsure, or if your system has no SPI master driver, say N.
+config MMC_NIOS
+ tristate "NIOS SD/SDIO/MMC Host"
+ depends on NIOS_SD_HOST
+ help
+ Device driver for the FPS-Tech SD/SDIO/MMC Host for Altera NIOS
systems
+
+config NIOS_MMC_NOBLK_PREFETCH
+ tristate "Disable Block pre-fetching"
+ depends on MMC_NIOS
+ help
+ The NIOS SD Host will pre-fetch a complete block from memory
+ before writing on the SD interface. The pre-fetch is performed
+ for systems that have high memory access times (eg: DDR-based
systems).
+ For configurations with low-latency memory access (eg: SSRAM),
pre-fetching
+ shouldn't be required. Disable Block pre-fetching only if you
have a low-latency
+ memory system.
+
+ If unsure, say N here
diff --git a/linux-2.6.x/drivers/mmc/host/Makefile
b/linux-2.6.x/drivers/mmc/host/Makefile
index 3877c87..673384f 100644
--- a/linux-2.6.x/drivers/mmc/host/Makefile
+++ b/linux-2.6.x/drivers/mmc/host/Makefile
@@ -17,4 +17,5 @@ obj-$(CONFIG_MMC_OMAP) += omap.o
obj-$(CONFIG_MMC_AT91) += at91_mci.o
obj-$(CONFIG_MMC_TIFM_SD) += tifm_sd.o
obj-$(CONFIG_MMC_SPI) += mmc_spi.o
+obj-$(CONFIG_MMC_NIOS) += nios_mmc.o
diff --git a/linux-2.6.x/drivers/mmc/host/nios_mmc.c
b/linux-2.6.x/drivers/mmc/host/nios_mmc.c
new file mode 100755
index 0000000..ab519c5
--- /dev/null
+++ b/linux-2.6.x/drivers/mmc/host/nios_mmc.c
@@ -0,0 +1,480 @@
+/*
+ * linux/drivers/mmc/nios_mmc.c - FPS-Tech NIOS_MMC Driver
+ *
+ * Copyright (C) 2008 Jai Dhar / FPS-Tech, All Rights Reserved.
+ * Credits: This driver is partially derived from pxamci.c
+ *
+ * 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.
+ *
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/mmc/host.h>
+#include <linux/pagemap.h>
+
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
+
+#include "nios_mmc.h"
+#define DRIVER_NAME "nios_mmc"
+#define debug_level 1
+#define NR_SG 1
+
+#if defined(CONFIG_MMC_DEBUG)
+#define MMC_DEBUG(l,x...) {\
+ if (l <= debug_level)\
+ {\
+ printk("%s(): ",__func__); printk(x);\
+ }\
+}
+#else
+#define MMC_DEBUG(l,x...) {}
+#endif //CONFIG_MMC_DEBUG
+
+#define MMC_CRIT_ERR(x...) {\
+ printk("Crit. error in %s(): %s. Halting\n",__func__,x);\
+ while(1);\
+}
+
+static void nios_mmc_start_cmd(NIOS_MMC_HOST *host, struct mmc_command *cmd);
+static void nios_mmc_end_request(struct mmc_host *mmc, struct mmc_request
*mrq);
+/***************************** Start of main functions
********************************/
+
+void nios_mmc_end_cmd(NIOS_MMC_HOST *host)
+{
+ unsigned int tmp,ret;
+ struct mmc_command *cmd = host->cmd;
+ struct mmc_data *data = cmd->data;
+ struct mmc_command *stop = data->stop;
+
+ /* assign stop only if data is assigned */
+ if (data) stop = data->stop;
+ else stop = NULL;
+ /* Check MRQ first */
+ if (cmd == NULL)
+ {
+ MMC_CRIT_ERR("CMD is null when it shouldn't be!");
+ while(1);
+ }
+ tmp = readl(host->base + NIOS_MMC_REG_CTLSTAT);
+ //Interrupt flags will be cleared in ISR routine, so we don't have to
touch them */
+ if (tmp & NIOS_MMC_CTLSTAT_TIMEOUTERR_IF)
+ {
+ MMC_DEBUG(1,"Timeout error\n");
+ ret = MMC_ERR_TIMEOUT;
+ }
+ else if (tmp & NIOS_MMC_CTLSTAT_FRMERR_IF)
+ {
+ MMC_DEBUG(1,"Framing error\n");
+ ret = MMC_ERR_TIMEOUT;
+ }
+ else if (tmp & NIOS_MMC_CTLSTAT_CRCERR_IF)
+ {
+ MMC_DEBUG(1,"CRC Error\n");
+ ret = MMC_ERR_BADCRC;
+ }
+ else if (tmp & NIOS_MMC_CTLSTAT_FIFO_UNDERRUN_IF)
+ {
+ MMC_DEBUG(1,"FIFO Underrun error\n");
+ ret = MMC_ERR_BADCRC;
+ }
+ else if (tmp & NIOS_MMC_CTLSTAT_FIFO_OVERRUN_IF)
+ {
+ MMC_DEBUG(1,"FIFO Overrun error\n");
+ ret = MMC_ERR_BADCRC;
+ }
+ else
+ {
+ /* Response is good! */
+ ret = MMC_ERR_NONE;
+ }
+ if (ret != MMC_ERR_NONE)
+ {
+ MMC_DEBUG(1,"Error executing CMD%d\n",cmd->opcode);
+ MMC_DEBUG(2,"Response argument:
0x%X\n",readl(host->base+NIOS_MMC_REG_CMD_ARG0));
+ }
+ /* Load response into command structure */
+ cmd->error = ret;
+ if (mmc_resp_type(cmd) == MMC_RSP_R2)
+ {
+ cmd->resp[0] = readl (host->base + NIOS_MMC_REG_CMD_ARG3);
+ cmd->resp[1] = readl (host->base + NIOS_MMC_REG_CMD_ARG2);
+ cmd->resp[2] = readl (host->base + NIOS_MMC_REG_CMD_ARG1);
+ cmd->resp[3] = readl (host->base + NIOS_MMC_REG_CMD_ARG0);
+ }
+ else cmd->resp[0] = readl (host->base + NIOS_MMC_REG_CMD_ARG0);
+ /* Check if this was a data transaction */
+ if (data)
+ {
+ if (cmd->error == MMC_ERR_NONE)
+ data->bytes_xfered = data->blksz*data->blocks;
+ else data->bytes_xfered = 0;
+ }
+ if (stop)
+ {
+ /* Schedule the stop command */
+ /* We will need to reassign the pointer in the structure since
we are
+ * switching commands now */
+ host->cmd = stop;
+ nios_mmc_start_cmd(host, stop);
+ }
+ else
+ {
+ /* No other commands needed, finish off transaction */
+ nios_mmc_end_request(host->mmc, cmd->mrq);
+ }
+}
+/* nios_mmc_execute_cmd(): Key function that interacts with MMC Host to carry
out command */
+void nios_mmc_execute_cmd(NIOS_MMC_HOST *host, unsigned char cmd, unsigned int
arg_in,
+ unsigned char resp_type, unsigned char nocrc,
+ unsigned int bytes, unsigned int blocks, unsigned char rwn,
unsigned int buf)
+{
+ unsigned int xfer_ctl = 0;
+ u_char cmdidx;
+
+ /* Do a sanity check that the core isn't busy... why should it be since
we haven't started a cmd?? */
+ if (readl(host->base + NIOS_MMC_REG_CTLSTAT) & NIOS_MMC_CTLSTAT_BUSY)
+ {
+ MMC_CRIT_ERR("Core is busy when it shouldn't be!");
+ }
+ xfer_ctl = (cmd & 0x3F) << NIOS_MMC_XFER_CTL_CMD_IDX_SHIFT;
+ writel(arg_in, host->base + NIOS_MMC_REG_CMD_ARG0);
+ xfer_ctl |= (resp_type & 0x3) << NIOS_MMC_XFER_CTL_RESP_CODE_SHIFT;
+ if (nocrc) xfer_ctl |= NIOS_MMC_XFER_CTL_RESP_NOCRC;
+ if (rwn) xfer_ctl |= NIOS_MMC_XFER_CTL_DAT_RWn;
+ xfer_ctl |= (bytes & 0x3FF) << NIOS_MMC_XFER_CTL_BYTE_COUNT_SHIFT;
+ xfer_ctl |= (blocks & 0x3FF) << NIOS_MMC_XFER_CTL_BLOCK_COUNT_SHIFT;
+ xfer_ctl |= NIOS_MMC_XFER_CTL_XFER_START;
+ if (host->dat_width) xfer_ctl |= NIOS_MMC_XFER_CTL_DAT_WIDTH;
+ cmdidx = (xfer_ctl >> NIOS_MMC_XFER_CTL_CMD_IDX_SHIFT)&0x3F;
+ /* Setup DMA base */
+ writel(buf | (1<<31), host->base + NIOS_MMC_REG_DMA_BASE);
+ MMC_DEBUG(2,"XFER_CTL: 0x%X (CMD%d), DMA_BASE(%c): 0x%X, ARG_IN:
0x%X\n",
+ xfer_ctl,cmdidx,
+ (xfer_ctl&NIOS_MMC_XFER_CTL_DAT_RWn)?'R':'W',buf,
arg_in);
+ /* Execute command */
+ writel(xfer_ctl, host->base + NIOS_MMC_REG_XFER_CTL);
+}
+static irqreturn_t nios_mmc_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+ NIOS_MMC_HOST *host = dev_id;
+ unsigned int ret;
+
+ ret = readl(host->base + NIOS_MMC_REG_CTLSTAT);
+ MMC_DEBUG(2,"IRQ, ctlstat: 0x%X\n",ret);
+
+ if (ret & NIOS_MMC_CTLSTAT_CD_IF)
+ {
+ /* Card-detect interrupt */
+ if (ret & NIOS_MMC_CTLSTAT_CD)
+ {
+ MMC_DEBUG(1,"HOT-PLUG: Card inserted\n");
+ }
+ else
+ {
+ MMC_DEBUG(1,"HOT-PLUG: Card removed\n");
+ }
+ mmc_detect_change(host->mmc, 100);
+ }
+ if (ret & NIOS_MMC_CTLSTAT_XFER_IF)
+ {
+ MMC_DEBUG(3,"Detected XFER Interrupt\n");
+ /* Transfer has completed */
+ nios_mmc_end_cmd(host);
+ }
+
+ /* Clear the interrupt after everyone has had a chance to look at it! */
+ writel(ret, host->base + NIOS_MMC_REG_CTLSTAT);
+ return IRQ_HANDLED;
+}
+/* Function to start the CMD process */
+static void nios_mmc_start_cmd(NIOS_MMC_HOST *host, struct mmc_command *cmd)
+{
+ unsigned char resp_type = 0, nocrc = 0, rwn = 0;
+ struct mmc_data *data = cmd->data;
+ struct scatterlist *sg;
+ unsigned int current_address,bytes=0,blocks=0;
+
+ /* Do a sanity check that we are being passed the same CMD that is in
host struct */
+ if (host->cmd != cmd)
+ {
+ MMC_CRIT_ERR("Cmd doesn't match what is in structure");
+ }
+
+ MMC_DEBUG(2,"Opcode: %d Arg: 0x%X ",cmd->opcode,cmd->arg);
+ switch (mmc_resp_type(cmd))
+ {
+ case MMC_RSP_R3:
+ nocrc = 1;
+ case MMC_RSP_R1:
+ case MMC_RSP_R1B:
+ //case MMC_RSP_R6:
+ resp_type = 1;
+ break;
+ case MMC_RSP_R2:
+ resp_type = 2;
+ nocrc = 1;
+ break;
+ case MMC_RSP_NONE:
+ resp_type = 0;
+ break;
+ default:
+ MMC_CRIT_ERR("Unhandled MMC Response type!");
+ break;
+ }
+
+ sg = data->sg;
+ current_address = sg_address(sg);
+ cmd->error = MMC_ERR_NONE;
+ if (data)
+ {
+ if (data->sg_len > 1)
+ {
+ MMC_CRIT_ERR("sg_len is > 1!");
+ }
+ MMC_DEBUG(3,"Block size: %d Blocks: %d sg_len: %d\n",
+ data->blksz,data->blocks,data->sg_len);
+ if (data->stop) MMC_DEBUG(2,"Stop command present\n");
+ /* Setup byte count */
+ bytes = data->blksz;
+ blocks = data->blocks-1;
+
+ if (data->flags & MMC_DATA_READ) rwn = 1;
+ else rwn = 0;
+
+ }
+ nios_mmc_execute_cmd(host, cmd->opcode, cmd->arg,
+ resp_type, nocrc, bytes, blocks, rwn, current_address);
+
+}
+/****************** Driver-level interface *****************/
+
+/* This function is called from the driver level above */
+/* nios_mmc_request() initiates the MMC request as setup in the mrq structure
*/
+static void nios_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+ NIOS_MMC_HOST *host = mmc_priv(mmc);
+
+ if (host->cmd != NULL)
+ {
+ MMC_DEBUG(1,"HOST_CMD Not null!\n");
+ }
+ host->cmd = mrq->cmd;
+ MMC_DEBUG(3,"Start req\n");
+ nios_mmc_start_cmd(host, host->cmd);
+ return;
+}
+/* Function to cleanup previous call */
+static void nios_mmc_end_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+ NIOS_MMC_HOST *host = mmc_priv(mmc);
+ host->cmd = NULL;
+ mmc_request_done(host->mmc, mrq);
+ return;
+}
+static int nios_mmc_get_ro(struct mmc_host *mmc)
+{
+ MMC_DEBUG(3,"Get RO\n");
+ return 0;
+}
+static void nios_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+ NIOS_MMC_HOST *host = mmc_priv(mmc);
+ int div;
+
+ if (ios->clock)
+ {
+ /* FIXME: Look at divider calculation! */
+ MMC_DEBUG(3,"Requesting clock: %d\n",ios->clock);
+ div = (nasys_clock_freq / (2*ios->clock))-1;
+ writel((div & 0xFFFF) | NIOS_MMC_CLK_CTL_CLK_EN,
+ host->base + NIOS_MMC_REG_CLK_CTL);
+ }
+ else
+ {
+ /* Stop the clock */
+ MMC_DEBUG(3,"Request stop clock\n");
+ writel(0, host->base + NIOS_MMC_REG_CLK_CTL);
+ }
+
+ if (ios->bus_width)
+ host->dat_width = 1;
+ else
+ host->dat_width = 0;
+
+ return;
+}
+
+static struct mmc_host_ops nios_mmc_ops = {
+ .request = nios_mmc_request,
+ .get_ro = nios_mmc_get_ro,
+ .set_ios = nios_mmc_set_ios,
+};
+
+static int nios_mmc_probe(struct platform_device *pdev)
+{
+ struct mmc_host *mmc;
+ struct resource *r;
+ NIOS_MMC_HOST *host = NULL;
+ int ret, irq;
+
+ MMC_DEBUG(3,"Starting NIOS_MMC Probe\n");
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ irq = platform_get_irq(pdev, 0);
+ if (!r || irq < 0)
+ return -ENXIO;
+ r = request_mem_region(r->start, 16*4, DRIVER_NAME);
+ if (!r)
+ {
+ MMC_DEBUG(3,"Error allocating mem. region\n");
+ return -EBUSY;
+ }
+ mmc = mmc_alloc_host(sizeof(NIOS_MMC_HOST), &pdev->dev);
+ if (!mmc)
+ {
+ MMC_DEBUG(3,"Error allocating MMC Host\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+ mmc->ops = &nios_mmc_ops;
+ MMC_DEBUG(3,"Done initial probe\n");
+ mmc->f_max = nasys_clock_freq/4;
+ mmc->f_min = nasys_clock_freq/(1<<16);
+ mmc->max_phys_segs = NR_SG;
+ mmc->max_seg_size = 256;
+
+ host = mmc_priv(mmc);
+ host->mmc = mmc;
+ host->dma = -1;
+ host->dat_width = 0;
+ host->cmd = NULL;
+ mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
+
+ spin_lock_init(&host->lock);
+ host->res = r;
+ host->irq = irq;
+ host->base = ioremap(r->start, 16*4);
+ if (!host->base)
+ {
+ ret = -ENOMEM;
+ MMC_DEBUG(3,"Error in IO Remap\n");
+ goto out;
+ }
+ MMC_DEBUG(3,"Setup host with Base: 0x%X IRQ: %d\n",(unsigned int)
host->base, host->irq);
+
+ /* Check that SD/MMC Core is present */
+ ret = 0;
+ ret = readl(host->base + NIOS_MMC_REG_VERSION_INFO);
+ if ((ret & 0xFFFF) != 0xBEEF)
+ {
+ MMC_DEBUG(3,"Core not present\n");
+ ret = -ENXIO;
+ goto out;
+ }
+ printk("NIOS_MMC: FPS-Tech SD/SDIO/MMC Host Core, version %d.%d\n",ret
>> 24, (ret >> 16) & 0xff);
+ printk("NIOS_MMC: F_MAX: %d Hz, F_MIN: %d Hz\n",mmc->f_max,mmc->f_min);
+ ret = readl(host->base + NIOS_MMC_REG_CTLSTAT);
+ printk("NIOS_MMC: Host built with %s DAT driver\n",(ret &
NIOS_MMC_CTLSTAT_HOST_4BIT)?"4-bit":"1-bit");
+ mmc->caps = (ret&NIOS_MMC_CTLSTAT_HOST_4BIT)?MMC_CAP_4_BIT_DATA:0;
+
+ /* Execute soft-reset on core */
+ writel(NIOS_MMC_CTLSTAT_SOFT_RST,host->base + NIOS_MMC_REG_CTLSTAT);
+
+ /* Enable interrupts on CD and XFER_IF only */
+ /* Use BLK_PREFETCH for linux unless disabled */
+ /* This section sets up CTLSTAT for the rest of the driver.
+ * Make sure all further writes to CTLSTAT are using bitwise OR!!! */
+ ret = NIOS_MMC_CTLSTAT_CD_IE | NIOS_MMC_CTLSTAT_XFER_IE;
+#if !defined(CONFIG_NIOS_MMC_NOBLK_PREFETCH)
+ ret |= NIOS_MMC_CTLSTAT_BLK_PREFETCH;
+#endif
+ /* Execute write to CTLSTAT here */
+ writel(ret, host->base + NIOS_MMC_REG_CTLSTAT);
+ if (ret & NIOS_MMC_CTLSTAT_BLK_PREFETCH) {
+ printk("NIOS_MMC: Using block-prefetching\n");
+ }
+ else {
+ printk("NIOS_MMC: Block-prefetching disabled!\n");
+ }
+
+
+ ret = request_irq(host->irq, nios_mmc_irq, 0, DRIVER_NAME, (void *)
host);
+ if (ret)
+ {
+ MMC_DEBUG(3,"Error allocating interrupt\n");
+ goto out;
+ }
+ platform_set_drvdata(pdev, mmc);
+ mmc_add_host(mmc);
+ MMC_DEBUG(3,"Completed full probe successfully\n");
+ return 0;
+
+out:
+ if (host)
+ {
+ }
+ if (mmc) mmc_free_host(mmc);
+ release_resource(r);
+ return ret;
+}
+
+static int nios_mmc_remove(struct platform_device *pdev)
+{
+ struct mmc_host *mmc = platform_get_drvdata(pdev);
+
+ if (mmc) {
+ NIOS_MMC_HOST *host = mmc_priv(mmc);
+
+ mmc_remove_host(mmc);
+ free_irq(host->irq, (void *) host);
+ iounmap(host->base);
+ release_resource(host->res);
+ mmc_free_host(mmc);
+ }
+ return 0;
+}
+static int nios_mmc_suspend(struct platform_device *dev, pm_message_t state)
+{
+ return 0;
+}
+static int nios_mmc_resume(struct platform_device *dev)
+{
+ return 0;
+}
+
+static struct platform_driver nios_mmc_driver = {
+ .probe = nios_mmc_probe,
+ .remove = nios_mmc_remove,
+ .suspend = nios_mmc_suspend,
+ .resume = nios_mmc_resume,
+ .driver = {
+ .name = DRIVER_NAME,
+ },
+};
+
+static int __init nios_mmc_init(void)
+{
+ int ret;
+ ret = platform_driver_register(&nios_mmc_driver);
+ return ret;
+}
+
+static void __exit nios_mmc_exit(void)
+{
+ platform_driver_unregister(&nios_mmc_driver);
+}
+
+module_init(nios_mmc_init);
+module_exit(nios_mmc_exit);
+
+MODULE_DESCRIPTION("NIOS MMC Host Driver");
+MODULE_LICENSE("GPL");
diff --git a/linux-2.6.x/drivers/mmc/host/nios_mmc.h
b/linux-2.6.x/drivers/mmc/host/nios_mmc.h
new file mode 100755
index 0000000..d6100ad
--- /dev/null
+++ b/linux-2.6.x/drivers/mmc/host/nios_mmc.h
@@ -0,0 +1,68 @@
+#ifndef SDIO_HOST_H_
+#define SDIO_HOST_H_
+
+/******* SDIO Core defines *******/
+typedef volatile struct
+{
+ void __iomem *base;
+ struct mmc_host *mmc;
+ spinlock_t lock;
+ struct resource *res;
+ int irq;
+ int dma;
+ unsigned char dat_width; /* 1=4-bit mode, 0=1-bit */
+
+ /* This should point to current cmd we are processing */
+ struct mmc_command *cmd;
+} NIOS_MMC_HOST;
+
+#define NIOS_MMC_REG_CTLSTAT 0*4
+#define NIOS_MMC_REG_CLK_CTL 1*4
+#define NIOS_MMC_REG_CMD_ARG0 2*4
+#define NIOS_MMC_REG_CMD_ARG1 3*4
+#define NIOS_MMC_REG_CMD_ARG2 4*4
+#define NIOS_MMC_REG_CMD_ARG3 5*4
+#define NIOS_MMC_REG_DMA_BASE 6*4
+#define NIOS_MMC_REG_XFER_CTL 7*4
+#define NIOS_MMC_REG_VERSION_INFO 15*4
+
+#define NIOS_MMC_CTLSTAT_BUSY (1<<0)
+#define NIOS_MMC_CTLSTAT_CD (1<<1)
+#define NIOS_MMC_CTLSTAT_CD_IF (1<<3)
+#define NIOS_MMC_CTLSTAT_DEV_IF (1<<4)
+#define NIOS_MMC_CTLSTAT_XFER_IF (1<<5)
+#define NIOS_MMC_CTLSTAT_FRMERR_IF (1<<6)
+#define NIOS_MMC_CTLSTAT_CRCERR_IF (1<<7)
+#define NIOS_MMC_CTLSTAT_TIMEOUTERR_IF (1<<8)
+#define NIOS_MMC_CTLSTAT_FIFO_OVERRUN_IF (1<<9)
+#define NIOS_MMC_CTLSTAT_FIFO_UNDERRUN_IF (1<<10)
+#define NIOS_MMC_CTLSTAT_HOST_4BIT (1<<14)
+#define NIOS_MMC_CTLSTAT_CD_IE (1<<16)
+#define NIOS_MMC_CTLSTAT_XFER_IE (1<<18)
+#define NIOS_MMC_CTLSTAT_BLK_PREFETCH (1<<20)
+#define NIOS_MMC_CTLSTAT_SOFT_RST (1<<31)
+
+#define NIOS_MMC_CLK_CTL_CLK_EN (1<<31)
+#define NIOS_MMC_CLK_CTL_DLY_SHIFT 29
+#define NIOS_MMC_CLK_CTL_INV (1<<28)
+
+#define NIOS_MMC_XFER_CTL_XFER_START (1<<0)
+#define NIOS_MMC_XFER_CTL_CMD_IDX_SHIFT (1)
+#define NIOS_MMC_XFER_CTL_DAT_WIDTH (1<<7)
+#define NIOS_MMC_XFER_CTL_RESP_CODE_SHIFT (8)
+#define NIOS_MMC_XFER_CTL_DAT_RWn (1<<10)
+#define NIOS_MMC_XFER_CTL_RESP_NOCRC (1<<11)
+#define NIOS_MMC_XFER_CTL_BYTE_COUNT_SHIFT (12)
+#define NIOS_MMC_XFER_CTL_BLOCK_COUNT_SHIFT (22)
+
+/********** Function prototypes ************/
+int nios_mmc_host_cmd_resp(NIOS_MMC_HOST *nios_mmc_host, unsigned char cmd,
unsigned int arg,
+unsigned int *arg_out);
+int nios_mmc_host_init(NIOS_MMC_HOST *nios_mmc_host);
+int nios_mmc_read_extended(NIOS_MMC_HOST *nios_mmc_host, unsigned int addr,
unsigned char cmd, unsigned int arg,
+int bytes, int blocks, unsigned char dat_width, unsigned int *arg_out);
+void nios_mmc_host_set_clk_div(NIOS_MMC_HOST *nios_mmc_host, int div);
+int nios_mmc_write_extended(NIOS_MMC_HOST *nios_mmc_host, unsigned int addr,
unsigned char cmd, unsigned int arg,
+int bytes, int blocks, unsigned char dat_width, unsigned int *arg_out);
+
+#endif /*SDIO_HOST_H_*/
diff --git a/linux-2.6.x/include/asm-nios2nommu/scatterlist.h
b/linux-2.6.x/include/asm-nios2nommu/scatterlist.h
index 911c474..248e165 100644
--- a/linux-2.6.x/include/asm-nios2nommu/scatterlist.h
+++ b/linux-2.6.x/include/asm-nios2nommu/scatterlist.h
@@ -24,5 +24,8 @@ struct scatterlist {
#define sg_dma_len(sg) ((sg)->length)
#define ISA_DMA_THRESHOLD (0xffffffff)
+#define sg_address(sg) (page_to_virt((sg)->page) + (sg)->offset)
+#define sg_dma_address(sg) ((sg)->dma_address)
+#define sg_dma_len(sg) ((sg)->length)
#endif /* __ASM_SCATTERLIST_H */
--
1.5.3.3
_______________________________________________
uClinux-dev mailing list
[email protected]
http://mailman.uclinux.org/mailman/listinfo/uclinux-dev
This message was resent by [email protected]
To unsubscribe see:
http://mailman.uclinux.org/mailman/options/uclinux-dev