📄 jademmc1.c.svn-base
字号:
/* * linux/drivers/mmc/jademmc1.c - ARM PrimeCell MMCI PL180/1 driver * * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved. * * 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/config.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/init.h>#include <linux/ioport.h>#include <linux/device.h>#include <linux/interrupt.h>#include <linux/delay.h>#include <linux/err.h>#include <linux/highmem.h>#include <linux/mmc/host.h>#include <linux/mmc/protocol.h>#include <asm/div64.h>#include <asm/io.h>#include <asm/scatterlist.h>#include <asm/sizes.h>#include <asm/hardware/amba.h>#include <asm/hardware/clock.h>#include <asm/mach/mmc.h>#include <asm/memory.h>#include <asm/dma.h>#include <asm/mach/dma.h>#include <linux/completion.h>#include <asm/arch/platform.h>#include <linux/errno.h>#include <asm/arch/mmci.h>#include "mmci.h"#define DRIVER_NAME "MMCI-JADE"#define CONFIG_MMC_DEBUG #ifdef CONFIG_MMC_DEBUG#define DBG(host,fmt,args...) \ pr_debug("%s: %s: " fmt, mmc_hostname(host->mmc), __func__ , args)#else#define DBG(host,fmt,args...) do { } while (0)#endif#ifdef CONFIG_ARCH_X900 #define JADE_MMCI1_BASE X900_MMCI1_BASE #define PINCFG 0x38#else #define JADE_MMCI1_BASE Z228_MMCI1_BASE #define PINCFG 0x010c#endif int ch_sd;static struct ver_dma_param pa_sd;struct jademmci_host { void __iomem *base; struct mmc_request *mrq; struct mmc_command *cmd; struct mmc_data *data; struct mmc_host *mmc; struct clk *clk; unsigned int data_xfered; spinlock_t lock; unsigned int mclk; unsigned int cclk; u32 pwr; struct jademmc_platform_data *plat; struct timer_list timer; unsigned int oldstat; unsigned int sg_len; /* pio stuff */ struct scatterlist *sg_ptr; unsigned int sg_off; unsigned int size;};extern void ver_enable_dmac(void);#ifdef CONFIG_JADEMMC_PNP #define PMC_BASE_ADDR 0x20039000 #define PMC_EXTINTRMIS 0x48 #define PMC_EXTINTRRIS 0x4c #define PMC_EXTINTRCLR 0x50 #define PMC_EXTINTRMASK 0x54 #define PMC_EXTINTRCFG 0x58#endifstatic int sd_request_dma(void){ #ifdef CONFIG_ARCH_X900 ch_sd = ver_request_dma(0, "dma_sd",24,24); #else ch_sd = ver_request_dma(0, "dma_sd", 0x0f, 0x0f); #endif if(ch_sd < 0){ printk("<1> alloc sd dma error\n"); return ch_sd; }else{ printk("<1> sd dma chan: %d\n", ch_sd); } memset(&pa_sd, 0, sizeof (pa_sd)); return 0;} voidmmci_request_end(struct jademmci_host *host, struct mmc_request *mrq){ writel(0, host->base + MMCICOMMAND); host->mrq = NULL; host->cmd = NULL; if (mrq->data) mrq->data->bytes_xfered = host->data_xfered; /* * Need to drop the host lock here; mmc_request_done may call * back into the driver... */ spin_unlock(&host->lock); mmc_request_done(host->mmc, mrq); spin_lock(&host->lock);} void mmci_stop_data(struct jademmci_host *host){ writel(0, host->base + MMCIDATACTRL); writel(0, host->base + MMCIMASK1); host->data = NULL;}voidmmci_start_command(struct jademmci_host *host, struct mmc_command *cmd, u32 c){ void __iomem *base = host->base; DBG(host, "op %02x arg %08x flags %08x\n", cmd->opcode, cmd->arg, cmd->flags); if (readl(base + MMCICOMMAND) & MCI_CPSM_ENABLE) { writel(0, base + MMCICOMMAND); udelay(1); } c |= cmd->opcode | MCI_CPSM_ENABLE; switch (cmd->flags & MMC_RSP_MASK) { case MMC_RSP_NONE: default: break; case MMC_RSP_LONG: c |= MCI_CPSM_LONGRSP; case MMC_RSP_SHORT: c |= MCI_CPSM_RESPONSE; break; } if (/*interrupt*/0) c |= MCI_CPSM_INTERRUPT; host->cmd = cmd; writel(cmd->arg, base + MMCIARGUMENT); writel(c, base + MMCICOMMAND);} static void mmci_data_end(struct jademmci_host *host) { struct mmc_data *data; void __iomem *base; base=host->base; data =host->data; mmci_stop_data(host); if (data ) { if (!data->stop) { mmci_request_end(host, data->mrq); } else { mmci_start_command(host, data->stop, 0); } } writel(0,base + MMCIMASK1); writel(readl(base + MMCIMASK0) | MCI_DATAENDMASK, base + MMCIMASK0); }static void finish_dma_transfer(struct jademmci_host *host){ struct mmc_data *data; void __iomem *base = host->base; unsigned int tmp; data =host->data; host->data = NULL; if (data ) { if (!data->stop) mmci_request_end(host, data->mrq); else mmci_start_command(host, data->stop, 0); writel(0, base + MMCIMASK1); if (data->flags & MMC_DATA_READ ) writel(readl(base + MMCIMASK0) | MCI_DATACRCFAIL| MCI_DATAENDMASK| MCI_RXOVERRUN , base + MMCIMASK0); else{ tmp=readl(base+MMCISTATUS); writel(readl(base + MMCIMASK0) | MCI_DATACRCFAIL| MCI_DATAENDMASK| MCI_TXUNDERRUN , base + MMCIMASK0); } }}static void sd_dma_done(int a, int b, struct jademmci_host *host){ struct mmc_data *data; unsigned int tmp; unsigned int timeout=0xffffffff; if(b) printk("<1>sd dma error:%x, %x\n", a, b); host->data_xfered=host->size; data = host->data; if (!(data->flags & MMC_DATA_READ)) { do { tmp = readl(host->base +MMCISTATUS); tmp &= 1<<20; if (!tmp) break; timeout--; }while (timeout); udelay(3); } finish_dma_transfer(host);}int sd_start_dma(int read, unsigned int sg_len , u32 size,struct scatterlist *sg, struct jademmci_host *host){ pa_sd.SWidth = DMAC_TSIZE_WORD; pa_sd.DWidth = DMAC_TSIZE_WORD; if(read){ pa_sd.SBsize = 0x2; pa_sd.DBsize = 0x2; pa_sd.FlowCntrl =FLOW_PER_MEM_DMAC; pa_sd.SIncr = 0; pa_sd.DIncr = 1; pa_sd.lli_src = 1; }else{ pa_sd.SBsize = 0x2; pa_sd.DBsize = 0x2; pa_sd.FlowCntrl = FLOW_MEM_PER_DMAC; pa_sd.SIncr = 1; pa_sd.DIncr = 0; pa_sd.lli_src = 0; } if (ver_set_dma(ch_sd, &pa_sd) != 0) { printk("<1>sd read:set dma fail:\n"); return -1; } pa_sd.sg_len = sg_len; pa_sd.tsize = size; pa_sd.hwbuf = ((unsigned int)(JADE_MMCI1_BASE+0x80)); pa_sd.sg = sg; pa_sd.trans_done = sd_dma_done; pa_sd.done_data = host; if (ver_start_dma(ch_sd, &pa_sd) != 0) { printk("<1>sd:start dma fail:%d\n", size); return -1; } return 0;}static unsigned int fmax = 515633;static void mmci_enable_dma(struct jademmci_host *host,struct mmc_data *data ){ unsigned int sg_len,read; void __iomem *base; sg_len=host->sg_len; read = (data->flags & MMC_DATA_READ) ? 1 :0; base = host->base; sd_start_dma(read,sg_len,host->size,host->sg_ptr,host);}static void mmci_start_data(struct jademmci_host *host, struct mmc_data *data){ unsigned int datactrl=0, timeout; unsigned long long clks; void __iomem *base = host->base; DBG(host, "blksz %04x blks %04x flags %08x\n", 1 << data->blksz_bits, data->blocks, data->flags); host->data = data; host->size = data->blocks << data->blksz_bits; host->data_xfered = 0; mmci_init_sg(host, data); clks = (unsigned long long)data->timeout_ns * host->cclk; do_div(clks, 1000000000UL); timeout = data->timeout_clks + (unsigned int)clks; timeout=0xffffffff; writel(timeout, base + MMCIDATATIMER); writel(host->size, base + MMCIDATALENGTH); datactrl = MCI_DPSM_ENABLE | data->blksz_bits << 4; if (data->flags & MMC_DATA_READ) datactrl |= MCI_DPSM_DIRECTION; if ((host->size) >32 ) { writel((0x8000), base + MMCIDATALENGTH); datactrl |= MCI_DPSM_DMAENABLE; mmci_enable_dma(host,data); }else { datactrl &= ~MCI_DPSM_DMAENABLE; } writel(datactrl, base + MMCIDATACTRL); if (datactrl & MCI_DPSM_DMAENABLE) { if (data->flags & MMC_DATA_READ) writel(readl(base + MMCIMASK0) & ~(MCI_DATACRCFAIL| MCI_DATAENDMASK| MCI_RXOVERRUN), base + MMCIMASK0); else writel(readl(base + MMCIMASK0) & ~(MCI_DATACRCFAIL| MCI_DATAENDMASK| MCI_TXUNDERRUN), base + MMCIMASK0); } else writel(readl(base + MMCIMASK0) & ~MCI_DATAENDMASK, base + MMCIMASK0); writel(0, base + MMCIMASK1); } static voidmmci_data_irq(struct jademmci_host *host, struct mmc_data *data, unsigned int status){ if (status & MCI_DATABLOCKEND) { host->data_xfered += 1 << data->blksz_bits; } if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) { if (status & MCI_DATACRCFAIL) data->error = MMC_ERR_BADCRC; else if (status & MCI_DATATIMEOUT) data->error = MMC_ERR_TIMEOUT; else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN)) data->error = MMC_ERR_FIFO; status |= MCI_DATAEND; } if (status & MCI_DATAEND) { mmci_stop_data(host); if (!data->stop) { mmci_request_end(host, data->mrq); } else { mmci_start_command(host, data->stop, 0); } }}static voidmmci_cmd_irq(struct jademmci_host *host, struct mmc_command *cmd, unsigned int status){ void __iomem *base = host->base; host->cmd = NULL; cmd->resp[0] = readl(base + MMCIRESPONSE0); cmd->resp[1] = readl(base + MMCIRESPONSE1); cmd->resp[2] = readl(base + MMCIRESPONSE2); cmd->resp[3] = readl(base + MMCIRESPONSE3); if (status & MCI_CMDTIMEOUT) { cmd->error = MMC_ERR_TIMEOUT; } else if (status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) { cmd->error = MMC_ERR_BADCRC; } if (!cmd->data || cmd->error != MMC_ERR_NONE) { mmci_request_end(host, cmd->mrq); } else if (!(cmd->data->flags & MMC_DATA_READ)) { mmci_start_data(host, cmd->data); }}static int mmci_pio_read(struct jademmci_host *host, char *buffer, unsigned int remain){ void __iomem *base = host->base; char *ptr = buffer; u32 status; unsigned int timeout=0xffffffff; unsigned int *ptr_trans = buffer; unsigned int i; unsigned int transfered; do { int count = (readl(base + MMCIFIFOCNT) << 2); transfered= remain-count; if (transfered > remain) transfered = remain; for(i=0;i<transfered/4;i++ ) ptr_trans[i]=readl(base+MMCIFIFO); ptr_trans += transfered>>2; ptr +=transfered; remain=count; if (remain == 0) break; timeout--; } while (timeout); return ptr - buffer;}static int mmci_pio_write(struct jademmci_host *host, char *buffer, unsigned int remain, u32 status){ void __iomem *base = host->base; char *ptr = buffer; unsigned int *ptrt_rans = buffer; unsigned int i; do { unsigned int count, maxcnt; maxcnt = status & MCI_TXFIFOEMPTY ? MCI_FIFOSIZE : MCI_FIFOHALFSIZE; count = min(remain, maxcnt); for(i=0;i<count/4;i++ ) writel( ptrt_rans[i],base+MMCIFIFO); ptr += count; remain -= count; if (remain == 0) break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -