📄 mmci.c
字号:
/* it_mmcsd_clear_response_reg(&cmd); * linux/drivers/mmc/mmci.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 <linux/mmc/machmmc.h>#include <asm/div64.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/scatterlist.h>#include <asm/hardware/amba.h>#include <linux/mmc/mmc.h>#include <linux/interrupt.h>#include <asm/arch/gios.h>#include <asm/arch/gio.h>#include <asm/arch/irqs.h>#define GIO_SD_CARDDETECT 8#define GIO_SDCARD_WP 35#include "mmci.h"#include "itmmcsd.h"#include "mmc_debug.h"MODULE_LICENSE("INGENIENT");#if defined(CONFIG_ARCH_NTDEV_DM320) || defined(CONFIG_ARCH_NTR3_DM320) || defined(CONFIG_ARCH_ITDM320_20)static struct clk *clk_get(struct device *dev, const char *id);static void clk_put(struct clk *clk);static int clk_enable(struct clk *clk);static int clk_use(struct clk *clk);static unsigned long clk_get_rate(struct clk *clk);static void clk_unuse(struct clk *clk);void enable_interrupt(void);void disable_interrupt(void);void it_mmcsd_get_status(struct mmc_command *);void change_clk25m(void);#endifstatic unsigned short mmc_inw(unsigned long port){ unsigned short retval = inw(port); return retval;}static unsigned short mmc_outw(unsigned short data, unsigned long port){ outw(data,port); return 0;}#define udelay(x)#define DRIVER_NAME "SD-MMC"static unsigned int fmax = 515633;static int bCardInitialized = 0;void it_mmcsd_get_status(struct mmc_command *cmd){ cmd->status0 = inw(IO_MMC_STATUS0); rmb(); cmd->status1 = inw(IO_MMC_STATUS1); rmb(); cmd->resp[0] = inw(IO_MMC_RESPONSE0); rmb(); cmd->resp[1] = inw(IO_MMC_RESPONSE1); rmb(); cmd->resp[2] = inw(IO_MMC_RESPONSE2); rmb(); cmd->resp[3] = inw(IO_MMC_RESPONSE3); rmb(); cmd->resp[4] = inw(IO_MMC_RESPONSE4); rmb(); cmd->resp[5] = inw(IO_MMC_RESPONSE5); rmb(); cmd->resp[6] = inw(IO_MMC_RESPONSE6); rmb(); cmd->resp[7] = inw(IO_MMC_RESPONSE7); rmb(); cmd->cmd_index = inw (IO_MMC_COMMAND_INDEX); rmb();}void it_mmcsd_clear_response_reg(struct mmc_command *cmd){ outw(0,IO_MMC_RESPONSE0); wmb(); outw(0,IO_MMC_RESPONSE1); wmb(); outw(0,IO_MMC_RESPONSE2); wmb(); outw(0,IO_MMC_RESPONSE3); wmb(); outw(0,IO_MMC_RESPONSE4); wmb(); outw(0,IO_MMC_RESPONSE5); wmb(); outw(0,IO_MMC_RESPONSE6); wmb(); outw(0,IO_MMC_RESPONSE7); wmb(); outw(0,IO_MMC_COMMAND_INDEX); wmb(); cmd->resp[0] = 0; cmd->resp[1] = 0; cmd->resp[2] = 0; cmd->resp[3] = 0; cmd->resp[4] = 0; cmd->resp[5] = 0; cmd->resp[6] = 0; cmd->resp[7] = 0;}#if 0void it_mmcsd_print_status(struct mmc_command *cmd){ printk("Clk control : %x\n",inw(inw(IO_MMC_MEM_CLK_CONTROL))); printk("Control Reg : %x\n",inw(IO_MMC_CONTROL)); printk("status0 : %x \n",cmd->status0); printk("status1 : %x \n",cmd->status1); printk("resp[0] : %x \n",cmd->resp[0]); printk("resp[1] : %x \n",cmd->resp[1]); printk("resp[2] : %x \n",cmd->resp[2]); printk("resp[3] : %x \n",cmd->resp[3]); printk("resp[4] : %x \n",cmd->resp[4]); printk("resp[5] : %x \n",cmd->resp[5]); printk("resp[6] : %x \n",cmd->resp[6]); printk("resp[7] : %x \n",cmd->resp[7]); printk("cmd_index : %x \n",cmd->cmd_index);}#elsevoid it_mmcsd_print_status(struct mmc_command *cmd){ printk("\n status0 : %x \t",cmd->status0); printk("resp[6] : %x\t",cmd->resp[6]); printk("resp[7] : %x\t",cmd->resp[7]); printk("cmd_index : %x\t",cmd->cmd_index);}#endifvoid enable_interrupt(){ volatile u16 reg = 0; //Enable interrupt /* bring the sd/mmc controller to idle state */ reg = inw(IO_MMC_CONTROL); outw(reg | 0x03,IO_MMC_CONTROL); outw((inw(IO_INTC_EINT1) & 0xFFFC),IO_INTC_EINT1); outw(0x0FF,IO_MMC_INT_ENABLE); outw((inw(IO_INTC_EINT1) | 0x3),IO_INTC_EINT1); /* release idle state */ reg = inw(IO_MMC_CONTROL); outw(reg & 0xFFFC,IO_MMC_CONTROL); reg = inw(IO_MMC_CONTROL);}void disable_interrupt(){ volatile u16 reg = 0; //Disable interrupt /* bring the sd/mmc controller to idle state */ reg = inw(IO_MMC_CONTROL); rmb(); outw(reg | 0x03,IO_MMC_CONTROL); wmb(); outw((inw(IO_INTC_EINT1) & 0xFFFC),IO_INTC_EINT1); wmb(); outw(0x0000,IO_MMC_INT_ENABLE); wmb(); outw((inw(IO_INTC_EINT1) | 0x3),IO_INTC_EINT1); wmb(); /* release idle state */ reg = inw(IO_MMC_CONTROL); rmb(); outw(reg & 0xFFFC,IO_MMC_CONTROL); wmb(); reg = inw(IO_MMC_CONTROL); rmb();}void change_clk25m(){ volatile u16 reg = 0; //mmc_debug_msg ("%s\n",__FUNCTION__); /* bring the sd/mmc controller to idle state */ reg = inw (IO_MMC_CONTROL); rmb(); //mmc_debug_msg ("reg : %x\n",reg); outw(reg | 0x03,IO_MMC_CONTROL); wmb(); /*diable clock*/ reg = inw(IO_MMC_MEM_CLK_CONTROL); rmb(); outw(reg & 0xFEFF, IO_MMC_MEM_CLK_CONTROL); wmb(); reg = inw(IO_MMC_MEM_CLK_CONTROL); outw(inw(IO_CLK_INV) | 0x1,IO_CLK_INV); wmb(); /* set function clock */ outw(((inw(IO_CLK_DIV3) & 0xFF00 )| 0x01) ,IO_CLK_DIV3); wmb(); /* set mmc clock to ~ 25 MHz */ outw(((inw(IO_MMC_MEM_CLK_CONTROL) & 0xFF00) | 0x0),IO_MMC_MEM_CLK_CONTROL); wmb(); /* release idle state */ reg = inw(IO_MMC_CONTROL); rmb(); outw(reg & 0xFFFC,IO_MMC_CONTROL); wmb(); /* enable clock */ reg = inw(IO_MMC_MEM_CLK_CONTROL); rmb(); outw(reg | 0x0100, IO_MMC_MEM_CLK_CONTROL); wmb();}static void mmci_start_data(struct mmci_host *host, struct mmc_data *data){ unsigned int datactrl, timeout, irqmask; unsigned long long clks; host->data = data; host->size = data->blocks << data->blksz_bits; host->data_xfered = 0; mmci_init_sg(host, data); mmc_debug_msg ("%s %d\n",__FUNCTION__,__LINE__); clks = (unsigned long long)data->timeout_ns * host->cclk; do_div(clks, 1000000000UL); mmc_debug_msg ("%s %d\n",__FUNCTION__,__LINE__); timeout = data->timeout_clks + (unsigned int)clks; mmc_debug_msg ("host->size : %x\n",host->size); mmc_debug_msg ("data->blocks : %x\n",data->blocks); mmc_debug_msg ("data->blksz_bits : %x\n",data->blksz_bits); mmc_outw(data->blksz_bits,IO_MMC_BLOCK_LENGTH); mmc_outw(data->blocks,IO_MMC_NR_BLOCKS); datactrl = MCI_DPSM_ENABLE | data->blksz_bits << 4; if (data->flags & MMC_DATA_READ) { datactrl |= MCI_DPSM_DIRECTION; irqmask = MCI_RXFIFOHALFFULLMASK; } else { /* * We don't actually need to include "FIFO empty" here * since its implicit in "FIFO half empty". */ irqmask = MCI_TXFIFOHALFEMPTYMASK; }}void mmc_wait_for_op_cond(struct mmc_command *cmd){u32 marg;u16 cmd1;u32 oper_volt = 0x4;do { marg = 0x0; cmd1 = 55 | 0x0200 | 0x0080; //| 0x4000 | 0x0800; mmc_outw(marg & 0xFFFF,IO_MMC_ARG_LOW); mmc_outw((marg >> 16),IO_MMC_ARG_HI); mmc_outw(cmd1,IO_MMC_COMMAND); it_mmcsd_get_status(cmd); it_mmcsd_clear_response_reg(cmd); //clear the response register in the register //it_mmcsd_print_status(cmd); marg = (oper_volt << 14 ); cmd1 = 41 | 0x0600 | 0x0080;//| 0x4000; mmc_outw(marg & 0xFFFF,IO_MMC_ARG_LOW); mmc_outw((marg >> 16),IO_MMC_ARG_HI); mmc_outw(cmd1,IO_MMC_COMMAND); it_mmcsd_get_status(cmd); it_mmcsd_clear_response_reg(cmd); //clear the response register in the register //it_mmcsd_print_status(cmd); }while (!(cmd->resp[7] & 0x8000));}EXPORT_SYMBOL(mmc_wait_for_op_cond);static voidmmci_request_end(struct mmci_host *host, struct mmc_request *mrq){ 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);}static void mmci_stop_data(struct mmci_host *host){ host->data = NULL;}static voidmmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c){ u32 marg; u16 cmd1; mmc_debug_msg_command ("\nopcode : %d\targ : %x\n",(cmd->opcode & 0x3F),cmd->arg); it_mmcsd_clear_response_reg(cmd); host->cmd = cmd; marg = cmd->arg; cmd1 = cmd->opcode | cmd->flags | 0x0000; outw(marg & 0xFFFF,IO_MMC_ARG_LOW); outw((marg >> 16),IO_MMC_ARG_HI); outw(cmd1,IO_MMC_COMMAND); wmb(); bCardInitialized = 1;}static voidmmci_data_irq(struct mmci_host *host, struct mmc_data *data, unsigned int status){ if (status & MMC_INT_DATA_DONE) { 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 mmci_host *host, struct mmc_command *cmd, unsigned int status){ host->cmd = NULL; if (status & MMC_INT_RSP_TIMEOUT) { cmd->error = MMC_ERR_TIMEOUT; mmc_debug_msg ("Card has not responded \n"); } else if (status & MMC_INT_RSP_CRC_ERROR){ mmc_debug_msg("CRC ERROR\n"); 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)) { mmc_debug_msg("Data transfer\n"); mmci_start_data(host, cmd->data); host->mrq = NULL; host->cmd = NULL; }}/* * Handle completion of command and data transfers. */static volatile int in_interrupt = 1;static irqreturn_t mmci_irq(int irq, void *dev_id, struct pt_regs *regs){ struct mmci_host *host = dev_id; int ret = 1; struct mmc_command *cmd,data_cmd; struct mmc_data *data; spin_lock(&host->lock); //local_irq_disable(); if (in_interrupt){ mmc_debug_msg(" done -\t\n"); in_interrupt = 0; } cmd = host->cmd; if (cmd){ mmc_debug_msg ("Command is not NULL\n"); if((unsigned long ) cmd == 0x6b6b6b6b) { printk("\n Its too early to get an interrupt \n"); it_mmcsd_get_status(&data_cmd); it_mmcsd_print_status(&data_cmd); dump_stack(); panic("Early Interrupt\n"); spin_unlock(&host->lock); return IRQ_HANDLED; } it_mmcsd_get_status(cmd); //it_mmcsd_print_status(cmd); } else{ mmc_debug_msg("Command is NULL\n"); it_mmcsd_get_status(&data_cmd);// it_mmcsd_print_status(&data_cmd); cmd = &data_cmd; } data = host->data; if ((cmd->status0 & (MMC_INT_READ_CRC_ERROR|MMC_INT_WRITE_CRC_ERROR|MMC_INT_READ_TIMEOUT|MMC_INT_DATA_DONE)) | (cmd->status1 & (MMC_INT_DAT_RCV_RDY_S1|MMC_INT_DAT_TRX_RDY_S1))){ mmci_data_irq(host,data,(cmd->status0|cmd->status1 << 16)); } if ((cmd->status0 & (MMC_INT_RSP_CRC_ERROR | MMC_INT_RSP_TIMEOUT | MMC_INT_RSP_DONE))){ mmci_cmd_irq(host, cmd, cmd->status0); } in_interrupt = 1; ret = 1; //local_irq_enable(); spin_unlock(&host->lock); return IRQ_RETVAL(ret);}static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq){ struct mmci_host *host = mmc_priv(mmc); WARN_ON(host->mrq != NULL); spin_lock_irq(&host->lock); host->mrq = mrq; if (mrq->data && mrq->data->flags & MMC_DATA_READ){ mmci_start_data(host, mrq->data); } mmci_start_command(host, mrq->cmd, 0); spin_unlock_irq(&host->lock);}static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios){ volatile u16 reg = 0; /* bring the sd/mmc controller to idle state */ reg = inw (IO_MMC_CONTROL); rmb(); outw(reg | 0x03,IO_MMC_CONTROL); wmb(); if (mmc->ios.bus_width == MMC_BUS_WIDTH_4){ /*changing to 4-data line mode*/ outw(reg | (1 << 2),IO_MMC_CONTROL); wmb(); } else{ /*changing to 4-data line mode*/ outw(reg & (~(1 << 2)),IO_MMC_CONTROL); wmb(); } /* release idle state */ reg = inw(IO_MMC_CONTROL); rmb(); outw(reg & 0xFFFC,IO_MMC_CONTROL); wmb();}int write_to_card(struct mmc_host *mmc,struct mmc_request *mrq){ u32 current_add; u16 no_of_blks; u32 marg; u16 cmd1,reg; int write_count; volatile unsigned short reg1 = 0;#ifndef DMA_TRANSFER short write_data;#endif struct mmc_command cmd; struct mmci_host *host = mmc_priv(mmc); spin_lock(&host->lock); disable_interrupt(); local_irq_disable(); /* disable clock */ reg = mmc_inw(IO_MMC_MEM_CLK_CONTROL); mmc_outw(reg & 0xFEFF, IO_MMC_MEM_CLK_CONTROL); mrq->cmd->error = 0; mrq->cmd->mrq = mrq; if (mrq->data) { mrq->cmd->data = mrq->data;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -