1、Simplify the driver code.
2、modify the SDMMC_CLKEN_DISABLE
3、prepare for IDMA.
4、continue with 2b0034ec2e
This commit is contained in:
xbw
2013-08-08 16:50:13 +08:00
parent e31fedd62b
commit 1ce74250f9
2 changed files with 417 additions and 517 deletions

View File

@@ -64,64 +64,7 @@ int debug_level = 5;
#define xbwprintk(n, arg...)
#endif
#if defined(CONFIG_ARCH_RK29)
#define SDMMC_USE_INT_UNBUSY 0
#else
#define SDMMC_USE_INT_UNBUSY 0///1
#endif
/*
** You can set the macro to true, if some module wants to use this feature, which is about SDIO suspend-resume.
** As the following example.
** added by xbw at 2013-05-08
*/
#if defined(CONFIG_MTK_COMBO_DRIVER_VERSION_JB2)
#define RK_SDMMC_USE_SDIO_SUSPEND_RESUME 1
#else
#define RK_SDMMC_USE_SDIO_SUSPEND_RESUME 0
#endif
#define RK29_SDMMC_ERROR_FLAGS (SDMMC_INT_FRUN | SDMMC_INT_HLE )
#if defined(CONFIG_SDMMC0_RK29_SDCARD_DET_FROM_GPIO)
#if SDMMC_USE_INT_UNBUSY
#define RK29_SDMMC_INTMASK_USEDMA (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | SDMMC_INT_UNBUSY |RK29_SDMMC_ERROR_FLAGS )
#define RK29_SDMMC_INTMASK_USEIO (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | SDMMC_INT_UNBUSY |RK29_SDMMC_ERROR_FLAGS | SDMMC_INT_TXDR | SDMMC_INT_RXDR )
#else
#define RK29_SDMMC_INTMASK_USEDMA (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | RK29_SDMMC_ERROR_FLAGS )
#define RK29_SDMMC_INTMASK_USEIO (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | RK29_SDMMC_ERROR_FLAGS | SDMMC_INT_TXDR | SDMMC_INT_RXDR )
#endif
#else
#if SDMMC_USE_INT_UNBUSY
#define RK29_SDMMC_INTMASK_USEDMA (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | SDMMC_INT_UNBUSY |RK29_SDMMC_ERROR_FLAGS | SDMMC_INT_CD)
#define RK29_SDMMC_INTMASK_USEIO (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | SDMMC_INT_UNBUSY |RK29_SDMMC_ERROR_FLAGS | SDMMC_INT_CD| SDMMC_INT_TXDR | SDMMC_INT_RXDR )
#else
#define RK29_SDMMC_INTMASK_USEDMA (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | RK29_SDMMC_ERROR_FLAGS | SDMMC_INT_CD)
#define RK29_SDMMC_INTMASK_USEIO (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | RK29_SDMMC_ERROR_FLAGS | SDMMC_INT_CD| SDMMC_INT_TXDR | SDMMC_INT_RXDR )
#endif
#endif
#define RK29_SDMMC_SEND_START_TIMEOUT 3000 //The time interval from the time SEND_CMD to START_CMD_BIT cleared.
#define RK29_ERROR_PRINTK_INTERVAL 200 //The time interval between the two printk for the same error.
#define RK29_SDMMC_WAIT_DTO_INTERNVAL 4500 //The time interval from the CMD_DONE_INT to DTO_INT
#define RK29_SDMMC_REMOVAL_DELAY 2000 //The time interval from the CD_INT to detect_timer react.
#define RK29_SDMMC_VERSION "Ver.6.00 The last modify date is 2013-08-02"
#if !defined(CONFIG_USE_SDMMC0_FOR_WIFI_DEVELOP_BOARD)
#define RK29_CTRL_SDMMC_ID 0 //mainly used by SDMMC
#define RK29_CTRL_SDIO1_ID 1 //mainly used by sdio-wifi
#define RK29_CTRL_SDIO2_ID 2 //mainly used by sdio-card
#else
#define RK29_CTRL_SDMMC_ID 5
#define RK29_CTRL_SDIO1_ID 1
#define RK29_CTRL_SDIO2_ID 2
#endif
#define SDMMC_CLOCK_TEST 0
#define RK29_SDMMC_NOTIFY_REMOVE_INSERTION /* use sysfs to notify the removal or insertion of sd-card*/
//#define RK29_SDMMC_LIST_QUEUE /* use list-queue for multi-card*/
#define RK29_SDMMC_VERSION "Ver.6.01 The last modify date is 2013-08-05"
#define RK29_SDMMC_DEFAULT_SDIO_FREQ 0 // 1--run in default frequency(50Mhz); 0---run in 25Mhz,
#if defined(CONFIG_MT6620)|| defined(CONFIG_ESP8089)
@@ -137,172 +80,9 @@ int debug_level = 5;
#define DRIVER_SDMMC_USE_NEW_IOMUX_API 0
#endif
//support Internal DMA
#if 0 //Sometime in the future to enable
#define DRIVER_SDMMC_USE_IDMA 1
#else
#define DRIVER_SDMMC_USE_IDMA 0
#endif
#define SWITCH_VOLTAGE_18_33 0 //RK30_PIN2_PD7 //Temporary experiment
#define SWITCH_VOLTAGE_ENABLE_VALUE_33 GPIO_LOW
enum {
EVENT_CMD_COMPLETE = 0,
EVENT_DATA_COMPLETE,
EVENT_DATA_UNBUSY,
EVENT_DATA_ERROR,
EVENT_XFER_ERROR
};
enum rk29_sdmmc_state {
STATE_IDLE = 0,
STATE_SENDING_CMD,
STATE_DATA_BUSY,
STATE_DATA_UNBUSY,
STATE_DATA_END,
STATE_SENDING_STOP,
};
struct rk29_sdmmc_dma_info {
enum dma_ch chn;
char *name;
struct rk29_dma_client client;
};
static struct rk29_sdmmc_dma_info rk29_sdmmc_dma_infos[]= {
{
.chn = DMACH_SDMMC,
.client = {
.name = "rk29-dma-sdmmc0",
}
},
{
.chn = DMACH_SDIO,
.client = {
.name = "rk29-dma-sdio1",
}
},
{
.chn = DMACH_EMMC,
.client = {
.name = "rk29-dma-sdio2",
}
},
};
/* Interrupt Information */
typedef struct TagSDC_INT_INFO
{
u32 transLen; //the length of data sent.
u32 desLen; //the total length of the all data.
u32 *pBuf; //the data buffer for interrupt read or write.
}SDC_INT_INFO_T;
struct rk29_sdmmc {
spinlock_t lock;
void __iomem *regs;
struct clk *clk;
struct mmc_request *mrq;
struct mmc_request *new_mrq;
struct mmc_command *cmd;
struct mmc_data *data;
struct scatterlist *sg;
dma_addr_t dma_addr;;
unsigned int use_dma:1;
char dma_name[8];
u32 cmd_status;
u32 data_status;
u32 stop_cmdr;
u32 old_div;
u32 cmdr; //the value setted into command-register
u32 dodma; //sign the DMA used for transfer.
u32 errorstep;//record the error point.
int timeout_times; //use to force close the sdmmc0 when the timeout_times exceeds the limit.
u32 *pbuf;
SDC_INT_INFO_T intInfo;
struct rk29_sdmmc_dma_info dma_info;
int irq;
int error_times;
u32 old_cmd;
struct tasklet_struct tasklet;
unsigned long pending_events;
unsigned long completed_events;
enum rk29_sdmmc_state state;
#ifdef RK29_SDMMC_LIST_QUEUE
struct list_head queue;
struct list_head queue_node;
#endif
u32 bus_hz;
struct platform_device *pdev;
struct mmc_host *mmc;
u32 ctype;
unsigned int clock;
unsigned long flags;
#define RK29_SDMMC_CARD_PRESENT 0
int id;
struct timer_list detect_timer;
struct timer_list request_timer; //the timer for INT_CMD_DONE
struct timer_list DTO_timer; //the timer for INT_DTO
struct mmc_command stopcmd;
struct rksdmmc_gpio det_pin;
/* flag for current bus settings */
u32 bus_mode;
unsigned int oldstatus;
unsigned int complete_done;
unsigned int retryfunc;
int gpio_irq;
int gpio_power_en;
int gpio_power_en_level;
struct delayed_work work;
#ifdef CONFIG_RK29_SDIO_IRQ_FROM_GPIO
unsigned int sdio_INT_gpio;
unsigned int sdio_irq;
unsigned long trigger_level;
#endif
#if defined(CONFIG_SDMMC0_RK29_WRITE_PROTECT) || defined(CONFIG_SDMMC1_RK29_WRITE_PROTECT)
int write_protect;
int protect_level;
#endif
bool irq_state;
void (*set_iomux)(int device_id, unsigned int bus_width);
};
#ifdef RK29_SDMMC_NOTIFY_REMOVE_INSERTION
static struct rk29_sdmmc *globalSDhost[3];
#endif
#define rk29_sdmmc_test_and_clear_pending(host, event) \
test_and_clear_bit(event, &host->pending_events)
#define rk29_sdmmc_test_pending(host, event) \
test_bit(event, &host->pending_events)
#define rk29_sdmmc_test_completed(host, event) \
test_bit(event, &host->completed_events)
#define rk29_sdmmc_set_completed(host, event) \
set_bit(event, &host->completed_events)
#define rk29_sdmmc_set_pending(host, event) \
set_bit(event, &host->pending_events)
static void rk29_sdmmc_start_error(struct rk29_sdmmc *host);
static int rk29_sdmmc_clear_fifo(struct rk29_sdmmc *host);
int rk29_sdmmc_hw_init(void *data);
@@ -319,40 +99,14 @@ static unsigned int rk29_sdmmc_read(unsigned char __iomem *regbase, unsigned in
static int rk29_sdmmc_regs_printk(struct rk29_sdmmc *host)
{
printk("SDMMC_CTRL: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_CTRL));
printk("SDMMC_PWREN: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_PWREN));
printk("SDMMC_CLKDIV: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_CLKDIV));
printk("SDMMC_CLKSRC: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_CLKSRC));
printk("SDMMC_CLKENA: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_CLKENA));
printk("SDMMC_TMOUT: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_TMOUT));
printk("SDMMC_CTYPE: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_CTYPE));
printk("SDMMC_BLKSIZ: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_BLKSIZ));
printk("SDMMC_BYTCNT: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_BYTCNT));
printk("SDMMC_INTMASK:\t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_INTMASK));
printk("SDMMC_CMDARG: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_CMDARG));
printk("SDMMC_CMD: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_CMD));
printk("SDMMC_RESP0: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_RESP0));
printk("SDMMC_RESP1: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_RESP1));
printk("SDMMC_RESP2: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_RESP2));
printk("SDMMC_RESP3: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_RESP3));
printk("SDMMC_MINTSTS:\t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_MINTSTS));
printk("SDMMC_RINTSTS:\t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_RINTSTS));
printk("SDMMC_STATUS: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_STATUS));
printk("SDMMC_FIFOTH: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_FIFOTH));
printk("SDMMC_CDETECT:\t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_CDETECT));
printk("SDMMC_WRTPRT: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_WRTPRT));
printk("SDMMC_TCBCNT: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_TCBCNT));
printk("SDMMC_TBBCNT: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_TBBCNT));
printk("SDMMC_DEBNCE: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_DEBNCE));
printk("SDMMC_USRID: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_USRID));
struct sdmmc_reg *regs = rk_sdmmc_regs;
#if !defined(CONFIG_ARCH_RK29)
printk("SDMMC_VERID: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_VERID));
printk("SDMMC_UHS_REG:\t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_UHS_REG));
printk("SDMMC_RST_n: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_RST_n));
printk("SDMMC_CARDTHRCTL: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_CARDTHRCTL));
printk("SDMMC_BACK_END_POWER: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_BACK_END_POWER));
#endif
while( regs->name != 0 )
{
printk("%s: (0x%04x) = 0x%08x\n", regs->name, regs->addr, rk29_sdmmc_read(host->regs, regs->addr));
regs++;
}
printk("=======printk %s-register end =========\n", host->dma_name);
return 0;
}
@@ -362,9 +116,7 @@ static void rk29_sdmmc_enable_irq(struct rk29_sdmmc *host, bool irqflag)
unsigned long flags;
if(!host)
{
return;
}
local_irq_save(flags);
if(host->irq_state != irqflag)
@@ -384,6 +136,18 @@ static void rk29_sdmmc_enable_irq(struct rk29_sdmmc *host, bool irqflag)
#ifdef RK29_SDMMC_NOTIFY_REMOVE_INSERTION
/*
** debug the progress.
**
** # echo version > sys/sd-sdio/rescan //check the current sdmmc-driver version
**
** # echo sd-reset > sys/sd-sdio/rescan //run mmc0 mmc_rescan again
** # echo sd-regs > sys/sd-sdio/rescan //printk all registers of mmc0.
**
** # echo sdio1-reset > sys/sd-sdio/rescan //run mmc1 mmc_rescan again
** # echo sdio1-regs > sys/sd-sdio/rescan //printk all registers of mmc1.
**
*/
ssize_t rk29_sdmmc_progress_store(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t count)
{
@@ -549,8 +313,6 @@ ssize_t rk29_sdmmc_progress_store(struct kobject *kobj, struct kobj_attribute *a
return count;
}
struct kobj_attribute mmc_reset_attrs =
{
.attr = {
@@ -576,9 +338,8 @@ static int rk29_sdmmc_progress_add_attr( struct platform_device *pdev )
struct kobject *parentkobject;
struct kobject * me = kmalloc(sizeof(struct kobject) , GFP_KERNEL );
if(!me)
{
return -ENOMEM;
}
memset(me ,0,sizeof(struct kobject));
kobject_init( me , &mmc_kset_ktype );
@@ -589,157 +350,6 @@ static int rk29_sdmmc_progress_add_attr( struct platform_device *pdev )
}
#endif
#if defined (CONFIG_DEBUG_FS)
static int rk29_sdmmc_regs_show(struct seq_file *s, void *v)
{
struct rk29_sdmmc *host = s->private;
seq_printf(s, "SDMMC_CTRL: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_CTRL));
seq_printf(s, "SDMMC_PWREN: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_PWREN));
seq_printf(s, "SDMMC_CLKDIV: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_CLKDIV));
seq_printf(s, "SDMMC_CLKSRC: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_CLKSRC));
seq_printf(s, "SDMMC_CLKENA: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_CLKENA));
seq_printf(s, "SDMMC_TMOUT: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_TMOUT));
seq_printf(s, "SDMMC_CTYPE: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_CTYPE));
seq_printf(s, "SDMMC_BLKSIZ: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_BLKSIZ));
seq_printf(s, "SDMMC_BYTCNT: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_BYTCNT));
seq_printf(s, "SDMMC_INTMASK:\t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_INTMASK));
seq_printf(s, "SDMMC_CMDARG: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_CMDARG));
seq_printf(s, "SDMMC_CMD: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_CMD));
seq_printf(s, "SDMMC_RESP0: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_RESP0));
seq_printf(s, "SDMMC_RESP1: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_RESP1));
seq_printf(s, "SDMMC_RESP2: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_RESP2));
seq_printf(s, "SDMMC_RESP3: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_RESP3));
seq_printf(s, "SDMMC_MINTSTS:\t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_MINTSTS));
seq_printf(s, "SDMMC_RINTSTS:\t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_RINTSTS));
seq_printf(s, "SDMMC_STATUS: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_STATUS));
seq_printf(s, "SDMMC_FIFOTH: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_FIFOTH));
seq_printf(s, "SDMMC_CDETECT:\t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_CDETECT));
seq_printf(s, "SDMMC_WRTPRT: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_WRTPRT));
seq_printf(s, "SDMMC_TCBCNT: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_TCBCNT));
seq_printf(s, "SDMMC_TBBCNT: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_TBBCNT));
seq_printf(s, "SDMMC_DEBNCE: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_DEBNCE));
return 0;
}
/*
* The debugfs stuff below is mostly optimized away when
* CONFIG_DEBUG_FS is not set.
*/
static int rk29_sdmmc_req_show(struct seq_file *s, void *v)
{
struct rk29_sdmmc *host = s->private;
struct mmc_request *mrq;
struct mmc_command *cmd;
struct mmc_command *stop;
struct mmc_data *data;
/* Make sure we get a consistent snapshot */
spin_lock(&host->lock);
mrq = host->mrq;
if (mrq) {
cmd = mrq->cmd;
data = mrq->data;
stop = mrq->stop;
if (cmd)
seq_printf(s,
"CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n",
cmd->opcode, cmd->arg, cmd->flags,
cmd->resp[0], cmd->resp[1], cmd->resp[2],
cmd->resp[2], cmd->error);
if (data)
seq_printf(s, "DATA %u / %u * %u flg %x err %d\n",
data->bytes_xfered, data->blocks,
data->blksz, data->flags, data->error);
if (stop)
seq_printf(s,
"CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n",
stop->opcode, stop->arg, stop->flags,
stop->resp[0], stop->resp[1], stop->resp[2],
stop->resp[2], stop->error);
}
spin_unlock(&host->lock);
return 0;
}
static int rk29_sdmmc_req_open(struct inode *inode, struct file *file)
{
return single_open(file, rk29_sdmmc_req_show, inode->i_private);
}
static const struct file_operations rk29_sdmmc_req_fops = {
.owner = THIS_MODULE,
.open = rk29_sdmmc_req_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int rk29_sdmmc_regs_open(struct inode *inode, struct file *file)
{
return single_open(file, rk29_sdmmc_regs_show, inode->i_private);
}
static const struct file_operations rk29_sdmmc_regs_fops = {
.owner = THIS_MODULE,
.open = rk29_sdmmc_regs_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static void rk29_sdmmc_init_debugfs(struct rk29_sdmmc *host)
{
struct mmc_host *mmc = host->mmc;
struct dentry *root;
struct dentry *node;
root = mmc->debugfs_root;
if (!root)
return;
node = debugfs_create_file("regs", S_IRUSR, root, host,
&rk29_sdmmc_regs_fops);
if (IS_ERR(node))
return;
if (!node)
goto err;
node = debugfs_create_file("req", S_IRUSR, root, host, &rk29_sdmmc_req_fops);
if (!node)
goto err;
node = debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state);
if (!node)
goto err;
node = debugfs_create_x32("pending_events", S_IRUSR, root,
(u32 *)&host->pending_events);
if (!node)
goto err;
node = debugfs_create_x32("completed_events", S_IRUSR, root,
(u32 *)&host->completed_events);
if (!node)
goto err;
return;
err:
dev_err(&mmc->class_dev, "failed to initialize debugfs for host\n");
}
#endif
/**
** This function checks whether the core supports the IDMAC.
** return Returns 1 if HW supports IDMAC, else returns 0.
@@ -757,9 +367,6 @@ u32 rk_sdmmc_check_idma_support(struct rk29_sdmmc *host)
return retval;
}
static u32 rk29_sdmmc_prepare_command(struct mmc_command *cmd)
{
u32 cmdr = cmd->opcode;
@@ -769,7 +376,6 @@ static u32 rk29_sdmmc_prepare_command(struct mmc_command *cmd)
case MMC_GO_IDLE_STATE:
cmdr |= (SDMMC_CMD_INIT | SDMMC_CMD_PRV_DAT_NO_WAIT);
break;
case MMC_STOP_TRANSMISSION:
cmdr |= (SDMMC_CMD_STOP | SDMMC_CMD_PRV_DAT_NO_WAIT);
break;
@@ -777,7 +383,6 @@ static u32 rk29_sdmmc_prepare_command(struct mmc_command *cmd)
case MMC_GO_INACTIVE_STATE:
cmdr |= SDMMC_CMD_PRV_DAT_NO_WAIT;
break;
default:
cmdr |= SDMMC_CMD_PRV_DAT_WAIT;
break;
@@ -1030,13 +635,9 @@ static void rk29_sdmmc_control_host_dma(struct rk29_sdmmc *host, bool enable)
u32 value = rk29_sdmmc_read(host->regs, SDMMC_CTRL);
if (enable)
{
value |= SDMMC_CTRL_DMA_ENABLE;
}
else
{
value &= ~(SDMMC_CTRL_DMA_ENABLE);
}
rk29_sdmmc_write(host->regs, SDMMC_CTRL, value);
}
@@ -1044,10 +645,7 @@ static void rk29_sdmmc_control_host_dma(struct rk29_sdmmc *host, bool enable)
static void send_stop_cmd(struct rk29_sdmmc *host)
{
int ret, i;
// int timeout = 250;
// unsigned int value;
if(host->mrq->cmd->error)
{
//stop DMA
@@ -1120,15 +718,42 @@ static void rk29_sdmmc_dma_complete(void *arg, int size, enum rk29_dma_buffresul
host->intInfo.transLen = host->intInfo.desLen;
}
static void rk_sdmmc_push_data32(struct rk29_sdmmc *host, void *buf, int cnt)
{
u32 *pdata = (u32 *)buf;
WARN_ON(cnt % 4 != 0);
WARN_ON((unsigned long)pdata & 0x3);
cnt = cnt >> 2;
while (cnt > 0) {
rk29_sdmmc_write(host->regs, SDMMC_DATA, *pdata++);
cnt--;
}
}
static void rk_sdmmc_pull_data32(struct rk29_sdmmc *host, void *buf, int cnt)
{
u32 *pdata = (u32 *)buf;
WARN_ON(cnt % 4 != 0);
WARN_ON((unsigned long)pdata & 0x3);
cnt = cnt >> 2;
while (cnt > 0) {
*pdata++ = rk29_sdmmc_read(host->regs, SDMMC_DATA);
cnt--;
}
}
static int rk29_sdmmc_read_data_pio(struct rk29_sdmmc *host)
{
struct scatterlist *sg;
u32 *buf;
unsigned int offset = 0;
struct mmc_data *data;
void *buf;
unsigned int offset;
struct mmc_data *data = host->data;
u32 value;
unsigned int nbytes = 0;
int remaining;
unsigned int nbytes=0, len;
value = rk29_sdmmc_read(host->regs, SDMMC_STATUS);
if ( value& SDMMC_STAUTS_FIFO_EMPTY)
@@ -1139,60 +764,55 @@ static int rk29_sdmmc_read_data_pio(struct rk29_sdmmc *host)
if((NULL == host)&&(NULL == host->data))
goto done;
data = host->data;
sg = host->sg;
buf = (u32 *)sg_virt(sg);
buf = sg_virt(sg);
offset = host->pio_offset;
while ( (host->intInfo.transLen < host->intInfo.desLen) && (!(value & SDMMC_STAUTS_FIFO_EMPTY)) )
{
if( ((offset + (host->intInfo.desLen - host->intInfo.transLen))<<2) <= sg->length )
{
buf[offset] = rk29_sdmmc_read(host->regs, SDMMC_DATA);
offset ++;
nbytes += 4;
host->intInfo.transLen++;
len = SDMMC_GET_FCNT(value) << PIO_DATA_SHIFT;
if (offset + len <= sg->length) {
host->pull_data(host, (void *)(buf + offset), len);
if ((offset<<2) == sg->length)
{
offset += len;
nbytes += len;
host->intInfo.transLen++;
if (offset == sg->length) {
flush_dcache_page(sg_page(sg));
host->sg = sg = sg_next(sg);
if (!sg)
goto done;
offset = 0;
buf = (u32 *)sg_virt(sg);
buf = sg_virt(sg);
}
}
else
{
remaining = (sg->length>>2) - offset;
while( remaining>0)
{
buf[offset] = rk29_sdmmc_read(host->regs, SDMMC_DATA);
offset ++;
nbytes += 4;
remaining --;
host->intInfo.transLen++;
}
}else {
unsigned int remaining = sg->length - offset;
host->pull_data(host, (void *)(buf + offset),remaining);
nbytes += remaining;
host->intInfo.transLen++;
flush_dcache_page(sg_page(sg));
host->sg = sg = sg_next(sg);
if (!sg)
goto done;
offset = 0;
buf = (u32 *)sg_virt(sg);
}
flush_dcache_page(sg_page(sg));
host->sg = sg = sg_next(sg);
if (!sg)
goto done;
offset = len - remaining;
buf = sg_virt(sg);
host->pull_data(host, buf, offset);
nbytes += offset;
}
host->pio_offset = offset;
data->bytes_xfered += nbytes;
value = rk29_sdmmc_read(host->regs, SDMMC_STATUS);
}
return 0;
done:
data->bytes_xfered += nbytes;
return 0;
}
@@ -1200,12 +820,11 @@ done:
static int rk29_sdmmc_write_data_pio(struct rk29_sdmmc *host)
{
struct scatterlist *sg;
u32 *buf;
unsigned int offset = 0;
struct mmc_data *data;
void *buf;
unsigned int offset;
struct mmc_data *data = host->data;
u32 value;
unsigned int nbytes = 0;
int remaining;
unsigned int nbytes=0, len;
value = rk29_sdmmc_read(host->regs, SDMMC_STATUS);
if ( value& SDMMC_STAUTS_FIFO_EMPTY)
@@ -1217,62 +836,61 @@ static int rk29_sdmmc_write_data_pio(struct rk29_sdmmc *host)
if((NULL == host)&&(NULL == host->data))
goto done;
data = host->data;
sg = host->sg;
buf = (u32 *)sg_virt(sg);
buf = sg_virt(sg);
offset = host->pio_offset;
while ( (host->intInfo.transLen < host->intInfo.desLen) && (!(value & SDMMC_STAUTS_FIFO_EMPTY)) )
{
if( ((offset + (host->intInfo.desLen - host->intInfo.transLen))<<2) <= sg->length )
{
rk29_sdmmc_write(host->regs, SDMMC_DATA, buf[offset]);
offset ++;
nbytes += 4;
host->intInfo.transLen++;
len = SDMMC_FIFO_SZ -(SDMMC_GET_FCNT(value) << PIO_DATA_SHIFT);
if (offset + len <= sg->length) {
host->push_data(host, (void *)(buf + offset), len);
if ((offset<<2) == sg->length)
{
offset += len;
nbytes += len;
host->intInfo.transLen++;
if (offset == sg->length) {
host->sg = sg = sg_next(sg);
if (!sg)
goto done;
offset = 0;
buf = (u32 *)sg_virt(sg);
buf = sg_virt(sg);
}
}
else
{
remaining = (sg->length>>2) - offset;
while( remaining>0)
{
rk29_sdmmc_write(host->regs, SDMMC_DATA, buf[offset]);
offset ++;
nbytes += 4;
remaining --;
host->intInfo.transLen++;
}
} else {
unsigned int remaining = sg->length - offset;
host->sg = sg = sg_next(sg);
if (!sg)
goto done;
host->push_data(host, (void *)(buf + offset),
remaining);
nbytes += remaining;
host->intInfo.transLen++;
offset = 0;
buf = (u32 *)sg_virt(sg);
}
host->sg = sg = sg_next(sg);
if (!sg)
goto done;
data->bytes_xfered += nbytes;
offset = len - remaining;
buf = sg_virt(sg);
host->push_data(host, (void *)buf, offset);
nbytes += offset;
}
host->pio_offset = offset;
data->bytes_xfered += nbytes;
value = rk29_sdmmc_read(host->regs, SDMMC_STATUS);
}
return 0;
done:
data->bytes_xfered += nbytes;
return 0;
}
static int rk29_sdmmc_submit_data_dma(struct rk29_sdmmc *host, struct mmc_data *data)
{
unsigned int i,direction, sgDirection;
unsigned int i,direction, sgDirection;
int ret, dma_len=0;
if(host->use_dma == 0)
@@ -1398,9 +1016,10 @@ static int rk29_sdmmc_prepare_write_data(struct rk29_sdmmc *host, struct mmc_dat
host->intInfo.transLen = 0;
host->intInfo.pBuf = (u32 *)pBuf;
if(0)//(host->intInfo.desLen <= 512 )
if(0)//(host->intInfo.desLen <= TX_WMARK)
{
//use pio-mode
//use pio-mode
rk29_sdmmc_write_data_pio(host);
return SDM_SUCCESS;
}
else
@@ -1429,9 +1048,6 @@ static int rk29_sdmmc_prepare_write_data(struct rk29_sdmmc *host, struct mmc_dat
return output;
}
static int rk29_sdmmc_prepare_read_data(struct rk29_sdmmc *host, struct mmc_data *data)
{
u32 count = 0;
@@ -1452,9 +1068,10 @@ static int rk29_sdmmc_prepare_read_data(struct rk29_sdmmc *host, struct mmc_data
if(count > (RX_WMARK+1)) //datasheet error.actually, it can nont waken the interrupt when less and equal than RX_WMARK+1
{
if(0) //(host->intInfo.desLen <= 512 )
if(0)//(host->intInfo.desLen <= RX_WMARK)
{
//use pio-mode
rk29_sdmmc_read_data_pio(host);
return SDM_SUCCESS;
}
else
@@ -1538,6 +1155,7 @@ static void rk29_sdmmc_submit_data(struct rk29_sdmmc *host, struct mmc_data *dat
data->bytes_xfered = 0;
host->pbuf = (u32*)sg_virt(data->sg);
host->pio_offset = 0;
if (data->flags & MMC_DATA_STREAM)
{
@@ -4057,6 +3675,12 @@ static int rk29_sdmmc_probe(struct platform_device *pdev)
host->dma_addr = regs->start + SDMMC_DATA;
}
/*
* Get the host data width,default 32bit
*/
host->push_data = rk_sdmmc_push_data32;
host->pull_data = rk_sdmmc_pull_data32;
#if defined(CONFIG_SDMMC0_RK29_WRITE_PROTECT) || defined(CONFIG_SDMMC1_RK29_WRITE_PROTECT)
host->write_protect = pdata->write_prt;
host->protect_level = pdata->write_prt_enalbe_level;
@@ -4212,10 +3836,6 @@ static int rk29_sdmmc_probe(struct platform_device *pdev)
}
#endif
#if defined (CONFIG_DEBUG_FS)
rk29_sdmmc_init_debugfs(host);
#endif
printk(KERN_INFO ".Line%d..The End of SDMMC-probe %s. [%s]\n", __LINE__, RK29_SDMMC_VERSION,host->dma_name);
return 0;

View File

@@ -68,6 +68,59 @@
#define SDMMC_DATA SDMMC_FIFO_BASE
#endif
struct sdmmc_reg
{
u32 addr;
char * name;
};
static struct sdmmc_reg rk_sdmmc_regs[] =
{
{ 0x0000, " CTRL" },
{ 0x0004, " PWREN" },
{ 0x0008, " CLKDIV" },
{ 0x000C, " CLKSRC" },
{ 0x0010, " CLKENA" },
{ 0x0014, " TMOUT" },
{ 0x0018, " CTYPE" },
{ 0x001C, " BLKSIZ" },
{ 0x0020, " BYTCNT" },
{ 0x0024, " INTMSK" },
{ 0x0028, " CMDARG" },
{ 0x002C, " CMD" },
{ 0x0030, " RESP0" },
{ 0x0034, " RESP1" },
{ 0x0038, " RESP2" },
{ 0x003C, " RESP3" },
{ 0x0040, " MINSTS" },
{ 0x0044, " RINTSTS" },
{ 0x0048, " STATUS" },
{ 0x004C, " FIFOTH" },
{ 0x0050, " CDETECT" },
{ 0x0054, " WRTPRT" },
{ 0x0058, " GPIO" },
{ 0x005C, " TCBCNT" },
{ 0x0060, " TBBCNT" },
{ 0x0064, " DEBNCE" },
{ 0x0068, " USRID" },
#if !defined(CONFIG_ARCH_RK29)
{ 0x006C, " VERID" },
{ 0x0070, " HCON" },
{ 0x0074, " UHS_REG" },
{ 0x0078, " RST_n" },
{ 0x0080, " BMOD" },
{ 0x0084, " PLDMND" },
{ 0x0088, " DBADDR" },
{ 0x008C, " IDSTS" },
{ 0x0090, " IDINTEN" },
{ 0x0094, " DSCADDR" },
{ 0x0098, " BUFADDR" },
{ 0x0100, "CARDTHRCTL" },
{ 0x0104, "BackEndPwr" },
#endif
{ 0, 0 }
};
#define BIT(n) (1<<(n))
#define RK_CLEAR_BIT(n) (0<<(n))
@@ -102,7 +155,7 @@
#define SDMMC_CLKEN_LOW_PWR BIT(16)
#define SDMMC_CLKEN_NO_LOW_PWR RK_CLEAR_BIT(16) //low-power mode disabled
#define SDMMC_CLKEN_ENABLE BIT(0)
#define SDMMC_CLKEN_DISABLE RK_CLEAR_BIT(16) //clock disabled
#define SDMMC_CLKEN_DISABLE RK_CLEAR_BIT(0) //clock disabled
/* time-out register defines(base+0x14) */
#define SDMMC_TMOUT_DATA(n) _SBF(8, (n))
@@ -186,8 +239,9 @@
#define SDMMC_STAUTS_FIFO_EMPTY BIT(2) //FIFO is empty status
/* Status register defines */
#define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FF)//fifo_count, numbers of filled locations in FIFO
#define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF)//fifo_count, numbers of filled locations in FIFO
#define SDMMC_FIFO_SZ 32
#define PIO_DATA_SHIFT 2
/* FIFO Register (base + 0x4c)*/
@@ -308,13 +362,239 @@
#define SDM_WAIT_FOR_CMDSTART_TIMEOUT (12)
#define SDM_WAIT_FOR_FIFORESET_TIMEOUT (13)
#define FALSE 0
#define TRUE 1
#define DEBOUNCE_TIME (25) //uint is ms, recommend 5--25ms
#if defined(CONFIG_ARCH_RK29)
#define SDMMC_USE_INT_UNBUSY 0
#else
#define SDMMC_USE_INT_UNBUSY 0///1
#endif
/*
** You can set the macro to true, if some module wants to use this feature, which is about SDIO suspend-resume.
** As the following example.
** added by xbw at 2013-05-08
*/
#if defined(CONFIG_MTK_COMBO_DRIVER_VERSION_JB2)
#define RK_SDMMC_USE_SDIO_SUSPEND_RESUME 1
#else
#define RK_SDMMC_USE_SDIO_SUSPEND_RESUME 0
#endif
#define RK29_SDMMC_ERROR_FLAGS (SDMMC_INT_FRUN | SDMMC_INT_HLE )
#if defined(CONFIG_SDMMC0_RK29_SDCARD_DET_FROM_GPIO)
#if SDMMC_USE_INT_UNBUSY
#define RK29_SDMMC_INTMASK_USEDMA (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | SDMMC_INT_UNBUSY |RK29_SDMMC_ERROR_FLAGS )
#define RK29_SDMMC_INTMASK_USEIO (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | SDMMC_INT_UNBUSY |RK29_SDMMC_ERROR_FLAGS | SDMMC_INT_TXDR | SDMMC_INT_RXDR )
#else
#define RK29_SDMMC_INTMASK_USEDMA (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | RK29_SDMMC_ERROR_FLAGS )
#define RK29_SDMMC_INTMASK_USEIO (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | RK29_SDMMC_ERROR_FLAGS | SDMMC_INT_TXDR | SDMMC_INT_RXDR )
#endif
#else
#if SDMMC_USE_INT_UNBUSY
#define RK29_SDMMC_INTMASK_USEDMA (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | SDMMC_INT_UNBUSY |RK29_SDMMC_ERROR_FLAGS | SDMMC_INT_CD)
#define RK29_SDMMC_INTMASK_USEIO (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | SDMMC_INT_UNBUSY |RK29_SDMMC_ERROR_FLAGS | SDMMC_INT_CD| SDMMC_INT_TXDR | SDMMC_INT_RXDR )
#else
#define RK29_SDMMC_INTMASK_USEDMA (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | RK29_SDMMC_ERROR_FLAGS | SDMMC_INT_CD)
#define RK29_SDMMC_INTMASK_USEIO (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | RK29_SDMMC_ERROR_FLAGS | SDMMC_INT_CD| SDMMC_INT_TXDR | SDMMC_INT_RXDR )
#endif
#endif
#define RK29_SDMMC_SEND_START_TIMEOUT 3000 //The time interval from the time SEND_CMD to START_CMD_BIT cleared.
#define RK29_ERROR_PRINTK_INTERVAL 200 //The time interval between the two printk for the same error.
#define RK29_SDMMC_WAIT_DTO_INTERNVAL 4500 //The time interval from the CMD_DONE_INT to DTO_INT
#define RK29_SDMMC_REMOVAL_DELAY 2000 //The time interval from the CD_INT to detect_timer react.
//#define RK29_SDMMC_VERSION "Ver.6.00 The last modify date is 2013-08-02"
#if !defined(CONFIG_USE_SDMMC0_FOR_WIFI_DEVELOP_BOARD)
#define RK29_CTRL_SDMMC_ID 0 //mainly used by SDMMC
#define RK29_CTRL_SDIO1_ID 1 //mainly used by sdio-wifi
#define RK29_CTRL_SDIO2_ID 2 //mainly used by sdio-card
#else
#define RK29_CTRL_SDMMC_ID 5
#define RK29_CTRL_SDIO1_ID 1
#define RK29_CTRL_SDIO2_ID 2
#endif
#define SDMMC_CLOCK_TEST 0
#define RK29_SDMMC_NOTIFY_REMOVE_INSERTION /* use sysfs to notify the removal or insertion of sd-card*/
//#define RK29_SDMMC_LIST_QUEUE /* use list-queue for multi-card*/
//support Internal DMA
#if 0 //Sometime in the future to enable
#define DRIVER_SDMMC_USE_IDMA 1
#else
#define DRIVER_SDMMC_USE_IDMA 0
#endif
enum {
EVENT_CMD_COMPLETE = 0,
EVENT_DATA_COMPLETE,
EVENT_DATA_UNBUSY,
EVENT_DATA_ERROR,
EVENT_XFER_ERROR
};
enum rk29_sdmmc_state {
STATE_IDLE = 0,
STATE_SENDING_CMD,
STATE_DATA_BUSY,
STATE_DATA_UNBUSY,
STATE_DATA_END,
STATE_SENDING_STOP,
};
struct rk29_sdmmc_dma_info {
enum dma_ch chn;
char *name;
struct rk29_dma_client client;
};
static struct rk29_sdmmc_dma_info rk29_sdmmc_dma_infos[]= {
{
.chn = DMACH_SDMMC,
.client = {
.name = "rk29-dma-sdmmc0",
}
},
{
.chn = DMACH_SDIO,
.client = {
.name = "rk29-dma-sdio1",
}
},
{
.chn = DMACH_EMMC,
.client = {
.name = "rk29-dma-sdio2",
}
},
};
/* Interrupt Information */
typedef struct TagSDC_INT_INFO
{
u32 transLen; //the length of data sent.
u32 desLen; //the total length of the all data.
u32 *pBuf; //the data buffer for interrupt read or write.
}SDC_INT_INFO_T;
struct rk29_sdmmc {
spinlock_t lock;
void __iomem *regs;
struct clk *clk;
struct mmc_request *mrq;
struct mmc_request *new_mrq;
struct mmc_command *cmd;
struct mmc_data *data;
struct scatterlist *sg;
unsigned int pio_offset;
dma_addr_t dma_addr;;
unsigned int use_dma:1;
char dma_name[8];
u32 cmd_status;
u32 data_status;
u32 stop_cmdr;
u32 old_div;
u32 cmdr; //the value setted into command-register
u32 dodma; //sign the DMA used for transfer.
u32 errorstep;//record the error point.
int timeout_times; //use to force close the sdmmc0 when the timeout_times exceeds the limit.
u32 *pbuf;
SDC_INT_INFO_T intInfo;
struct rk29_sdmmc_dma_info dma_info;
int irq;
int error_times;
u32 old_cmd;
struct tasklet_struct tasklet;
unsigned long pending_events;
unsigned long completed_events;
enum rk29_sdmmc_state state;
#ifdef RK29_SDMMC_LIST_QUEUE
struct list_head queue;
struct list_head queue_node;
#endif
u32 bus_hz;
struct platform_device *pdev;
struct mmc_host *mmc;
u32 ctype;
unsigned int clock;
unsigned long flags;
#define RK29_SDMMC_CARD_PRESENT 0
int id;
struct timer_list detect_timer;
struct timer_list request_timer; //the timer for INT_CMD_DONE
struct timer_list DTO_timer; //the timer for INT_DTO
struct mmc_command stopcmd;
struct rksdmmc_gpio det_pin;
/* flag for current bus settings */
u32 bus_mode;
unsigned int oldstatus;
unsigned int complete_done;
unsigned int retryfunc;
int gpio_irq;
int gpio_power_en;
int gpio_power_en_level;
struct delayed_work work;
#ifdef CONFIG_RK29_SDIO_IRQ_FROM_GPIO
unsigned int sdio_INT_gpio;
unsigned int sdio_irq;
unsigned long trigger_level;
#endif
#if defined(CONFIG_SDMMC0_RK29_WRITE_PROTECT) || defined(CONFIG_SDMMC1_RK29_WRITE_PROTECT)
int write_protect;
int protect_level;
#endif
bool irq_state;
void (*set_iomux)(int device_id, unsigned int bus_width);
/* FIFO push and pull */
int data_shift;
void (*push_data)(struct rk29_sdmmc *host, void *buf, int cnt);
void (*pull_data)(struct rk29_sdmmc *host, void *buf, int cnt);
};
#ifdef RK29_SDMMC_NOTIFY_REMOVE_INSERTION
static struct rk29_sdmmc *globalSDhost[3];
#endif
#define rk29_sdmmc_test_and_clear_pending(host, event) \
test_and_clear_bit(event, &host->pending_events)
#define rk29_sdmmc_test_pending(host, event) \
test_bit(event, &host->pending_events)
#define rk29_sdmmc_test_completed(host, event) \
test_bit(event, &host->completed_events)
#define rk29_sdmmc_set_completed(host, event) \
set_bit(event, &host->completed_events)
#define rk29_sdmmc_set_pending(host, event) \
set_bit(event, &host->pending_events)
#endif