#include <linux/stat.h>
#include <linux/delay.h>
#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/version.h>
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/card.h>
#include <mach/board.h>
-#include <mach/rk29_iomap.h>
+#include <mach/io.h>
#include <mach/gpio.h>
#include <mach/iomux.h>
#include <asm/dma.h>
-#include <mach/rk29-dma-pl330.h>
+#include <mach/dma-pl330.h>
#include <asm/scatterlist.h>
#include "rk29_sdmmc.h"
#define RK29_SDMMC_xbw_Debug 0
#if RK29_SDMMC_xbw_Debug
-int debug_level = 7;
+int debug_level = 5;
#define xbwprintk(n, format, arg...) \
if (n <= debug_level) { \
printk(format,##arg); \
#define xbwprintk(n, arg...)
#endif
-#define RK29_SDMMC_ERROR_FLAGS (SDMMC_INT_FRUN | SDMMC_INT_RTO | SDMMC_INT_HLE )
+#define RK29_SDMMC_ERROR_FLAGS (SDMMC_INT_FRUN | SDMMC_INT_HLE )
+#if defined(CONFIG_ARCH_RK29)
#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 )
+#elif defined(CONFIG_ARCH_RK30)
+#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 )
+#endif
-#define RK29_SDMMC_SEND_START_TIMEOUT 2000 //The time interval from the time SEND_CMD to START_CMD_BIT cleared.
+#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 1500 //The time interval from the CMD_DONE_INT to DTO_INT
+#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.2.04 The last modify date is 2011-08-24,modifyed by XBW."
+#define RK29_SDMMC_VERSION "Ver.3.03 The last modify date is 2012-03-23,modifyed by XBW."
+#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*/
struct rk29_sdmmc {
spinlock_t lock;
- spinlock_t request_lock;
void __iomem *regs;
struct clk *clk;
unsigned int oldstatus;
unsigned int complete_done;
+ unsigned int retryfunc;
+
#ifdef CONFIG_PM
int gpio_irq;
int gpio_det;
#endif
+
+#if defined(CONFIG_SDMMC0_RK29_WRITE_PROTECT) || defined(CONFIG_SDMMC1_RK29_WRITE_PROTECT)
+ int write_protect;
+#endif
+
+ void (*set_iomux)(int device_id, unsigned int bus_width);
+
};
#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_set_completed(host, event) \
set_bit(event, &host->completed_events)
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);
static void rk29_sdmmc_write(unsigned char __iomem *regbase, unsigned int regOff,unsigned int val)
{
return count;
}
- spin_lock(&host->lock);
-
//envalue the address of host base on input-parameter.
if( !strncmp(buf,"sd-" , strlen("sd-")) )
{
- host = (struct rk29_sdmmc *)globalSDhost[RK29_CTRL_SDMMC_ID];
+ host = (struct rk29_sdmmc *)globalSDhost[0];
if(!host)
{
printk("%s..%d.. fail to call progress_store because the host is null. ==xbw==\n",__FUNCTION__,__LINE__);
- goto progress_store_out;
+ return count;
}
}
else if( !strncmp(buf,"sdio1-" , strlen("sdio1-")) )
if(!host)
{
printk("%s..%d.. fail to call progress_store because the host-sdio1 is null. ==xbw==\n",__FUNCTION__,__LINE__);
- goto progress_store_out;
+ return count;
}
}
else if( !strncmp(buf,"sdio2-" , strlen("sdio2-")) )
if(!host)
{
printk("%s..%d.. fail to call progress_store because the host-sdio2 is null. ==xbw==\n",__FUNCTION__,__LINE__);
- goto progress_store_out;
+ return count;
}
}
else
{
printk("%s..%d.. You want to use sysfs for SDMMC but input-parameter is wrong.====xbw====\n",__FUNCTION__,__LINE__);
- goto progress_store_out;//return count;
+ return count;
}
+ spin_lock(&host->lock);
+
if(strncmp(buf,oldbuf , strlen(buf)))
{
printk(".%d.. MMC0 receive the message %s from VOLD.====xbw[%s]====\n", __LINE__, buf, host->dma_name);
* insert card state-change: No-Media ==> Pending ==> Idle-Unmounted ==> Checking ==>Mounted
* remove card state-change: Unmounting ==> Idle-Unmounted ==> No-Media
*/
+ #if !defined(CONFIG_USE_SDMMC0_FOR_WIFI_DEVELOP_BOARD)
if(RK29_CTRL_SDMMC_ID == host->pdev->id)
{
+#if 1 //to wirte log in log-file-system during the stage of umount. Modifyed by xbw at 2011-12-26
if(!strncmp(buf, "sd-Unmounting", strlen("sd-Unmounting")))
{
if(unmounting_times++%10 == 0)
printk(".%d.. MMC0 receive the message Unmounting(waitTimes=%d) from VOLD.====xbw[%s]====\n", \
__LINE__, unmounting_times, host->dma_name);
}
- host->mmc->re_initialized_flags = 0;
- mod_timer(&host->detect_timer, jiffies + msecs_to_jiffies(RK29_SDMMC_REMOVAL_DELAY));
+
+ if(0 == host->mmc->re_initialized_flags)
+ mod_timer(&host->detect_timer, jiffies + msecs_to_jiffies(RK29_SDMMC_REMOVAL_DELAY*2));
+ }
+ else if(!strncmp(buf, "sd-Idle-Unmounted", strlen("sd-Idle-Unmounted")))
+ {
+ if(0 == host->mmc->re_initialized_flags)
+ mod_timer(&host->detect_timer, jiffies + msecs_to_jiffies(RK29_SDMMC_REMOVAL_DELAY*2));
}
+#else
+ if(!strncmp(buf, "sd-Unmounting", strlen("sd-Unmounting")))
+ {
+ if(unmounting_times++%10 == 0)
+ {
+ printk(".%d.. MMC0 receive the message Unmounting(waitTimes=%d) from VOLD.====xbw[%s]====\n", \
+ __LINE__, unmounting_times, host->dma_name);
+ }
+ host->mmc->re_initialized_flags = 0;
+ mod_timer(&host->detect_timer, jiffies + msecs_to_jiffies(RK29_SDMMC_REMOVAL_DELAY*2));
+ }
+#endif
else if( !strncmp(buf, "sd-No-Media", strlen("sd-No-Media")))
{
printk(".%d.. MMC0 receive the message No-Media from VOLD. waitTimes=%d ====xbw[%s]====\n" ,\
else if( !strncmp(buf,"sd-reset" , strlen("sd-reset")) )
{
printk(".%d.. Now manual reset for SDMMC0. ====xbw[%s]====\n",__LINE__, host->dma_name);
+ rk29_sdmmc_hw_init(host);
mmc_detect_change(host->mmc, 0);
}
else if( !strncmp(buf, "sd-regs", strlen("sd-regs")))
}
}
+ #else
+ if(0 == host->pdev->id)
+ {
+ if( !strncmp(buf,"sd-reset" , strlen("sd-reset")) )
+ {
+ printk(".%d.. Now manual reset for SDMMC0. ====xbw[%s]====\n",__LINE__, host->dma_name);
+ rk29_sdmmc_hw_init(host);
+ mmc_detect_change(host->mmc, 0);
+ }
+ else if( !strncmp(buf, "sd-regs", strlen("sd-regs")))
+ {
+ printk(".%d.. Now printk the register of SDMMC0. ====xbw[%s]====\n",__LINE__, host->dma_name);
+ rk29_sdmmc_regs_printk(host);
+ }
+ }
+ #endif
else if(RK29_CTRL_SDIO1_ID == host->pdev->id)
{
if( !strncmp(buf, "sdio1-regs", strlen("sdio1-regs")))
else if( !strncmp(buf,"sdio1-reset" , strlen("sdio1-reset")) )
{
printk(".%d.. Now manual reset for SDMMC1. ====xbw[%s]====\n",__LINE__, host->dma_name);
+ rk29_sdmmc_hw_init(host);
mmc_detect_change(host->mmc, 0);
}
}
else if( !strncmp(buf,"sdio2-reset" , strlen("sdio2-reset")) )
{
printk(".%d.. Now manual reset for SDMMC2. ====xbw[%s]====\n",__LINE__, host->dma_name);
+ rk29_sdmmc_hw_init(host);
mmc_detect_change(host->mmc, 0);
}
}
-progress_store_out:
spin_unlock(&host->lock);
return count;
{
.attr = {
.name = "rescan",
- .mode = 0777},
+ .mode = 0764},
.show = NULL,
.store = rk29_sdmmc_progress_store,
};
return cmdr;
}
+void rk29_sdmmc_set_frq(struct rk29_sdmmc *host)
+{
+ struct mmc_host *mmchost = platform_get_drvdata(host->pdev);
+ struct mmc_card *card;
+ struct mmc_ios *ios;
+ unsigned int max_dtr;
+
+ extern void mmc_set_clock(struct mmc_host *host, unsigned int hz);
+
+ if(!mmchost)
+ return;
+
+ card = (struct mmc_card *)mmchost->card;
+ ios = ( struct mmc_ios *)&mmchost->ios;
+
+ if(!card || !ios)
+ return;
+
+ if(MMC_POWER_ON == ios->power_mode)
+ return;
+
+ max_dtr = (unsigned int)-1;
+
+ if (mmc_card_highspeed(card))
+ {
+ if (max_dtr > card->ext_csd.hs_max_dtr)
+ max_dtr = card->ext_csd.hs_max_dtr;
+
+ }
+ else if (max_dtr > card->csd.max_dtr)
+ {
+ if(MMC_TYPE_SD == card->type)
+ {
+ max_dtr = (card->csd.max_dtr > SD_FPP_FREQ) ? SD_FPP_FREQ : (card->csd.max_dtr);
+ }
+ else
+ {
+ max_dtr = (card->csd.max_dtr > MMC_FPP_FREQ) ? MMC_FPP_FREQ : (card->csd.max_dtr);
+ }
+ }
+
+ xbwprintk(7, "%s..%d... call mmc_set_clock() set clk=%d ===xbw[%s]===\n", \
+ __FUNCTION__, __LINE__, max_dtr, host->dma_name);
+
+
+ mmc_set_clock(mmchost, max_dtr);
+
+}
+
static int rk29_sdmmc_start_command(struct rk29_sdmmc *host, struct mmc_command *cmd, u32 cmd_flags)
{
- int tmo = RK29_SDMMC_SEND_START_TIMEOUT*2;
+ int tmo = RK29_SDMMC_SEND_START_TIMEOUT*10;//wait 60ms cycle.
host->cmd = cmd;
host->old_cmd = cmd->opcode;
-
+ host->errorstep = 0;
+ host->pending_events = 0;
+ host->completed_events = 0;
+ host->complete_done = 0;
+ host->retryfunc = 0;
+ host->cmd_status = 0;
+
+ if(MMC_STOP_TRANSMISSION != cmd->opcode)
+ {
+ host->data_status = 0;
+ }
+
+ if(RK29_CTRL_SDMMC_ID == host->pdev->id)
+ {
+ //adjust the frequency division control of SDMMC0 every time.
+ rk29_sdmmc_set_frq(host);
+ }
+
rk29_sdmmc_write(host->regs, SDMMC_CMDARG, cmd->arg); // write to SDMMC_CMDARG register
rk29_sdmmc_write(host->regs, SDMMC_CMD, cmd_flags | SDMMC_CMD_START); // write to SDMMC_CMD register
xbwprintk(5, "\n%s..%d..************.start cmd=%d, arg=0x%x ********=====xbw[%s]=======\n", \
__FUNCTION__, __LINE__, cmd->opcode, cmd->arg, host->dma_name);
+ host->mmc->doneflag = 1;
+
/* wait until CIU accepts the command */
while (--tmo && (rk29_sdmmc_read(host->regs, SDMMC_CMD) & SDMMC_CMD_START))
{
host->errorstep = 0x1;
return SDM_WAIT_FOR_CMDSTART_TIMEOUT;
}
-
+ host->errorstep = 0xfe;
+
return SDM_SUCCESS;
}
static int rk29_sdmmc_wait_unbusy(struct rk29_sdmmc *host)
{
- int time_out = 250000; //max is 250ms
+ int time_out = 500000;//250000; //max is 250ms; //adapt the value to the sick card. modify at 2011-10-08
- while (rk29_sdmmc_read(host->regs, SDMMC_STATUS) & SDMMC_STAUTS_DATA_BUSY)
+ while (rk29_sdmmc_read(host->regs, SDMMC_STATUS) & (SDMMC_STAUTS_DATA_BUSY|SDMMC_STAUTS_MC_BUSY))
{
udelay(1);
time_out--;
return SDM_SUCCESS;
}
-static void send_stop_cmd(struct rk29_sdmmc *host)
-{
- mod_timer(&host->request_timer, jiffies + msecs_to_jiffies(RK29_SDMMC_SEND_START_TIMEOUT+250));
-
- host->stopcmd.opcode = MMC_STOP_TRANSMISSION;
- host->stopcmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;;
- host->stopcmd.arg = 0;
- host->stopcmd.data = NULL;
- host->stopcmd.mrq = NULL;
- host->stopcmd.retries = 0;
- host->stopcmd.error = 0;
- if(host->mrq && host->mrq->stop)
- {
- host->mrq->stop->error = 0;
- }
-
- host->cmdr = rk29_sdmmc_prepare_command(&host->stopcmd);
- rk29_sdmmc_start_command(host, &host->stopcmd, host->cmdr);
-}
-
static void rk29_sdmmc_dma_cleanup(struct rk29_sdmmc *host)
{
if (host->data)
rk29_sdmmc_write(host->regs, SDMMC_CTRL, value);
}
+static void send_stop_cmd(struct rk29_sdmmc *host)
+{
+ int ret;
+
+ if(host->mrq->cmd->error)
+ {
+ //stop DMA
+ if(host->dodma)
+ {
+ rk29_sdmmc_stop_dma(host);
+ rk29_sdmmc_control_host_dma(host, FALSE);
+
+ host->dodma = 0;
+ }
+
+ ret= rk29_sdmmc_clear_fifo(host);
+ if(SDM_SUCCESS != ret)
+ {
+ xbwprintk(3, "%s..%d.. clear fifo error before call CMD_STOP ====xbw[%s]====\n", \
+ __FUNCTION__, __LINE__, host->dma_name);
+ }
+ }
+
+ mod_timer(&host->request_timer, jiffies + msecs_to_jiffies(RK29_SDMMC_SEND_START_TIMEOUT+1500));
+
+ host->stopcmd.opcode = MMC_STOP_TRANSMISSION;
+ host->stopcmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;;
+ host->stopcmd.arg = 0;
+ host->stopcmd.data = NULL;
+ host->stopcmd.mrq = NULL;
+ host->stopcmd.retries = 0;
+ host->stopcmd.error = 0;
+ if(host->mrq && host->mrq->stop)
+ {
+ host->mrq->stop->error = 0;
+ }
+
+ host->cmdr = rk29_sdmmc_prepare_command(&host->stopcmd);
+
+ ret = rk29_sdmmc_start_command(host, &host->stopcmd, host->cmdr);
+ if(SDM_SUCCESS != ret)
+ {
+ rk29_sdmmc_start_error(host);
+
+ host->state = STATE_IDLE;
+ host->complete_done = 4;
+ }
+}
+
/* This function is called by the DMA driver from tasklet context. */
static void rk29_sdmmc_dma_complete(void *arg, int size, enum rk29_dma_buffresult result)
}
else
{
- xbwprintk(3, "%s..%d... trace data, ======xbw=[%s]====\n", __FUNCTION__, __LINE__, host->dma_name);
+ xbwprintk(7, "%s..%d... trace data, ======xbw=[%s]====\n", __FUNCTION__, __LINE__, host->dma_name);
output = rk29_sdmmc_submit_data_dma(host, data);
if(output)
{
host->dodma = 0;
- printk("%s..%d... CMD%d setupDMA failure!!!!! ==xbw[%s]==\n", \
- __FUNCTION__, __LINE__, host->cmd->opcode, host->dma_name);
+ printk("%s..%d... CMD%d setupDMA failure!!!!! pre_cmd=%d ==xbw[%s]==\n", \
+ __FUNCTION__, __LINE__, host->cmd->opcode,host->old_cmd, host->dma_name);
host->errorstep = 0x81;
rk29_sdmmc_write(host->regs, SDMMC_BYTCNT,data->blksz*data->blocks);
rk29_sdmmc_write(host->regs, SDMMC_BLKSIZ,data->blksz);
- xbwprintk(3, "%s..%d... trace data, CMD%d, data->blksz=%d, data->blocks=%d ======xbw=[%s]====\n", \
- __FUNCTION__, __LINE__, host->cmd->opcode,data->blksz, data->blocks, host->dma_name);
+ xbwprintk(6, "%s..%d..CMD%d(arg=0x%x), data->blksz=%d, data->blocks=%d ==xbw=[%s]==\n", \
+ __FUNCTION__, __LINE__, host->cmd->opcode,host->cmd->arg,data->blksz, data->blocks, host->dma_name);
if (data->flags & MMC_DATA_WRITE)
{
host->cmdr |= (SDMMC_CMD_DAT_WRITE | SDMMC_CMD_DAT_EXP);
- xbwprintk(3, "%s..%d... write data, len=%d ======xbw=[%s]====\n", \
+ xbwprintk(7, "%s..%d... write data, len=%d ======xbw=[%s]====\n", \
__FUNCTION__, __LINE__, data->blksz*data->blocks, host->dma_name);
ret = rk29_sdmmc_prepare_write_data(host, data);
else
{
host->cmdr |= (SDMMC_CMD_DAT_READ | SDMMC_CMD_DAT_EXP);
- xbwprintk(3, "%s..%d... read data len=%d ======xbw=[%s]====\n", \
+ xbwprintk(7, "%s..%d... read data len=%d ======xbw=[%s]====\n", \
__FUNCTION__, __LINE__, data->blksz*data->blocks, host->dma_name);
ret = rk29_sdmmc_prepare_read_data(host, data);
static int sdmmc_send_cmd_start(struct rk29_sdmmc *host, unsigned int cmd)
{
- int tmo = 1000;
+ int tmo = RK29_SDMMC_SEND_START_TIMEOUT*10;//wait 60ms cycle.
rk29_sdmmc_write(host->regs, SDMMC_CMD, SDMMC_CMD_START | cmd);
- while (--tmo && readl(host->regs + SDMMC_CMD) & SDMMC_CMD_START)
+ while (--tmo && (rk29_sdmmc_read(host->regs, SDMMC_CMD) & SDMMC_CMD_START))
{
- cpu_relax();
+ udelay(2);
}
if(!tmo)
static int rk29_sdmmc_get_cd(struct mmc_host *mmc)
{
struct rk29_sdmmc *host = mmc_priv(mmc);
- u32 cdetect;
+ u32 cdetect=1;
-#ifdef CONFIG_PM
- if(host->gpio_det == INVALID_GPIO)
- return 1;
-#endif
+ switch(host->pdev->id)
+ {
+ case 0:
+ {
+ #ifdef CONFIG_PM
+ if(host->gpio_det == INVALID_GPIO)
+ return 1;
+ #endif
+
+ cdetect = rk29_sdmmc_read(host->regs, SDMMC_CDETECT);
- cdetect = rk29_sdmmc_read(host->regs, SDMMC_CDETECT);
+ cdetect = (cdetect & SDMMC_CARD_DETECT_N)?0:1;
+
+ break;
+ }
- return (cdetect & SDMMC_CARD_DETECT_N)?0:1;
+ case 1:
+ {
+ #if defined(CONFIG_USE_SDMMC1_FOR_WIFI_DEVELOP_BOARD)
+ cdetect = 1;
+ #else
+ cdetect = test_bit(RK29_SDMMC_CARD_PRESENT, &host->flags)?1:0;
+ #endif
+ break;
+ }
+
+ default:
+ cdetect = 1;
+ break;
+
+ }
+
+ return cdetect;
}
}
/* reset */
+#if defined(CONFIG_ARCH_RK29)
rk29_sdmmc_write(host->regs, SDMMC_CTRL,(SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET ));
-
+#elif defined(CONFIG_ARCH_RK30)
+ rk29_sdmmc_write(host->regs, SDMMC_CTRL,(SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET));
+#endif
timeOut = 1000;
value = rk29_sdmmc_read(host->regs, SDMMC_CTRL);
while (( value & (SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_RESET)) && (timeOut > 0))
}
else
{
- rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEDMA | SDMMC_INT_SDIO);
+ if(0== host->pdev->id)
+ {
+ #if !defined(CONFIG_USE_SDMMC0_FOR_WIFI_DEVELOP_BOARD)
+ rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEDMA | SDMMC_INT_SDIO);
+ #else
+ rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEDMA);
+ #endif
+ }
+ else if(1== host->pdev->id)
+ {
+ #if !defined(CONFIG_USE_SDMMC1_FOR_WIFI_DEVELOP_BOARD)
+ rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEDMA | SDMMC_INT_SDIO);
+ #else
+ rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEDMA);
+ #endif
+ }
+ else
+ {
+ rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEDMA | SDMMC_INT_SDIO);
+ }
}
}
else
}
else
{
- rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEIO | SDMMC_INT_SDIO);
+ if(0== host->pdev->id)
+ {
+ #if !defined(CONFIG_USE_SDMMC0_FOR_WIFI_DEVELOP_BOARD)
+ rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEIO | SDMMC_INT_SDIO);
+ #else
+ rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEIO);
+ #endif
+ }
+ else if(1== host->pdev->id)
+ {
+ #if !defined(CONFIG_USE_SDMMC1_FOR_WIFI_DEVELOP_BOARD)
+ rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEIO | SDMMC_INT_SDIO);
+ #else
+ rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEIO);
+ #endif
+ }
+ else
+ {
+ rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEDMA | SDMMC_INT_SDIO);
+ }
}
}
tmo = 1000;
while (--tmo && (rk29_sdmmc_read(host->regs, SDMMC_CMD) & SDMMC_CMD_START))
{
- cpu_relax();
+ udelay(1);//cpu_relax();
}
if(!tmo)
{
if(RK29_CTRL_SDMMC_ID == host->pdev->id)
{
//SDMMC use low-power mode
+ #if SDMMC_CLOCK_TEST
if (enable)
{
- value = (SDMMC_CLKEN_LOW_PWR | SDMMC_CLKEN_ENABLE);
+ value = (SDMMC_CLKEN_ENABLE);
}
else
{
- value = (SDMMC_CLKEN_LOW_PWR | SDMMC_CLKEN_DISABLE);
+ value = (SDMMC_CLKEN_DISABLE);
+ }
+
+ #else
+ {
+ if (enable)
+ {
+ value = (SDMMC_CLKEN_LOW_PWR | SDMMC_CLKEN_ENABLE);
+ }
+ else
+ {
+ value = (SDMMC_CLKEN_LOW_PWR | SDMMC_CLKEN_DISABLE);
+ }
}
+ #endif
}
else
{
return SDM_SUCCESS;
Error_exit:
- printk("\n%s....%d.. control clock fail!!! Enable=%d, ret=%d ===xbw[%s]====\n",\
+ printk("\n%s....%d.. control clock fail!!! Enable=%d, ret=0x%x ===xbw[%s]====\n",\
__FILE__,__LINE__,enable,ret, host->dma_name);
return ret;
tmo = 1000;
while (--tmo && (rk29_sdmmc_read(host->regs, SDMMC_CMD) & SDMMC_CMD_START))
{
- cpu_relax();
+ udelay(1);//cpu_relax();
}
if(!tmo)
{
SetFreq_error:
- printk("%s..%s..%d.. change division fail, ret=%d !!! ====xbw[%s]====\n",\
- __FILE__, __FUNCTION__,__LINE__,ret, host->dma_name);
+ printk("%s..%d.. change division fail, errorStep=0x%x,ret=%d !!! ====xbw[%s]====\n",\
+ __FILE__, __LINE__,host->errorstep,ret, host->dma_name);
return ret;
}
-
-
-static int rk29_sdmmc_hw_init(struct rk29_sdmmc *host)
+int rk29_sdmmc_hw_init(void *data)
{
+ struct rk29_sdmmc *host = (struct rk29_sdmmc *)data;
+
+ //set the iomux
+ host->ctype = SDMMC_CTYPE_1BIT;
+ host->set_iomux(host->pdev->id, host->ctype);
+
/* reset controller */
rk29_sdmmc_reset_controller(host);
+
rk29_sdmmc_change_clk_div(host, FOD_FREQ);
return SDM_SUCCESS;
-int rk29_sdmmc_set_iomux(struct rk29_sdmmc *host)
-{
- #if 0
- switch (host->busWidth)
- {
- case
- rk29_mux_api_set(GPIO1D1_SDMMC0CMD_NAME, GPIO1H_SDMMC0_CMD);
- rk29_mux_api_set(GPIO1D0_SDMMC0CLKOUT_NAME, GPIO1H_SDMMC0_CLKOUT);
- rk29_mux_api_set(GPIO1D2_SDMMC0DATA0_NAME, GPIO1H_SDMMC0_DATA0);
- rk29_mux_api_set(GPIO1D3_SDMMC0DATA1_NAME, GPIO1H_SDMMC0_DATA1);
- rk29_mux_api_set(GPIO1D4_SDMMC0DATA2_NAME, GPIO1H_SDMMC0_DATA2);
- }
- #endif
-
- return 0;
-}
-
int rk29_sdmmc_set_buswidth(struct rk29_sdmmc *host)
{
//int ret;
default:
return SDM_PARAM_ERROR;
}
- rk29_sdmmc_set_iomux(host);
+
+ host->set_iomux(host->pdev->id, host->ctype);
/* Set the current bus width */
rk29_sdmmc_write(host->regs, SDMMC_CTYPE, host->ctype);
}
-void rk29_sdmmc_set_frq(struct rk29_sdmmc *host)
-{
- struct mmc_host *mmchost = platform_get_drvdata(host->pdev);
- struct mmc_card *card;
- struct mmc_ios *ios;
- unsigned int max_dtr;
-
- extern void mmc_set_clock(struct mmc_host *host, unsigned int hz);
-
- if(!mmchost)
- return;
-
- card = (struct mmc_card *)mmchost->card;
- ios = ( struct mmc_ios *)&mmchost->ios;
-
- if(!card && !ios)
- return;
-
- if(MMC_POWER_ON == ios->power_mode)
- return;
-
- max_dtr = (unsigned int)-1;
-
- if (mmc_card_highspeed(card))
- {
- if (max_dtr > card->ext_csd.hs_max_dtr)
- max_dtr = card->ext_csd.hs_max_dtr;
-
- }
- else if (max_dtr > card->csd.max_dtr)
- {
- if(MMC_TYPE_SD == card->type)
- {
- max_dtr = (card->csd.max_dtr > SD_FPP_FREQ) ? SD_FPP_FREQ : (card->csd.max_dtr);
- }
- else
- {
- max_dtr = (card->csd.max_dtr > MMC_FPP_FREQ) ? MMC_FPP_FREQ : (card->csd.max_dtr);
- }
- }
-
- xbwprintk(7, "%s..%d... call mmc_set_clock() set clk=%d ===xbw[%s]===\n", \
- __FUNCTION__, __LINE__, max_dtr, host->dma_name);
-
-
- mmc_set_clock(mmchost, max_dtr);
-
-}
-
static void rk29_sdmmc_dealwith_timeout(struct rk29_sdmmc *host)
{
+ if(0 == host->mmc->doneflag)
+ return; //not to generate error flag if the command has been over.
+
switch(host->state)
{
case STATE_IDLE:
static void rk29_sdmmc_INT_CMD_DONE_timeout(unsigned long host_data)
{
struct rk29_sdmmc *host = (struct rk29_sdmmc *) host_data;
+ unsigned long iflags;
+
+ spin_lock_irqsave(&host->lock, iflags);
if(STATE_SENDING_CMD == host->state)
{
rk29_sdmmc_dealwith_timeout(host);
}
+ spin_unlock_irqrestore(&host->lock, iflags);
}
static void rk29_sdmmc_INT_DTO_timeout(unsigned long host_data)
{
struct rk29_sdmmc *host = (struct rk29_sdmmc *) host_data;
+ unsigned long iflags;
+
+ spin_lock_irqsave(&host->lock, iflags);
if( (host->cmdr & SDMMC_CMD_DAT_EXP) && (STATE_DATA_BUSY == host->state))
rk29_sdmmc_dealwith_timeout(host);
}
+ spin_unlock_irqrestore(&host->lock, iflags);
+
}
mrq = host->new_mrq;
cmd = mrq->cmd;
cmd->error = 0;
- host->complete_done = 0;
cmdr = rk29_sdmmc_prepare_command(cmd);
ret = SDM_SUCCESS;
printk("%s..Error happen in CMD_PRV_DAT_WAIT. STATUS-reg=0x%x ===xbw[%s]===\n", \
__FUNCTION__, rk29_sdmmc_read(host->regs, SDMMC_STATUS),host->dma_name);
}
+ rk29_sdmmc_clear_fifo(host);
goto start_request_Err;
}
}
host->cmdr = cmdr;
host->cmd = cmd;
- host->pending_events = 0;
- host->completed_events = 0;
host->data_status = 0;
host->data = NULL;
host->errorstep = 0;
host->dodma = 0;
- if(RK29_CTRL_SDMMC_ID == host->pdev->id)
- {
- //adjust the frequency division control of SDMMC0 every time.
- rk29_sdmmc_set_frq(host);
- }
-
+
//setting for the data
rk29_sdmmc_submit_data(host, mrq->data);
-
+ host->errorstep = 0xff;
xbwprintk(7, "%s..%d... CMD%d begin to call rk29_sdmmc_start_command() ===xbw[%s]===\n", \
__FUNCTION__, __LINE__ , cmd->opcode,host->dma_name);
goto start_request_Err;
}
+ host->errorstep = 0xfd;
xbwprintk(7, "%s..%d... CMD=%d, wait for INT_CMD_DONE, ret=%d , \n \
host->state=0x%x, cmdINT=0x%x \n host->pendingEvent=0x%lu, host->completeEvents=0x%lu =========xbw=[%s]=====\n\n",\
}
host->state = STATE_IDLE; //modifyed by xbw at 2011-08-15
- spin_unlock_irqrestore(&host->lock, iflags);
- mmc_request_done(host->mmc, host->mrq);
+ if(host->mrq && host->mmc->doneflag)
+ {
+ host->mmc->doneflag = 0;
+ spin_unlock_irqrestore(&host->lock, iflags);
+
+ mmc_request_done(host->mmc, host->mrq);
+ }
+ else
+ {
+ spin_unlock_irqrestore(&host->lock, iflags);
+ }
return ret;
unsigned long iflags;
struct rk29_sdmmc *host = mmc_priv(mmc);
- spin_lock(&host->request_lock);
-
spin_lock_irqsave(&host->lock, iflags);
#if 0
__FUNCTION__, __LINE__, host->dma_name, host->dma_name);
host->state = STATE_IDLE;
+ rk29_sdmmc_write(host->regs, SDMMC_RINTSTS, 0xFFFFFFFF);
spin_unlock_irqrestore(&host->lock, iflags);
mmc_request_done(mmc, mrq);
- goto request_ext;//return;
+ return;
}
#endif
- xbwprintk(3, "\n%s..%d..New cmd=%2d(arg=0x%8x)=== cardPresent=0x%lu, state=0x%x ==xbw[%s]==\n", \
+ xbwprintk(6, "\n%s..%d..New cmd=%2d(arg=0x%8x)=== cardPresent=0x%lu, state=0x%x ==xbw[%s]==\n", \
__FUNCTION__, __LINE__,mrq->cmd->opcode, mrq->cmd->arg,host->flags,host->state, host->dma_name);
if(RK29_CTRL_SDMMC_ID == host->pdev->id)
}
else
{
- if(host->error_times++ % (RK29_ERROR_PRINTK_INTERVAL*2) ==0)
+ if(host->error_times++ % (RK29_ERROR_PRINTK_INTERVAL*3) ==0)
{
printk("%s: Refuse to run CMD%2d(arg=0x%8x) due to the removal of card. 3==xbw[%s]==\n", \
__FUNCTION__, mrq->cmd->opcode, mrq->cmd->arg, host->dma_name);
host->state = STATE_IDLE;
spin_unlock_irqrestore(&host->lock, iflags);
mmc_request_done(mmc, mrq);
- goto request_ext;//return;
+ return;
}
else
{
{
host->old_cmd = mrq->cmd->opcode;
host->error_times = 0;
- }
+ }
}
}
else
{
host->old_cmd = mrq->cmd->opcode;
host->error_times = 0;
+
+ if(!test_bit(RK29_SDMMC_CARD_PRESENT, &host->flags))
+ {
+ host->state = STATE_IDLE;
+ mrq->cmd->error = -ENOMEDIUM;
+ spin_unlock_irqrestore(&host->lock, iflags);
+ mmc_request_done(mmc, mrq);
+ return;
+ }
+
}
- #if 1
- if(host->state != STATE_IDLE)
- {
- printk("%s..%d..state Error! ,old_state=%d, OldCMD=%d ,NewCMD%2d,arg=0x%x ===xbw[%s]===\n", \
- __FUNCTION__, __LINE__, host->state, host->cmd->opcode,mrq->cmd->opcode,mrq->cmd->arg, host->dma_name);
- }
-
+ #if 1
+ host->new_mrq = mrq;
spin_unlock_irqrestore(&host->lock, iflags);
- host->new_mrq = mrq;
rk29_sdmmc_start_request(mmc);
#else
spin_unlock_irqrestore(&host->lock, iflags);
mmc_request_done(mmc, mrq);
- goto request_ext;//return;
+ return;
#endif
}
#endif
-
-request_ext:
- spin_unlock(&host->request_lock);
+
}
spin_lock_irqsave(&host->lock, iflags);
- /*
- * Waiting SDIO controller to be IDLE.
- */
- while (timeout-- > 0)
- {
- value = rk29_sdmmc_read(host->regs, SDMMC_STATUS);
- if ((value & SDMMC_STAUTS_DATA_BUSY) == 0 &&(value & SDMMC_CMD_FSM_MASK) == SDMMC_CMD_FSM_IDLE)
- {
- break;
- }
-
- mdelay(1);
- }
- if (timeout <= 0)
- {
- printk("%s..%d...Waiting for SDMMC%d controller to be IDLE timeout.==xbw[%s]===\n", \
- __FUNCTION__, __LINE__, host->pdev->id, host->dma_name);
+ if(test_bit(RK29_SDMMC_CARD_PRESENT, &host->flags) || (RK29_CTRL_SDMMC_ID == host->pdev->id))
+ {
+ /*
+ * Waiting SDIO controller to be IDLE.
+ */
+ while (timeout-- > 0)
+ {
+ value = rk29_sdmmc_read(host->regs, SDMMC_STATUS);
+ if ((value & SDMMC_STAUTS_DATA_BUSY) == 0 &&(value & SDMMC_CMD_FSM_MASK) == SDMMC_CMD_FSM_IDLE)
+ {
+ break;
+ }
+
+ mdelay(1);
+ }
+ if (timeout <= 0)
+ {
+ printk("%s..%d...Waiting for SDMMC%d controller to be IDLE timeout.==xbw[%s]===\n", \
+ __FUNCTION__, __LINE__, host->pdev->id, host->dma_name);
- goto out;
+ goto out;
+ }
}
//if(host->bus_mode != ios->power_mode)
}
-
+ if(!(test_bit(RK29_SDMMC_CARD_PRESENT, &host->flags) || (RK29_CTRL_SDIO1_ID != host->pdev->id)))
+ goto out; //exit the set_ios directly if the SDIO is not present.
+
if(host->ctype != ios->bus_width)
{
switch (ios->bus_width)
static int rk29_sdmmc_get_ro(struct mmc_host *mmc)
{
- struct rk29_sdmmc *host = mmc_priv(mmc);
- u32 wrtprt = rk29_sdmmc_read(host->regs, SDMMC_WRTPRT);
+ struct rk29_sdmmc *host = mmc_priv(mmc);
+ int ret=0;
+
+ switch(host->pdev->id)
+ {
+ case 0:
+ {
+ #if defined(CONFIG_SDMMC0_RK29_WRITE_PROTECT) || defined(CONFIG_SDMMC1_RK29_WRITE_PROTECT)
+ if(INVALID_GPIO == host->write_protect)
+ ret = 0;//no write-protect
+ else
+ ret = gpio_get_value(host->write_protect)?1:0;
+
+ xbwprintk(7,"%s..%d.. write_prt_pin=%d, get_ro=%d ===xbw[%s]===\n",\
+ __FUNCTION__, __LINE__,host->write_protect, ret, host->dma_name);
+
+ #else
+ u32 wrtprt = rk29_sdmmc_read(host->regs, SDMMC_WRTPRT);
+
+ ret = (wrtprt & SDMMC_WRITE_PROTECT)?1:0;
+ #endif
+
+ break;
+ }
+
+ case 1:
+ ret = 0;//no write-protect
+ break;
+
+ default:
+ ret = 0;
+ break;
+ }
+
+ return ret;
- return (wrtprt & SDMMC_WRITE_PROTECT)?1:0;
}
}
+static int rk29_sdmmc_clear_fifo(struct rk29_sdmmc *host)
+{
+ unsigned int timeout, value;
+ int ret = SDM_SUCCESS;
+
+ if(RK29_CTRL_SDMMC_ID == host->pdev->id)
+ {
+ rk29_sdmmc_write(host->regs, SDMMC_RINTSTS, 0xFFFFFFFF);
+ }
+
+ rk29_sdmmc_stop_dma(host);
+ rk29_sdmmc_control_host_dma(host, FALSE);
+ host->dodma = 0;
+
+ //Clean the fifo.
+ for(timeout=0; timeout<FIFO_DEPTH; timeout++)
+ {
+ if(rk29_sdmmc_read(host->regs, SDMMC_STATUS) & SDMMC_STAUTS_FIFO_EMPTY)
+ break;
+
+ value = rk29_sdmmc_read(host->regs, SDMMC_DATA);
+ }
+
+ /* reset */
+ timeout = 1000;
+ value = rk29_sdmmc_read(host->regs, SDMMC_CTRL);
+ value |= (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET);
+ rk29_sdmmc_write(host->regs, SDMMC_CTRL, value);
+
+ value = rk29_sdmmc_read(host->regs, SDMMC_CTRL);
+
+ while( (value & (SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_RESET | SDMMC_CTRL_DMA_RESET)) && (timeout > 0))
+ {
+ udelay(1);
+ timeout--;
+ value = rk29_sdmmc_read(host->regs, SDMMC_CTRL);
+ }
+
+ if (timeout == 0)
+ {
+ host->errorstep = 0x0A;
+ ret = SDM_WAIT_FOR_FIFORESET_TIMEOUT;
+ }
+
+ return ret;
+}
+
+
static const struct mmc_host_ops rk29_sdmmc_ops[] = {
{
{
.request = rk29_sdmmc_request,
.set_ios = rk29_sdmmc_set_ios,
+ .get_ro = rk29_sdmmc_get_ro,
+ .get_cd = rk29_sdmmc_get_cd,
.enable_sdio_irq = rk29_sdmmc_enable_sdio_irq,
.init_card = rk29_sdmmc_init_card,
},
static void rk29_sdmmc_request_end(struct rk29_sdmmc *host, struct mmc_command *cmd)
{
- u32 status;
+ u32 status = host->data_status;
int output=SDM_SUCCESS;
xbwprintk(7, "%s..%d... cmd=%d, host->state=0x%x,\n pendingEvent=0x%lu, completeEvents=0x%lu ====xbw=[%s]====\n\n",\
{
goto exit;//It need not to wait-for-busy if the CMD-ERROR happen.
}
-
+ host->errorstep = 0xf7;
if(cmd->data)
- {
-
- status = host->data_status;
-
+ {
if(host->cmdr & SDMMC_CMD_DAT_WRITE)
{
if(status & (SDMMC_INT_DCRC | SDMMC_INT_EBE))
{
- cmd->data->error = -EILSEQ;;//mrq->data->error = -EILSEQ;
+ cmd->data->error = -EILSEQ;
output = SDM_DATA_CRC_ERROR;
host->errorstep = 0x16;
}
if ((mmc_resp_type(cmd) == MMC_RSP_R1B) || (MMC_STOP_TRANSMISSION == cmd->opcode))
{
output = rk29_sdmmc_wait_unbusy(host);
- if(SDM_SUCCESS != output)
+ if((SDM_SUCCESS != output) && (!host->mrq->cmd->error))
{
+ printk("%s..%d... CMD12 wait busy timeout!!!!! errorStep=0x%x ====xbw=[%s]====\n", \
+ __FUNCTION__, __LINE__, host->errorstep, host->dma_name);
+ rk29_sdmmc_clear_fifo(host);
cmd->error = -ETIMEDOUT;
host->mrq->cmd->error = -ETIMEDOUT;
host->errorstep = 0x1C;
- printk("%s..%d... CMD12 wait busy timeout!!!!! ====xbw=[%s]====\n", \
- __FUNCTION__, __LINE__, host->dma_name);
}
}
}
-
+ host->errorstep = 0xf6;
+
//trace error
if(cmd->data && cmd->data->error)
- {
- if( (!cmd->error) && (0==cmd->retries) && (host->error_times++%RK29_ERROR_PRINTK_INTERVAL == 0))
- {
- printk("%s..%d......CMD=%d error!!!, arg=%x, errorTimes=%d, errorStep=0x%x ! ====xbw[%s]====\n",\
- __FUNCTION__, __LINE__, cmd->opcode, cmd->arg, host->error_times,host->errorstep, host->dma_name);
+ {
+ if( (!cmd->error) && (0==cmd->retries))
+ {
+ printk("%s..%d......CMD=%d error!!!(arg=0x%x,cmdretry=%d,blksize=%d, blocks=%d), \n \
+ statusReg=0x%x, ctrlReg=0x%x, nerrorTimes=%d, errorStep=0x%x ====xbw[%s]====\n",\
+ __FUNCTION__, __LINE__, cmd->opcode, cmd->arg, cmd->retries,cmd->data->blksz, cmd->data->blocks,
+ rk29_sdmmc_read(host->regs, SDMMC_STATUS),
+ rk29_sdmmc_read(host->regs, SDMMC_CTRL),
+ host->error_times,host->errorstep, host->dma_name);
}
cmd->error = -ENODATA;
}
+ host->errorstep = 0xf5;
exit:
{
host->cmd->error = -EIO;
host->mrq->cmd->error = -EIO;
- host->cmd_status = SDMMC_INT_RTO;
+ host->cmd_status |= SDMMC_INT_RTO;
del_timer_sync(&host->request_timer);
struct rk29_sdmmc *host = (struct rk29_sdmmc *)priv;
struct mmc_data *data = host->cmd->data;
enum rk29_sdmmc_state state = host->state;
-
- spin_lock(&host->lock);
-
+ int pending_flag, stopflag;
+ unsigned long iflags;
+
+ spin_lock_irqsave(&host->lock, iflags);
+
state = host->state;
+ pending_flag = 0;
+ stopflag = 0;
do
{
if (!rk29_sdmmc_test_and_clear_pending(host, EVENT_CMD_COMPLETE))
break;
+ host->errorstep = 0xfb;
del_timer_sync(&host->request_timer); //delete the timer for INT_COME_DONE
__FUNCTION__, __LINE__,host->cmd->opcode,host->dma_name);
host->complete_done = 1;
- goto unlock;
+ break;
}
-
+ host->errorstep = 0xfa;
if(host->cmd->error)
{
del_timer_sync(&host->DTO_timer); //delete the timer for INT_DTO
xbwprintk(7, "%s..%d.. cmderr, so call send_stop_cmd() ====xbw[%s]====\n", \
__FUNCTION__, __LINE__, host->dma_name);
+ #if 0
state = STATE_SENDING_CMD;//STATE_SENDING_STOP;
- send_stop_cmd(host);
+ send_stop_cmd(host);
+ #else
+ stopflag = 1; //Moidfyed by xbw at 2011-09-08
+ #endif
break;
}
rk29_sdmmc_set_pending(host, EVENT_DATA_COMPLETE);
}
-
- state = STATE_DATA_BUSY;
+ host->errorstep = 0xf9;
+ state = STATE_DATA_BUSY;
/* fall through */
}
if (!rk29_sdmmc_test_and_clear_pending(host, EVENT_DATA_COMPLETE))
break;
-
+ host->errorstep = 0xf8;
rk29_sdmmc_set_completed(host, EVENT_DATA_COMPLETE);
del_timer_sync(&host->DTO_timer); //delete the timer for INT_DTO
if(!( (MMC_READ_SINGLE_BLOCK == host->cmd->opcode)&&( -EIO == data->error))) //deal with START_BIT_ERROR
{
- host->complete_done = 1;
- goto unlock;
+ host->complete_done = 2;
+ break;
}
}
-
+ host->errorstep = 0xf4;
xbwprintk(7, "%s..%d.. after DATA_COMPLETE, so call send_stop_cmd() ====xbw[%s]====\n", \
__FUNCTION__, __LINE__, host->dma_name);
-
+
+ #if 0
state = STATE_SENDING_CMD;
send_stop_cmd(host);
+ #else
+ stopflag = 2; //Moidfyed by xbw at 2011-09-08
+ #endif
+
break;
}
del_timer_sync(&host->request_timer); //delete the timer for INT_CMD_DONE int CMD12
rk29_sdmmc_request_end(host, host->cmd);
- host->complete_done = 1;
- goto unlock;
+ host->complete_done = 3;
+ break;
}
}
- } while(0);
+
+ pending_flag = (host->complete_done > 0) && (host->retryfunc<50) \
+ && (rk29_sdmmc_test_pending(host, EVENT_CMD_COMPLETE)|| rk29_sdmmc_test_pending(host, EVENT_DATA_COMPLETE) );
+ if(pending_flag)
+ {
+ xbwprintk(7, "%s..%d... cmd=%d(arg=0x%x),completedone=%d, retrycount=%d, doneflag=%d, \n \
+ host->state=0x%x, switchstate=%x, \n \
+ pendingEvent=0x%lu, completeEvents=0x%lu, \n \
+ mrqCMD=%d, arg=0x%x \n ====xbw[%s]====\n",\
+
+ __FUNCTION__, __LINE__,host->cmd->opcode, host->cmd->arg, host->complete_done,\
+ host->retryfunc, host->mmc->doneflag,host->state, state, \
+ host->pending_events,host->completed_events,\
+ host->mrq->cmd->opcode, host->mrq->cmd->arg, host->dma_name);
+
+ cpu_relax();
+ }
+
+ } while(pending_flag && ++host->retryfunc); //while(0);
+
+ if(0!=stopflag)
+ {
+ if(host->cmd->error)
+ xbwprintk(3,"%d: call send_stop_cmd== %d, completedone=%d, doneflag=%d, hoststate=%x, statusReg=0x%x \n", \
+ __LINE__,stopflag, host->complete_done, host->mmc->doneflag, state, rk29_sdmmc_read(host->regs, SDMMC_STATUS));
+
+ state = STATE_SENDING_CMD;
+ send_stop_cmd(host); //Moidfyed by xbw at 2011-09-08
+ }
host->state = state;
-
-unlock:
+
if(0==host->complete_done)
{
- spin_unlock(&host->lock);
+ host->errorstep = 0xf2;
+ spin_unlock_irqrestore(&host->lock, iflags);
return;
}
-
+ host->errorstep = 0xf3;
host->state = STATE_IDLE;
- spin_unlock(&host->lock);
-
- if(host->mrq)
+
+ if(host->mrq && host->mmc->doneflag)
{
+ host->mmc->doneflag = 0;
+ spin_unlock_irqrestore(&host->lock, iflags);
+
mmc_request_done(host->mmc, host->mrq);
}
+ else
+ {
+ spin_unlock_irqrestore(&host->lock, iflags);
+ }
}
{
u32 multi, unit;
- if(!host->cmd_status)
- host->cmd_status = status;
-
+ host->cmd_status |= status;
+ host->errorstep = 0xfc;
if((MMC_STOP_TRANSMISSION != host->cmd->opcode) && (host->cmdr & SDMMC_CMD_DAT_EXP))
{
- unit = 5*1024*1024;
+ unit = 3*1024*1024;
multi = rk29_sdmmc_read(host->regs, SDMMC_BYTCNT)/unit;
multi += ((rk29_sdmmc_read(host->regs, SDMMC_BYTCNT)%unit) ? 1 :0 );
multi = (multi>0) ? multi : 1;
- mod_timer(&host->DTO_timer, jiffies + msecs_to_jiffies(RK29_SDMMC_WAIT_DTO_INTERNVAL*multi));
+ multi += (host->cmd->retries>2)?2:host->cmd->retries;
+ mod_timer(&host->DTO_timer, jiffies + msecs_to_jiffies(RK29_SDMMC_WAIT_DTO_INTERNVAL*multi));//max wait 8s larger
}
smp_wmb();
pending = rk29_sdmmc_read(host->regs, SDMMC_MINTSTS);// read only mask reg
if (!pending)
{
- spin_unlock_irqrestore(&host->lock, iflags);
- return IRQ_HANDLED;
+ goto Exit_INT;
}
host->error_times = 0;
#if 1
+ del_timer(&host->request_timer);
+ del_timer(&host->DTO_timer);
rk29_sdmmc_dealwith_timeout(host);
#endif
if(host->mmc->re_initialized_flags)
{
- mod_timer(&host->detect_timer, jiffies + msecs_to_jiffies(RK29_SDMMC_REMOVAL_DELAY/2));
+ mod_timer(&host->detect_timer, jiffies + msecs_to_jiffies(RK29_SDMMC_REMOVAL_DELAY));
}
else
{
}
- spin_unlock_irqrestore(&host->lock, iflags);
- return IRQ_HANDLED;
+ goto Exit_INT;
}
xbwprintk(6, "%s..%d.. CMD%d INT_CMD_DONE INT=0x%x ====xbw[%s]====\n", \
__FUNCTION__, __LINE__, host->cmd->opcode,pending, host->dma_name);
-
+
rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_CMD_DONE); // clear interrupt
rk29_sdmmc_cmd_interrupt(host, status);
+
+ goto Exit_INT;
}
if(pending & SDMMC_INT_SDIO)
rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_SDIO);
mmc_signal_sdio_irq(host->mmc);
+
+ goto Exit_INT;
}
if(!(pending & SDMMC_INT_CMD_DONE))
tasklet_schedule(&host->tasklet);
- spin_unlock_irqrestore(&host->lock, iflags);
- return IRQ_HANDLED;
+ goto Exit_INT;
}
__FUNCTION__, pending,host->cmd->opcode, host->cmd->arg, host->cmd->retries, host->dma_name);
rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_HLE);
- spin_unlock_irqrestore(&host->lock, iflags);
- return IRQ_HANDLED;
+ goto Exit_INT;
}
__FUNCTION__, __LINE__,host->cmd->opcode,pending, host->dma_name);
rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_DTO);
- del_timer_sync(&host->DTO_timer); //delete the timer for INT_DTO
+ del_timer(&host->DTO_timer); //delete the timer for INT_DTO
- if (!host->data_status)
- host->data_status = status;
+ host->data_status |= status;
smp_wmb();
rk29_sdmmc_set_pending(host, EVENT_DATA_COMPLETE);
tasklet_schedule(&host->tasklet);
-
- spin_unlock_irqrestore(&host->lock, iflags);
- return IRQ_HANDLED;
+ goto Exit_INT;
}
__FUNCTION__, pending, host->cmd->opcode, host->cmd->arg, host->cmd->retries,host->dma_name);
rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_FRUN);
- spin_unlock_irqrestore(&host->lock, iflags);
- return IRQ_HANDLED;
+ goto Exit_INT;
}
+#if defined(CONFIG_ARCH_RK30)
+ if(pending & SDMMC_INT_UNBUSY)
+ {
+ // printk("%d..%s: ==test=== xbw======\n", __LINE__, __FUNCTION__);
+ // rk29_sdmmc_regs_printk(host);
+ rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_UNBUSY);
+ goto Exit_INT;
+ }
+#endif
+
if (pending & SDMMC_INT_RXDR)
{
xbwprintk(6, "%s..%d.. SDMMC_INT_RXDR INT=0x%x ====xbw[%s]====\n", \
rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_TXDR); // clear interrupt
}
+Exit_INT:
+
spin_unlock_irqrestore(&host->lock, iflags);
return IRQ_HANDLED;
}
smp_rmb();
- if(RK29_CTRL_SDMMC_ID == host->pdev->id)
+ if((RK29_CTRL_SDMMC_ID == host->pdev->id) && rk29_sdmmc_get_cd(host->mmc))
{
host->mmc->re_initialized_flags =1;
}
unsigned int status;
status = pdata->status(mmc_dev(host->mmc));
-
+
+ pr_info("%s: slot status change detected(%d-%d)\n",mmc_hostname(host->mmc), host->oldstatus, status);
+
if (status ^ host->oldstatus)
- {
- pr_info("%s: slot status change detected(%d-%d)\n",mmc_hostname(host->mmc), host->oldstatus, status);
+ {
if (status)
{
+ rk29_sdmmc_hw_init(host);
set_bit(RK29_SDMMC_CARD_PRESENT, &host->flags);
mod_timer(&host->detect_timer, jiffies + msecs_to_jiffies(200));
}
static void rk29_sdmmc1_status_notify_cb(int card_present, void *dev_id)
{
struct rk29_sdmmc *host = dev_id;
- printk(KERN_INFO "%s, card_present %d\n", mmc_hostname(host->mmc), card_present);
+ //printk(KERN_INFO "%s, card_present %d\n", mmc_hostname(host->mmc), card_present);
rk29_sdmmc1_check_status((unsigned long)host);
}
host->error_times = 0;
host->state = STATE_IDLE;
host->complete_done = 0;
+ host->retryfunc = 0;
host->mrq = NULL;
host->new_mrq = NULL;
#ifdef CONFIG_PM
host->gpio_det = pdata->detect_irq;
#endif
+ host->set_iomux = pdata->set_iomux;
if(pdata->io_init)
pdata->io_init();
spin_lock_init(&host->lock);
- spin_lock_init(&host->request_lock);
#ifdef RK29_SDMMC_LIST_QUEUE
INIT_LIST_HEAD(&host->queue);
#endif
host->clk = clk_get(&pdev->dev, "mmc");
-
+
#if RK29_SDMMC_DEFAULT_SDIO_FREQ
clk_set_rate(host->clk,SDHC_FPP_FREQ);
#else
clk_set_rate(host->clk,RK29_MAX_SDIO_FREQ);
#endif
-
+
clk_enable(host->clk);
clk_enable(clk_get(&pdev->dev, "hclk_mmc"));
}
mmc->ops = &rk29_sdmmc_ops[pdev->id];
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
+ mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
+#endif
mmc->f_min = FOD_FREQ;
#if RK29_SDMMC_DEFAULT_SDIO_FREQ
}
else
{
- mmc->f_max = RK29_MAX_SDIO_FREQ;//SDHC_FPP_FREQ / 2;
+ mmc->f_max = RK29_MAX_SDIO_FREQ;
}
#endif
| MMC_VDD_31_32|MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_34_35| MMC_VDD_35_36; ///set valid volage 2.7---3.6v
mmc->caps = pdata->host_caps;
mmc->re_initialized_flags = 1;
+ mmc->doneflag = 1;
+ mmc->sdmmc_host_hw_init = rk29_sdmmc_hw_init;
/*
* We can do SGIO
*/
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
+ mmc->max_segs = 64;
+#else
mmc->max_phys_segs = 64;
mmc->max_hw_segs = 64;
+#endif
/*
* Block size can be up to 2048 bytes, but must be a power of two.
tasklet_init(&host->tasklet, rk29_sdmmc_tasklet_func, (unsigned long)host);
+ /* Create card detect handler thread */
+ setup_timer(&host->detect_timer, rk29_sdmmc_detect_change,(unsigned long)host);
+ setup_timer(&host->request_timer,rk29_sdmmc_INT_CMD_DONE_timeout,(unsigned long)host);
+ setup_timer(&host->DTO_timer,rk29_sdmmc_INT_DTO_timeout,(unsigned long)host);
+
irq = platform_get_irq(pdev, 0);
if (irq < 0)
{
memcpy(host->dma_name, pdata->dma_name, 8);
host->use_dma = pdata->use_dma;
+ xbwprintk(7,"%s..%s..%d..*********** Bus clock= %d Khz ====xbw[%s]===\n",\
+ __FILE__, __FUNCTION__,__LINE__,clk_get_rate(host->clk)/1000, host->dma_name);
+
/*DMA init*/
if(host->use_dma)
{
host->dma_addr = regs->start + SDMMC_DATA;
}
+#if defined(CONFIG_SDMMC0_RK29_WRITE_PROTECT) || defined(CONFIG_SDMMC1_RK29_WRITE_PROTECT)
+ host->write_protect = pdata->write_prt;
+#endif
+
rk29_sdmmc_hw_init(host);
ret = request_irq(irq, rk29_sdmmc_interrupt, 0, dev_name(&pdev->dev), host);
if(RK29_CTRL_SDMMC_ID== host->pdev->id)
{
- clear_bit(RK29_SDMMC_CARD_PRESENT, &host->flags);
+ if(rk29_sdmmc_get_cd(host->mmc))
+ {
+ set_bit(RK29_SDMMC_CARD_PRESENT, &host->flags);
+ }
+ else
+ {
+ clear_bit(RK29_SDMMC_CARD_PRESENT, &host->flags);
+ }
+ }
+ else
+ {
+ #if defined(CONFIG_USE_SDMMC0_FOR_WIFI_DEVELOP_BOARD)
+ if(0== host->pdev->id)
+ {
+ set_bit(RK29_SDMMC_CARD_PRESENT, &host->flags);
+ }
+ #endif
+
+ #if defined(CONFIG_USE_SDMMC1_FOR_WIFI_DEVELOP_BOARD)
+ if(1== host->pdev->id)
+ {
+ set_bit(RK29_SDMMC_CARD_PRESENT, &host->flags);
+ }
+ #endif
}
}
}
- /* Create card detect handler thread */
- setup_timer(&host->detect_timer, rk29_sdmmc_detect_change,(unsigned long)host);
- setup_timer(&host->request_timer,rk29_sdmmc_INT_CMD_DONE_timeout,(unsigned long)host);
- setup_timer(&host->DTO_timer,rk29_sdmmc_INT_DTO_timeout,(unsigned long)host);
platform_set_drvdata(pdev, mmc);
#ifdef RK29_SDMMC_NOTIFY_REMOVE_INSERTION
globalSDhost[pdev->id] = (struct rk29_sdmmc *)host;
- if(RK29_CTRL_SDMMC_ID== host->pdev->id)
+ if(0== host->pdev->id)
{
rk29_sdmmc_progress_add_attr(pdev);
}
#ifdef CONFIG_PM
+#if defined(CONFIG_ARCH_RK29)
static irqreturn_t det_keys_isr(int irq, void *dev_id)
{
struct rk29_sdmmc *host = dev_id;
rk29_mux_api_set(GPIO2A2_SDMMC0DETECTN_NAME, GPIO2L_SDMMC0_DETECT_N);
}
+#elif defined(CONFIG_ARCH_RK30)
+static irqreturn_t det_keys_isr(int irq, void *dev_id)
+{
+ struct rk29_sdmmc *host = dev_id;
+ dev_info(&host->pdev->dev, "sd det_gpio changed(%s), send wakeup key!\n",
+ gpio_get_value(RK30_PIN3_PB6)?"removed":"insert");
+ rk29_sdmmc_detect_change((unsigned long)dev_id);
+
+ return IRQ_HANDLED;
+}
+
+static int rk29_sdmmc_sdcard_suspend(struct rk29_sdmmc *host)
+{
+ int ret = 0;
+ rk29_mux_api_set(GPIO3B6_SDMMC0DETECTN_NAME, GPIO3B_GPIO3B6);
+ gpio_request(RK30_PIN3_PB6, "sd_detect");
+ gpio_direction_input(RK30_PIN3_PB6);
+
+ host->gpio_irq = gpio_to_irq(RK30_PIN3_PB6);
+ ret = request_irq(host->gpio_irq, det_keys_isr,
+ (gpio_get_value(RK30_PIN3_PB6))?IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING,
+ "sd_detect",
+ host);
+
+ enable_irq_wake(host->gpio_irq);
+
+ return ret;
+}
+static void rk29_sdmmc_sdcard_resume(struct rk29_sdmmc *host)
+{
+ disable_irq_wake(host->gpio_irq);
+ free_irq(host->gpio_irq,host);
+ gpio_free(RK30_PIN3_PB6);
+ rk29_mux_api_set(GPIO3B6_SDMMC0DETECTN_NAME, GPIO3B_SDMMC0_DETECT_N);
+}
+
+#endif
static int rk29_sdmmc_suspend(struct platform_device *pdev, pm_message_t state)
if(host && host->pdev && (RK29_CTRL_SDMMC_ID == host->pdev->id)) //only the SDMMC0 have suspend-resume; noted by xbw
{
if (mmc)
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
+ ret = mmc_suspend_host(mmc);
+#else
ret = mmc_suspend_host(mmc, state);
+#endif
if(rk29_sdmmc_sdcard_suspend(host) < 0)
dev_info(&host->pdev->dev, "rk29_sdmmc_sdcard_suspend error\n");