From: xbw Date: Tue, 25 Feb 2014 05:09:26 +0000 (+0800) Subject: SDMMC: Delete those code which will never be used in the future. X-Git-Tag: firefly_0821_release~6289 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=9401f2e4feea8c884418f3c5821e83aee7b313b0;p=firefly-linux-kernel-4.4.55.git SDMMC: Delete those code which will never be used in the future. --- diff --git a/drivers/mmc/host/rk2818-sdmmc.h b/drivers/mmc/host/rk2818-sdmmc.h deleted file mode 100755 index 19069a0a3c56..000000000000 --- a/drivers/mmc/host/rk2818-sdmmc.h +++ /dev/null @@ -1,132 +0,0 @@ -/* drivers/mmc/host/rk2818-sdmmc.h - * - * Copyright (C) 2010 ROCKCHIP, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef __RK2818_SDMMC_H -#define __RK2818_SDMMC_H - -#define MAX_SG_CHN 2 - - -#define SDMMC_CTRL (0x000) -#define SDMMC_PWREN (0x004) -#define SDMMC_CLKDIV (0x008) -#define SDMMC_CLKSRC (0x00c) -#define SDMMC_CLKENA (0x010) -#define SDMMC_TMOUT (0x014) -#define SDMMC_CTYPE (0x018) -#define SDMMC_BLKSIZ (0x01c) -#define SDMMC_BYTCNT (0x020) -#define SDMMC_INTMASK (0x024) -#define SDMMC_CMDARG (0x028) -#define SDMMC_CMD (0x02c) -#define SDMMC_RESP0 (0x030) -#define SDMMC_RESP1 (0x034) -#define SDMMC_RESP2 (0x038) -#define SDMMC_RESP3 (0x03c) -#define SDMMC_MINTSTS (0x040) -#define SDMMC_RINTSTS (0x044) -#define SDMMC_STATUS (0x048) -#define SDMMC_FIFOTH (0x04c) -#define SDMMC_CDETECT (0x050) -#define SDMMC_WRTPRT (0x054) -#define SDMMC_TCBCNT (0x05c) -#define SDMMC_TBBCNT (0x060) -#define SDMMC_DEBNCE (0x064) - -#define SDMMC_DATA (0x100) - -#define RK2818_BIT(n) (1<<(n)) - -/* Control register defines */ -#define SDMMC_CTRL_OD_PULLUP RK2818_BIT(24) -#define SDMMC_CTRL_ABRT_READ_DATA RK2818_BIT(8) -#define SDMMC_CTRL_SEND_IRQ_RESP RK2818_BIT(7) -#define SDMMC_CTRL_READ_WAIT RK2818_BIT(6) -#define SDMMC_CTRL_DMA_ENABLE RK2818_BIT(5) -#define SDMMC_CTRL_INT_ENABLE RK2818_BIT(4) -#define SDMMC_CTRL_DMA_RESET RK2818_BIT(2) -#define SDMMC_CTRL_FIFO_RESET RK2818_BIT(1) -#define SDMMC_CTRL_RESET RK2818_BIT(0) -/* Clock Enable register defines */ -#define SDMMC_CLKEN_LOW_PWR RK2818_BIT(16) -#define SDMMC_CLKEN_ENABLE RK2818_BIT(0) -/* time-out register defines */ -#define SDMMC_TMOUT_DATA(n) _SBF(8, (n)) -#define SDMMC_TMOUT_DATA_MSK 0xFFFFFF00 -#define SDMMC_TMOUT_RESP(n) ((n) & 0xFF) -#define SDMMC_TMOUT_RESP_MSK 0xFF -/* card-type register defines */ -#define SDMMC_CTYPE_8BIT RK2818_BIT(16) -#define SDMMC_CTYPE_4BIT RK2818_BIT(0) -/* Interrupt status & mask register defines */ -#define SDMMC_INT_SDIO RK2818_BIT(16) -#define SDMMC_INT_EBE RK2818_BIT(15) -#define SDMMC_INT_ACD RK2818_BIT(14) -#define SDMMC_INT_SBE RK2818_BIT(13) -#define SDMMC_INT_HLE RK2818_BIT(12) -#define SDMMC_INT_FRUN RK2818_BIT(11) -#define SDMMC_INT_HTO RK2818_BIT(10) -#define SDMMC_INT_DRTO RK2818_BIT(9) -#define SDMMC_INT_RTO RK2818_BIT(8) -#define SDMMC_INT_DCRC RK2818_BIT(7) -#define SDMMC_INT_RCRC RK2818_BIT(6) -#define SDMMC_INT_RXDR RK2818_BIT(5) -#define SDMMC_INT_TXDR RK2818_BIT(4) -#define SDMMC_INT_DTO RK2818_BIT(3) -#define SDMMC_INT_CMD_DONE RK2818_BIT(2) -#define SDMMC_INT_RE RK2818_BIT(1) -#define SDMMC_INT_CD RK2818_BIT(0) - -/* Command register defines */ -#define SDMMC_CMD_START RK2818_BIT(31) -#define SDMMC_CMD_CCS_EXP RK2818_BIT(23) -#define SDMMC_CMD_CEATA_RD RK2818_BIT(22) -#define SDMMC_CMD_UPD_CLK RK2818_BIT(21) -#define SDMMC_CMD_INIT RK2818_BIT(15) -#define SDMMC_CMD_STOP RK2818_BIT(14) -#define SDMMC_CMD_PRV_DAT_WAIT RK2818_BIT(13) -#define SDMMC_CMD_SEND_STOP RK2818_BIT(12) -#define SDMMC_CMD_STRM_MODE RK2818_BIT(11) -#define SDMMC_CMD_DAT_WR RK2818_BIT(10) -#define SDMMC_CMD_DAT_EXP RK2818_BIT(9) -#define SDMMC_CMD_RESP_CRC RK2818_BIT(8) -#define SDMMC_CMD_RESP_LONG RK2818_BIT(7) -#define SDMMC_CMD_RESP_EXP RK2818_BIT(6) -#define SDMMC_CMD_INDX(n) ((n) & 0x1F) -/* Status register defines */ -#define SDMMC_STAUTS_RESP_INDEX RK2818_BIT(11) -#define SDMMC_STAUTS_MC_BUSY RK2818_BIT(10) -#define SDMMC_STAUTS_DATA_BUSY RK2818_BIT(9) -#define SDMMC_STAUTS_CARD_PRESENT RK2818_BIT(8) -#define SDMMC_STAUTS_FIFO_FULL RK2818_BIT(3) -#define SDMMC_STAUTS_FIFO_EMPTY RK2818_BIT(2) -#define SDMMC_STAUTS_FIFO_TX_WATERMARK RK2818_BIT(1) -#define SDMMC_STAUTS_FIFO_RX_WATERMARK RK2818_BIT(0) - - - - -#define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FF) -#define SDMMC_FIFO_SZ 32 - -#define SDMMC_WRITE_PROTECT RK2818_BIT(0) -#define SDMMC_CARD_DETECT_N RK2818_BIT(0) - -/* Specifies how often in millisecs to poll for card removal-insertion changes - * when the timer switch is open */ -#define RK_SDMMC0_SWITCH_POLL_DELAY 35 - - -#endif diff --git a/drivers/mmc/host/rk29_sdmmc.c b/drivers/mmc/host/rk29_sdmmc.c deleted file mode 100755 index eb9f8327aa8f..000000000000 --- a/drivers/mmc/host/rk29_sdmmc.c +++ /dev/null @@ -1,4049 +0,0 @@ -/* drivers/mmc/host/rk29_sdmmc.c - * - * Copyright (C) 2010 ROCKCHIP, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * mount -t debugfs debugfs /data/debugfs;cat /data/debugfs/mmc0/status - * echo 't' >/proc/sysrq-trigger - * echo 19 >/sys/module/wakelock/parameters/debug_mask - * vdc volume uevent on - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "rk29_sdmmc.h" - - -#define RK29_SDMMC_xbw_Debug 0 - -#if RK29_SDMMC_xbw_Debug -int debug_level = 5; -#define xbwprintk(n, format, arg...) \ - if (n <= debug_level) { \ - printk(format,##arg); \ - } -#else -#define xbwprintk(n, arg...) -#endif - -#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) -#define RK29_MAX_SDIO_FREQ 50000000 //set max-sdio-frequency 50Mhz in MTK module. -#else -#define RK29_MAX_SDIO_FREQ 25000000 //set max-sdio-frequency 25Mhz at the present time -#endif - -//use the new iomux-API -#if defined(CONFIG_ARCH_RK3066B)||defined(CONFIG_ARCH_RK3168)||defined(CONFIG_ARCH_RK3188)||defined(CONFIG_ARCH_RK3026)||defined(CONFIG_ARCH_RK319X) -#define DRIVER_SDMMC_USE_NEW_IOMUX_API 1 -#else -#define DRIVER_SDMMC_USE_NEW_IOMUX_API 0 -#endif - -#define SWITCH_VOLTAGE_18_33 0 //RK30_PIN2_PD7 //Temporary experiment -#define SWITCH_VOLTAGE_ENABLE_VALUE_33 GPIO_LOW - -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) -{ - __raw_writel(val,regbase + regOff); -} - -static unsigned int rk29_sdmmc_read(unsigned char __iomem *regbase, unsigned int regOff) -{ - return __raw_readl(regbase + regOff); -} - -static int rk29_sdmmc_regs_printk(struct rk29_sdmmc *host) -{ - struct sdmmc_reg *regs = rk_sdmmc_regs; - - 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; -} - -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) - { - host->irq_state = irqflag; - if(irqflag) - { - enable_irq(host->irq); - } - else - { - disable_irq(host->irq); - } - } - local_irq_restore(flags); -} - - -#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) -{ - struct rk29_sdmmc *host = NULL; - static u32 unmounting_times = 0; - static char oldbuf[64]; - - if( !strncmp(buf,"version" , strlen("version"))) - { - printk(KERN_INFO "\n The driver SDMMC named 'rk29_sdmmc.c' is %s.\n", RK29_SDMMC_VERSION); - return count; - } - - //envalue the address of host base on input-parameter. - if( !strncmp(buf,"sd-" , strlen("sd-")) ) - { - host = (struct rk29_sdmmc *)globalSDhost[0]; - if(!host) - { - printk(KERN_WARNING "%s..%d.. fail to call progress_store because the host is null. \n",__FUNCTION__,__LINE__); - return count; - } - } - else if( !strncmp(buf,"sdio1-" , strlen("sdio1-")) ) - { - host = (struct rk29_sdmmc *)globalSDhost[RK29_CTRL_SDIO1_ID]; - if(!host) - { - printk(KERN_WARNING "%s..%d.. fail to call progress_store because the host-sdio1 is null.\n",__FUNCTION__,__LINE__); - return count; - } - } - else if( !strncmp(buf,"sdio2-" , strlen("sdio2-")) ) - { - host = (struct rk29_sdmmc *)globalSDhost[RK29_CTRL_SDIO2_ID]; - if(!host) - { - printk(KERN_WARNING "%s..%d.. fail to call progress_store because the host-sdio2 is null.\n",__FUNCTION__,__LINE__); - return count; - } - } - else - { - printk(KERN_WARNING "%s..%d.. You want to use sysfs for SDMMC but input-parameter is wrong.\n",__FUNCTION__,__LINE__); - return count; - } - rk29_sdmmc_enable_irq(host, false); - - //spin_lock(&host->lock); - if(strncmp(buf,oldbuf , strlen(buf))) - { - printk(KERN_INFO ".%d.. MMC0 receive the message %s from VOLD.[%s]\n", __LINE__, buf, host->dma_name); - strcpy(oldbuf, buf); - } - - /* - * //deal with the message - * 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(!strncmp(buf, "sd-Unmounting", strlen("sd-Unmounting"))) - { - if(unmounting_times++%10 == 0) - { - printk(KERN_INFO ".%d.. MMC0 receive the message Unmounting(waitTimes=%d) from VOLD.[%s]\n", \ - __LINE__, unmounting_times, host->dma_name); - } - - 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-No-Media", strlen("sd-No-Media"))) - { - printk(KERN_INFO ".%d.. MMC0 receive the message No-Media from VOLD. waitTimes=%d [%s]\n" ,\ - __LINE__,unmounting_times, host->dma_name); - - del_timer_sync(&host->detect_timer); - host->mmc->re_initialized_flags = 1; - unmounting_times = 0; - - if(test_bit(RK29_SDMMC_CARD_PRESENT, &host->flags)) - { - mmc_detect_change(host->mmc, 0); - } - } - else if( !strncmp(buf, "sd-Ready", strlen("sd-Ready"))) - { - printk(KERN_INFO ".%d.. MMC0 receive the message Ready(ReInitFlag=%d) from VOLD. waitTimes=%d [%s]\n" ,\ - __LINE__, host->mmc->re_initialized_flags, unmounting_times, host->dma_name); - - unmounting_times = 0; - host->mmc->re_initialized_flags = 1; - } - else if( !strncmp(buf,"sd-reset" , strlen("sd-reset")) ) - { - printk(KERN_INFO ".%d.. Now manual reset for SDMMC0. [%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(KERN_INFO ".%d.. Now printk the register of SDMMC0. [%s]\n",__LINE__, host->dma_name); - rk29_sdmmc_regs_printk(host); - } - - } - #else - if(0 == host->pdev->id) - { - if( !strncmp(buf,"sd-reset" , strlen("sd-reset")) ) - { - printk(KERN_INFO ".%d.. Now manual reset for SDMMC0. [%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(KERN_INFO ".%d.. Now printk the register of SDMMC0. [%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"))) - { - printk(KERN_INFO ".%d.. Now printk the register of SDMMC1. [%s]\n",__LINE__, host->dma_name); - rk29_sdmmc_regs_printk(host); - } - else if( !strncmp(buf,"sdio1-reset" , strlen("sdio1-reset")) ) - { - printk(KERN_INFO ".%d.. Now manual reset for SDMMC1. [%s]\n",__LINE__, host->dma_name); - rk29_sdmmc_hw_init(host); - mmc_detect_change(host->mmc, 0); - } - } - else if(RK29_CTRL_SDIO2_ID == host->pdev->id) - { - if( !strncmp(buf, "sdio2-regs", strlen("sdio2-regs"))) - { - printk(KERN_INFO ".%d.. Now printk the register of SDMMC2. [%s]\n",__LINE__, host->dma_name); - rk29_sdmmc_regs_printk(host); - } - else if( !strncmp(buf,"sdio2-reset" , strlen("sdio2-reset")) ) - { - printk(KERN_INFO ".%d.. Now manual reset for SDMMC2. [%s]\n",__LINE__, host->dma_name); - rk29_sdmmc_hw_init(host); - mmc_detect_change(host->mmc, 0); - } - } - - // spin_unlock(&host->lock); - - rk29_sdmmc_enable_irq(host, true); - return count; -} - -struct kobj_attribute mmc_reset_attrs = -{ - .attr = { - .name = "rescan", - .mode = 0764}, - .show = NULL, - .store = rk29_sdmmc_progress_store, -}; -struct attribute *mmc_attrs[] = -{ - &mmc_reset_attrs.attr, - NULL -}; - -static struct kobj_type mmc_kset_ktype = { - .sysfs_ops = &kobj_sysfs_ops, - .default_attrs = &mmc_attrs[0], -}; - -static int rk29_sdmmc_progress_add_attr( struct platform_device *pdev ) -{ - int result; - 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 ); - - parentkobject = &pdev->dev.kobj ; - result = kobject_add( me , parentkobject->parent->parent->parent,"%s", "sd-sdio" ); - - return result; -} -#endif - -/** -** This function checks whether the core supports the IDMAC. -** return Returns 1 if HW supports IDMAC, else returns 0. -*/ -u32 rk_sdmmc_check_idma_support(struct rk29_sdmmc *host) -{ - u32 retval = 0; - u32 ctrl_reg; - ctrl_reg = rk29_sdmmc_read(host->regs, SDMMC_CTRL); - if(ctrl_reg & SDMMC_CTRL_USE_IDMAC) - retval = 1;//Return "true", indicating the hardware supports IDMAC - else - retval = 0;// Hardware doesnot support IDMAC - - return retval; -} - -static u32 rk29_sdmmc_prepare_command(struct mmc_command *cmd) -{ - u32 cmdr = cmd->opcode; - - switch(cmdr) - { - 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; - case MMC_SEND_STATUS: - case MMC_GO_INACTIVE_STATE: - cmdr |= SDMMC_CMD_PRV_DAT_NO_WAIT; - break; - default: - cmdr |= SDMMC_CMD_PRV_DAT_WAIT; - break; - } - - /* response type */ - switch(mmc_resp_type(cmd)) - { - case MMC_RSP_R1: - case MMC_RSP_R1B: - // case MMC_RSP_R5: //R5,R6,R7 is same with the R1 - //case MMC_RSP_R6: - // case R6m_TYPE: - // case MMC_RSP_R7: - cmdr |= (SDMMC_CMD_RESP_CRC | SDMMC_CMD_RESP_SHORT | SDMMC_CMD_RESP_EXP); - break; - case MMC_RSP_R3: - //case MMC_RSP_R4: - /* these response not contain crc7, so don't care crc error and response error */ - cmdr |= (SDMMC_CMD_RESP_NO_CRC | SDMMC_CMD_RESP_SHORT | SDMMC_CMD_RESP_EXP); - break; - case MMC_RSP_R2: - cmdr |= (SDMMC_CMD_RESP_CRC | SDMMC_CMD_RESP_LONG | SDMMC_CMD_RESP_EXP); - break; - case MMC_RSP_NONE: - cmdr |= (SDMMC_CMD_RESP_CRC_NOCARE | SDMMC_CMD_RESP_NOCARE | SDMMC_CMD_RESP_NO_EXP); - break; - default: - cmdr |= (SDMMC_CMD_RESP_CRC_NOCARE | SDMMC_CMD_RESP_NOCARE | SDMMC_CMD_RESP_NO_EXP); - break; - } - - 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 [%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*10;//wait 60ms cycle. - - host->cmd = cmd; - host->old_cmd = cmd->opcode; - host->errorstep = 0; - host->pending_events = 0; - host->completed_events = 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 - -#if defined(CONFIG_ARCH_RK29) - rk29_sdmmc_write(host->regs, SDMMC_CMD, cmd_flags | SDMMC_CMD_START); // write to SDMMC_CMD register -#else - rk29_sdmmc_write(host->regs, SDMMC_CMD, cmd_flags | SDMMC_CMD_USE_HOLD_REG |SDMMC_CMD_START); // write to SDMMC_CMD register -#endif - - xbwprintk(1,"\n%s..%d..************.start cmd=%d, arg=0x%x ******** [%s]\n", \ - __FUNCTION__, __LINE__, cmd->opcode, cmd->arg, host->dma_name); - - - /* wait until CIU accepts the command */ - while (--tmo && (rk29_sdmmc_read(host->regs, SDMMC_CMD) & SDMMC_CMD_START)) - { - udelay(2);//cpu_relax(); - } - - host->complete_done = 0; - host->mmc->doneflag = 1; - - if(!tmo) - { - if(0==cmd->retries) - { - printk(KERN_WARNING "%s..%d.. CMD_START timeout! CMD%d(arg=0x%x, retries=%d) [%s]\n",\ - __FUNCTION__,__LINE__, cmd->opcode, cmd->arg, cmd->retries,host->dma_name); - } - - cmd->error = -ETIMEDOUT; - host->mrq->cmd->error = -ETIMEDOUT; - del_timer_sync(&host->request_timer); - - host->errorstep = 0x1; - return SDM_WAIT_FOR_CMDSTART_TIMEOUT; - } - host->errorstep = 0xfe; - - return SDM_SUCCESS; -} - -static int rk29_sdmmc_reset_fifo(struct rk29_sdmmc *host) -{ - u32 value; - int timeout; - int ret = SDM_SUCCESS; - - value = rk29_sdmmc_read(host->regs, SDMMC_STATUS); - if (!(value & SDMMC_STAUTS_FIFO_EMPTY)) - { - value = rk29_sdmmc_read(host->regs, SDMMC_CTRL); - value |= SDMMC_CTRL_FIFO_RESET; - rk29_sdmmc_write(host->regs, SDMMC_CTRL, value); - - timeout = 1000; - while (((value = rk29_sdmmc_read(host->regs, SDMMC_CTRL)) & (SDMMC_CTRL_FIFO_RESET)) && (timeout > 0)) - { - udelay(1); - timeout--; - } - if (timeout == 0) - { - host->errorstep = 0x2; - ret = SDM_WAIT_FOR_FIFORESET_TIMEOUT; - } - } - - return ret; - -} - -static int rk29_sdmmc_wait_unbusy(struct rk29_sdmmc *host) -{ - int time_out = 500000;//250000; //max is 250ms; //adapt the value to the sick card. modify at 2011-10-08 - -#if SDMMC_USE_INT_UNBUSY - if((24==host->cmd->opcode)||(25==host->cmd->opcode)) - return SDM_SUCCESS; -#endif - while (rk29_sdmmc_read(host->regs, SDMMC_STATUS) & (SDMMC_STAUTS_DATA_BUSY|SDMMC_STAUTS_MC_BUSY)) - { - udelay(1); - time_out--; - - if(time_out == 0) - { - host->errorstep = 0x3; - return SDM_BUSY_TIMEOUT; - } - } - - return SDM_SUCCESS; -} - -static void rk29_sdmmc_dma_cleanup(struct rk29_sdmmc *host) -{ - if (host->data) - { - dma_unmap_sg(&host->pdev->dev, host->data->sg, host->data->sg_len, - ((host->data->flags & MMC_DATA_WRITE) - ? DMA_TO_DEVICE : DMA_FROM_DEVICE)); - } -} - -static void rk29_sdmmc_stop_dma(struct rk29_sdmmc *host) -{ - int ret = 0; - - if(host->use_dma == 0) - return; - - if (host->dma_info.chn> 0) - { - rk29_sdmmc_dma_cleanup(host); - - ret = rk29_dma_ctrl(host->dma_info.chn,RK29_DMAOP_STOP); - if(ret < 0) - { - printk(KERN_WARNING "%s..%d...rk29_dma_ctrl STOP error! [%s]\n", __FUNCTION__, __LINE__, host->dma_name); - host->errorstep = 0x95; - return; - } - - ret = rk29_dma_ctrl(host->dma_info.chn,RK29_DMAOP_FLUSH); - if(ret < 0) - { - printk(KERN_WARNING "%s..%d...rk29_dma_ctrl FLUSH error! [%s]\n", __FUNCTION__, __LINE__, host->dma_name); - host->errorstep = 0x96; - return; - } - - } - else - { - /* Data transfer was stopped by the interrupt handler */ - rk29_sdmmc_set_pending(host, EVENT_DATA_COMPLETE); - } -} - -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); -} - -static void send_stop_cmd(struct rk29_sdmmc *host) -{ - int ret, i; - - 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 [%s]\n", \ - __FUNCTION__, __LINE__, host->dma_name); - } - } - - i = 0; - while(++i>2) - { - ret = rk29_sdmmc_wait_unbusy(host); - if(SDM_SUCCESS == ret) - break; - - mod_timer(&host->request_timer, jiffies + msecs_to_jiffies(RK29_SDMMC_SEND_START_TIMEOUT+2500)); - xbwprintk(7, "%d..%s: retry times=%d before send_stop_cmd [%s].\n", __LINE__, __FUNCTION__, i, host->dma_name); - - } - - - host->errorstep = 0xe1; - mod_timer(&host->request_timer, jiffies + msecs_to_jiffies(RK29_SDMMC_SEND_START_TIMEOUT+2500)); - - 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; - } - host->errorstep = 0xe2; -} - - -/* 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) -{ - struct rk29_sdmmc *host = arg; - - if(host->use_dma == 0) - return; - - 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; - void *buf; - unsigned int offset; - struct mmc_data *data = host->data; - u32 value; - unsigned int nbytes=0, len; - - value = rk29_sdmmc_read(host->regs, SDMMC_STATUS); - if ( value& SDMMC_STAUTS_FIFO_EMPTY) - goto done; - - if(NULL == host->data) - goto done; - - if((NULL == host)&&(NULL == host->data)) - goto done; - - sg = host->sg; - buf = sg_virt(sg); - offset = host->pio_offset; - - while ( (host->intInfo.transLen < host->intInfo.desLen) && (!(value & SDMMC_STAUTS_FIFO_EMPTY)) ) - { - len = SDMMC_GET_FCNT(value) << PIO_DATA_SHIFT; - if (offset + len <= sg->length) { - host->pull_data(host, (void *)(buf + offset), len); - - 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 = sg_virt(sg); - } - }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 = 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; -} - - -static int rk29_sdmmc_write_data_pio(struct rk29_sdmmc *host) -{ - struct scatterlist *sg; - void *buf; - unsigned int offset; - struct mmc_data *data = host->data; - u32 value; - unsigned int nbytes=0, len; - - value = rk29_sdmmc_read(host->regs, SDMMC_STATUS); - if ( value& SDMMC_STAUTS_FIFO_EMPTY) - goto done; - - if(NULL == host->data) - goto done; - - if((NULL == host)&&(NULL == host->data)) - goto done; - - sg = host->sg; - buf = sg_virt(sg); - offset = host->pio_offset; - - while ( (host->intInfo.transLen < host->intInfo.desLen) && (!(value & SDMMC_STAUTS_FIFO_EMPTY)) ) - { - len = SDMMC_FIFO_SZ -(SDMMC_GET_FCNT(value) << PIO_DATA_SHIFT); - if (offset + len <= sg->length) { - host->push_data(host, (void *)(buf + offset), len); - - offset += len; - nbytes += len; - host->intInfo.transLen++; - if (offset == sg->length) { - host->sg = sg = sg_next(sg); - if (!sg) - goto done; - - offset = 0; - buf = sg_virt(sg); - } - } else { - unsigned int remaining = sg->length - offset; - - host->push_data(host, (void *)(buf + offset), - remaining); - nbytes += remaining; - host->intInfo.transLen++; - - host->sg = sg = sg_next(sg); - if (!sg) - goto done; - - 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; - int ret, dma_len=0; - - if(host->use_dma == 0) - { - printk(KERN_WARNING "%s..%d...setup DMA fail!!!!!!. host->use_dma=0 [%s]\n", __FUNCTION__, __LINE__, host->dma_name); - host->errorstep = 0x4; - return -ENOSYS; - } - /* If we don't have a channel, we can't do DMA */ - if (host->dma_info.chn < 0) - { - printk(KERN_WARNING "%s..%d...setup DMA fail!!!!!!!. dma_info.chn < 0 [%s]\n", __FUNCTION__, __LINE__, host->dma_name); - host->errorstep = 0x5; - return -ENODEV; - } - - if (data->blksz & 3) - { - printk(KERN_ERR "%s..%d...data_len not aligned to 4bytes. [%s]\n", \ - __FUNCTION__, __LINE__, host->dma_name); - - return -EINVAL; - } - - if (data->flags & MMC_DATA_READ) - { - direction = RK29_DMASRC_HW; - sgDirection = DMA_FROM_DEVICE; - } - else - { - direction = RK29_DMASRC_MEM; - sgDirection = DMA_TO_DEVICE; - } - - ret = rk29_dma_ctrl(host->dma_info.chn,RK29_DMAOP_STOP); - if(ret < 0) - { - printk(KERN_WARNING "%s..%d...rk29_dma_ctrl stop error![%s]\n", __FUNCTION__, __LINE__, host->dma_name); - host->errorstep = 0x91; - return -ENOSYS; - } - - ret = rk29_dma_ctrl(host->dma_info.chn,RK29_DMAOP_FLUSH); - if(ret < 0) - { - printk(KERN_WARNING "%s..%d...rk29_dma_ctrl flush error![%s]\n", __FUNCTION__, __LINE__, host->dma_name); - host->errorstep = 0x91; - return -ENOSYS; - } - - - ret = rk29_dma_devconfig(host->dma_info.chn, direction, (unsigned long )(host->dma_addr)); - if(0 != ret) - { - printk(KERN_WARNING "%s..%d...call rk29_dma_devconfig() fail ![%s]\n", __FUNCTION__, __LINE__, host->dma_name); - host->errorstep = 0x8; - return -ENOSYS; - } - - dma_len = dma_map_sg(&host->pdev->dev, data->sg, data->sg_len, sgDirection); - for (i = 0; i < dma_len; i++) - { - ret = rk29_dma_enqueue(host->dma_info.chn, host, sg_dma_address(&data->sg[i]),sg_dma_len(&data->sg[i])); - if(ret < 0) - { - printk(KERN_WARNING "%s..%d...call rk29_dma_devconfig() fail ![%s]\n", __FUNCTION__, __LINE__, host->dma_name); - host->errorstep = 0x93; - return -ENOSYS; - } - } - - rk29_sdmmc_control_host_dma(host, TRUE);// enable dma - ret = rk29_dma_ctrl(host->dma_info.chn, RK29_DMAOP_START); - if(ret < 0) - { - printk(KERN_WARNING "%s..%d...rk29_dma_ctrl start error![%s]\n", __FUNCTION__, __LINE__, host->dma_name); - host->errorstep = 0x94; - return -ENOSYS; - } - - return 0; -} - - -static int rk29_sdmmc_prepare_write_data(struct rk29_sdmmc *host, struct mmc_data *data) -{ - int output; - u32 i = 0; - u32 dataLen; - u32 count, *pBuf = (u32 *)host->pbuf; - - output = SDM_SUCCESS; - dataLen = data->blocks*data->blksz; - - host->dodma = 0; //DMA still no request; - - //SDMMC controller request the data is multiple of 4. - count = (dataLen >> 2) + ((dataLen & 0x3) ? 1:0); -#if 0 - if(count <= FIFO_DEPTH) -#else - #if defined(CONFIG_ARCH_RK29) - if( (count <= 0x20) && (RK29_CTRL_SDMMC_ID != host->pdev->id)) - #else - if( (count <= 0x80) && (RK29_CTRL_SDMMC_ID != host->pdev->id)) - #endif -#endif - { - - #if 1 - for (i=0; iregs, SDMMC_DATA, pBuf[i]); - } - #else - rk29_sdmmc_write_data_pio(host); - #endif - } - else - { - host->intInfo.desLen = count; - host->intInfo.transLen = 0; - host->intInfo.pBuf = (u32 *)pBuf; - - if(0)//(host->intInfo.desLen <= TX_WMARK) - { - //use pio-mode - rk29_sdmmc_write_data_pio(host); - return SDM_SUCCESS; - } - else - { - xbwprintk(7, "%s..%d... trace data, [%s]\n", __FUNCTION__, __LINE__, host->dma_name); - output = rk29_sdmmc_submit_data_dma(host, data); - if(output) - { - host->dodma = 0; - - printk(KERN_WARNING "%s..%d... CMD%d setupDMA failure!!!!! pre_cmd=%d [%s]\n", \ - __FUNCTION__, __LINE__, host->cmd->opcode,host->old_cmd, host->dma_name); - - host->errorstep = 0x81; - - rk29_sdmmc_control_host_dma(host, FALSE); - } - else - { - host->dodma = 1; - } - } - - } - - return output; -} - -static int rk29_sdmmc_prepare_read_data(struct rk29_sdmmc *host, struct mmc_data *data) -{ - u32 count = 0; - u32 dataLen; - int output; - - output = SDM_SUCCESS; - dataLen = data->blocks*data->blksz; - - host->dodma = 0;//DMA still no request; - - //SDMMC controller request the data is multiple of 4. - count = (dataLen >> 2) ;//+ ((dataLen & 0x3) ? 1:0); - - host->intInfo.desLen = (dataLen >> 2); - host->intInfo.transLen = 0; - host->intInfo.pBuf = (u32 *)host->pbuf; - - 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 <= RX_WMARK) - { - //use pio-mode - rk29_sdmmc_read_data_pio(host); - return SDM_SUCCESS; - } - else - { - output = rk29_sdmmc_submit_data_dma(host, data); - if(output) - { - host->dodma = 0; - - printk(KERN_WARNING "%s..%d... CMD%d setupDMA failure!!! [%s]\n", \ - __FUNCTION__, __LINE__, host->cmd->opcode, host->dma_name); - - host->errorstep = 0x82; - - rk29_sdmmc_control_host_dma(host, FALSE); - } - else - { - host->dodma = 1; - } - } - } - - return output; -} - - - -static int rk29_sdmmc_read_remain_data(struct rk29_sdmmc *host, u32 originalLen, void *pDataBuf) -{ - struct mmc_data *data; - struct scatterlist *sg; - u32 *buf, i = 0; - - if(1 == host->dodma) - { - data = host->data; - sg = host->sg; - buf = (u32 *)sg_virt(sg); - - for_each_sg(data->sg, sg, data->sg_len, i) - { - if (!sg) - return -1; - if (sg_is_last(sg)) - break; - } - - flush_dcache_page(sg_page(sg)); - host->sg = sg; - } - - rk29_sdmmc_read_data_pio(host); - - return SDM_SUCCESS; -} - -static void rk29_sdmmc_submit_data(struct rk29_sdmmc *host, struct mmc_data *data) -{ - int ret,i; - struct scatterlist *sg; - - if(data) - { - host->data = data; - data->error = 0; - host->cmd->data = data; - host->sg = data->sg; - - for_each_sg(data->sg, sg, data->sg_len, i) - { - if (sg->offset & 3 || sg->length & 3) - { - data->error = -EILSEQ; - printk("%s..%d..CMD%d(arg=0x%x), data->blksz=%d, data->blocks=%d [%s]\n", \ - __FUNCTION__, __LINE__, host->cmd->opcode,\ - host->cmd->arg,data->blksz, data->blocks, host->dma_name); - return ; - } - } - - data->bytes_xfered = 0; - host->pbuf = (u32*)sg_virt(data->sg); - host->pio_offset = 0; - - if (data->flags & MMC_DATA_STREAM) - { - host->cmdr |= SDMMC_CMD_STRM_MODE; //set stream mode - } - else - { - host->cmdr |= SDMMC_CMD_BLOCK_MODE; //set block mode - } - - //set the blocks and blocksize - rk29_sdmmc_write(host->regs, SDMMC_BYTCNT,data->blksz*data->blocks); - rk29_sdmmc_write(host->regs, SDMMC_BLKSIZ,data->blksz); - - xbwprintk(1, "%s..%d..CMD%d(arg=0x%x), data->blksz=%d, data->blocks=%d [%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(7,"%s..%d..CMD%d(arg=0x%x), data->blksz=%d, data->blocks=%d [%s]\n", \ - __FUNCTION__, __LINE__, host->cmd->opcode,host->cmd->arg,\ - 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(7, "%s..%d... read data len=%d [%s]\n", \ - __FUNCTION__, __LINE__, data->blksz*data->blocks, host->dma_name); - - ret = rk29_sdmmc_prepare_read_data(host, data); - } - - } - else - { - rk29_sdmmc_write(host->regs, SDMMC_BLKSIZ, 0); - rk29_sdmmc_write(host->regs, SDMMC_BYTCNT, 0); - } -} - - -static int sdmmc_send_cmd_start(struct rk29_sdmmc *host, unsigned int cmd) -{ - int tmo = RK29_SDMMC_SEND_START_TIMEOUT*10;//wait 60ms cycle. - -#if defined(CONFIG_ARCH_RK29) - rk29_sdmmc_write(host->regs, SDMMC_CMD, SDMMC_CMD_START | cmd); -#else - rk29_sdmmc_write(host->regs, SDMMC_CMD, SDMMC_CMD_USE_HOLD_REG |SDMMC_CMD_START | cmd); -#endif - while (--tmo && (rk29_sdmmc_read(host->regs, SDMMC_CMD) & SDMMC_CMD_START)) - { - udelay(2); - } - - if(!tmo && test_bit(RK29_SDMMC_CARD_PRESENT, &host->flags)) - { - printk(KERN_WARNING "%s.. %d set cmd(value=0x%x) register timeout error ! [%s]\n",\ - __FUNCTION__,__LINE__, cmd, host->dma_name); - - host->errorstep = 0x9; - return SDM_START_CMD_FAIL; - } - - return SDM_SUCCESS; -} - -static int rk29_sdmmc_get_cd(struct mmc_host *mmc) -{ - struct rk29_sdmmc *host = mmc_priv(mmc); - u32 cdetect=1; -#if defined(CONFIG_SDMMC0_RK29_SDCARD_DET_FROM_GPIO) - int i=0,cdetect1=0, cdetect2=0; -#endif - switch(host->pdev->id) - { - case 0: - { - #if defined(CONFIG_SDMMC0_RK29_SDCARD_DET_FROM_GPIO) - if(host->det_pin.io == INVALID_GPIO) - return 1; - - for(i=0;i<5;i++) - { - udelay(10); - cdetect1 = gpio_get_value(host->det_pin.io); - udelay(10); - cdetect2 = gpio_get_value(host->det_pin.io); - if(cdetect1 == cdetect2) - break; - } - cdetect = cdetect2; - if(host->det_pin.enable) - cdetect = cdetect?1:0; - else - cdetect = cdetect?0:1; - - #else - if(host->det_pin.io == INVALID_GPIO) - return 1; - - cdetect = rk29_sdmmc_read(host->regs, SDMMC_CDETECT); - - cdetect = (cdetect & SDMMC_CARD_DETECT_N)?0:1; - #endif - - break; - } - - case 1: - { - #if defined(CONFIG_USE_SDMMC1_FOR_WIFI_DEVELOP_BOARD) - cdetect = 1; - #else - if(host->det_pin.io == INVALID_GPIO) - return 1; - - cdetect = test_bit(RK29_SDMMC_CARD_PRESENT, &host->flags)?1:0; - #endif - break; - } - - default: - cdetect = 1; - break; - - } -#if defined(CONFIG_USE_SDMMC0_FOR_WIFI_DEVELOP_BOARD) - set_bit(RK29_SDMMC_CARD_PRESENT, &host->flags); - return 1; -#endif - - return cdetect; -} - - -/** - * Delay loop. - * Very rough microsecond delay loop for the system. - * \param[in] u32 Value in Number of Microseconds. - * \return Returns Void - **/ -void rk_sdmmc_udelay(u32 value) -{ - u32 counter; - for (counter = 0; counter < value ; counter++) - udelay(1); -} - -int rk_sdmmc_reset_host(struct rk29_sdmmc *host) -{ - int ret = SDM_SUCCESS; - int timeout; - //reset the host cotroller - rk29_sdmmc_write(host->regs, SDMMC_CTRL, SDMMC_CTRL_RESET); - udelay(10); - - timeout = 1000; - while((rk29_sdmmc_read(host->regs, SDMMC_CTRL) & SDMMC_CTRL_RESET)&& timeout--) - udelay(1); - if(0 == timeout) - { - ret = SDM_FALSE; - printk(KERN_ERR "%d.. reset ctrl_reset fail! [%s]=\n", __LINE__, host->dma_name); - goto EXIT_RESET; - } - -#if !defined(CONFIG_ARCH_RK29) - //reset DMA - rk29_sdmmc_write(host->regs, SDMMC_CTRL, SDMMC_CTRL_DMA_RESET); - udelay(10); - - timeout = 1000; - while((rk29_sdmmc_read(host->regs, SDMMC_CTRL) & SDMMC_CTRL_DMA_RESET)&& timeout--) - udelay(1); - if(0 == timeout) - { - ret = SDM_FALSE; - printk(KERN_ERR "%d.. reset dma_reset fail! [%s]=\n", __LINE__, host->dma_name); - goto EXIT_RESET; - } -#endif - - //reset FIFO - rk29_sdmmc_write(host->regs, SDMMC_CTRL, SDMMC_CTRL_FIFO_RESET); - udelay(10); - - timeout = 1000; - while((rk29_sdmmc_read(host->regs, SDMMC_CTRL) & SDMMC_CTRL_FIFO_RESET)&& timeout--) - udelay(1); - if(0 == timeout) - { - ret = SDM_FALSE; - printk(KERN_ERR "%d.. reset fofo_reset fail! [%s]=\n", __LINE__, host->dma_name); - goto EXIT_RESET; - } - -#if DRIVER_SDMMC_USE_IDMA - //reset the internal DMA Controller. - rk29_sdmmc_write(host->regs, SDMMC_BMOD, BMOD_SWR); - udelay(10); - - timeout = 1000; - while((rk29_sdmmc_read(host->regs, SDMMC_BMOD) & BMOD_SWR)&& timeout--) - udelay(1); - if(0 == timeout) - { - ret = SDM_FALSE; - printk(KERN_ERR "%d.. reset IDMAC fail! [%s]=\n", __LINE__, host->dma_name); - goto EXIT_RESET; - } - - // Program the BMOD register for DMA - rk29_sdmmc_write(host->regs, SDMMC_BMOD, BMOD_DSL_TWO); -#endif - -EXIT_RESET: - return ret; -} - -/****************************************************************/ -//reset the SDMMC controller of the current host -/****************************************************************/ -int rk29_sdmmc_reset_controller(struct rk29_sdmmc *host) -{ - u32 value = 0; - int timeOut = 0; - - rk29_sdmmc_write(host->regs, SDMMC_PWREN, POWER_ENABLE); - - //Clean the fifo. - for(timeOut=0; timeOutregs, SDMMC_STATUS) & SDMMC_STAUTS_FIFO_EMPTY) - break; - - value = rk29_sdmmc_read(host->regs, SDMMC_DATA); - } - - /* reset */ - value = rk_sdmmc_reset_host(host); - if(value) - return SDM_FALSE; - - /* FIFO threshold settings */ - rk29_sdmmc_write(host->regs, SDMMC_FIFOTH, FIFO_THRESHOLD_WATERMASK); - - rk29_sdmmc_write(host->regs, SDMMC_CTYPE, SDMMC_CTYPE_1BIT); - rk29_sdmmc_write(host->regs, SDMMC_CLKSRC, CLK_DIV_SRC_0); - - /* config debounce */ - host->bus_hz = clk_get_rate(host->clk); - -#if 0//Perhaps in some cases, it is necessary to restrict. - if((host->bus_hz > 52000000) || (host->bus_hz <= 0)) - { - printk(KERN_WARNING "%s..%s..%d..****Error!!!!!! Bus clock %d hz is beyond the prescribed limits. [%s]\n",\ - __FILE__, __FUNCTION__,__LINE__,host->bus_hz, host->dma_name); - - host->errorstep = 0x0B; - return SDM_PARAM_ERROR; - } -#endif - - rk29_sdmmc_write(host->regs, SDMMC_DEBNCE, (DEBOUNCE_TIME*host->bus_hz)& SDMMC_DEFAULT_DEBNCE_VAL); - - /* config interrupt */ - rk29_sdmmc_write(host->regs, SDMMC_RINTSTS, 0xFFFFFFFF); - - if(host->use_dma) - { - - if(RK29_CTRL_SDMMC_ID == host->pdev->id) - { - rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEDMA); - } - else - { - if(0== host->pdev->id) - { - #if !defined(CONFIG_USE_SDMMC0_FOR_WIFI_DEVELOP_BOARD) - #if defined(CONFIG_RK29_SDIO_IRQ_FROM_GPIO) - rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEDMA); - #else - rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEDMA | SDMMC_INT_SDIO); - #endif - #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) - #if defined(CONFIG_RK29_SDIO_IRQ_FROM_GPIO) - rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEDMA); - #else - rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEDMA | SDMMC_INT_SDIO); - #endif - #else - rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEDMA); - #endif - } - else - { - #if defined(CONFIG_RK29_SDIO_IRQ_FROM_GPIO) - rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEDMA); - #else - rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEDMA | SDMMC_INT_SDIO); - #endif - } - } - } - else - { - if(RK29_CTRL_SDMMC_ID == host->pdev->id) - { - rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEIO); - } - else - { - if(0== host->pdev->id) - { - #if !defined(CONFIG_USE_SDMMC0_FOR_WIFI_DEVELOP_BOARD) - #if defined(CONFIG_RK29_SDIO_IRQ_FROM_GPIO) - rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEIO); - #else - rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEIO | SDMMC_INT_SDIO); - #endif - #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) - #if defined(CONFIG_RK29_SDIO_IRQ_FROM_GPIO) - rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEIO); - #else - rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEIO | SDMMC_INT_SDIO); - #endif - #else - rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEIO); - #endif - } - else - { - #if defined(CONFIG_RK29_SDIO_IRQ_FROM_GPIO) - rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEIO); - #else - rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEIO | SDMMC_INT_SDIO); - #endif - } - } - } - - /* - ** Some machines may crash because of sdio-interrupt to open too early. - ** then, in the initialization phase, close the interruption. - ** noted by xbw,at 2013-07-25 - */ - rk29_sdmmc_write(host->regs, SDMMC_INTMASK,rk29_sdmmc_read(host->regs, SDMMC_INTMASK) & ~SDMMC_INT_SDIO); - - rk29_sdmmc_write(host->regs, SDMMC_PWREN, POWER_ENABLE); - -#if DRIVER_SDMMC_USE_IDMA - rk29_sdmmc_write(host->regs, SDMMC_CTRL, SDMMC_CTRL_INT_ENABLE | SDMMC_CTRL_USE_IDMAC); //Set the bit use_internal_dmac. -#else - rk29_sdmmc_write(host->regs, SDMMC_CTRL,SDMMC_CTRL_INT_ENABLE); // enable mci interrupt -#endif - - return SDM_SUCCESS; -} - - - - -//enable/disnable the clk. -static int rk29_sdmmc_control_clock(struct rk29_sdmmc *host, bool enable) -{ - u32 value = 0; - int tmo = 0; - int ret = SDM_SUCCESS; - - //wait previous start to clear - tmo = 1000; - while (--tmo && (rk29_sdmmc_read(host->regs, SDMMC_CMD) & SDMMC_CMD_START)) - { - udelay(1);//cpu_relax(); - } - if(!tmo) - { - host->errorstep = 0x0C; - ret = SDM_START_CMD_FAIL; - goto Error_exit; - } - - if(RK29_CTRL_SDMMC_ID == host->pdev->id) - { - //SDMMC use low-power mode - #if SDMMC_CLOCK_TEST - if (enable) - { - value = (SDMMC_CLKEN_ENABLE); - } - else - { - 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 - { - //SDIO-card use non-low-power mode - if (enable) - { - value = (SDMMC_CLKEN_ENABLE); - } - else - { - value = (SDMMC_CLKEN_DISABLE); - } - } - - rk29_sdmmc_write(host->regs, SDMMC_CLKENA, value); - - /* inform CIU */ - ret = sdmmc_send_cmd_start(host, SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT); - if(ret != SDM_SUCCESS) - { - goto Error_exit; - } - - return SDM_SUCCESS; - -Error_exit: - printk(KERN_WARNING "\n%s....%d.. control clock fail!!! Enable=%d, ret=0x%x [%s]\n",\ - __FILE__,__LINE__,enable,ret, host->dma_name); - - return ret; - -} - - -//adjust the frequency.ie, to set the frequency division control -int rk29_sdmmc_change_clk_div(struct rk29_sdmmc *host, u32 freqHz) -{ - u32 div; - u32 tmo; - int ret = SDM_SUCCESS; - - if(0 == freqHz) - { - ret = SDM_PARAM_ERROR; - goto SetFreq_error; - } - - ret = rk29_sdmmc_control_clock(host, FALSE); - if (ret != SDM_SUCCESS) - { - goto SetFreq_error; - } - - - host->bus_hz = clk_get_rate(host->clk); - if((host->bus_hz > 52000000) || (host->bus_hz <= 0)) - { - printk(KERN_WARNING "%s..%s..%d..****Error!!!!!! Bus clock %d hz is beyond the prescribed limits [%s]\n",\ - __FILE__, __FUNCTION__,__LINE__,host->bus_hz, host->dma_name); - - host->errorstep = 0x0D; - ret = SDM_PARAM_ERROR; - goto SetFreq_error; - } - - //calculate the divider - div = host->bus_hz/freqHz + ((( host->bus_hz%freqHz ) > 0) ? 1:0 ); - if( (div & 0x01) && (1 != div) ) - { - //It is sure that the value of div is even. - ++div; - } - - if(div > 1) - { - host->clock = host->bus_hz/div; - } - else - { - host->clock = host->bus_hz; - } - div = (div >> 1); - - //wait previous start to clear - tmo = 1000; - while (--tmo && (rk29_sdmmc_read(host->regs, SDMMC_CMD) & SDMMC_CMD_START)) - { - udelay(1);//cpu_relax(); - } - if(!tmo) - { - host->errorstep = 0x0E; - ret = SDM_START_CMD_FAIL; - goto SetFreq_error; - } - - /* set clock to desired speed */ - rk29_sdmmc_write(host->regs, SDMMC_CLKDIV, div); - - /* inform CIU */ - ret = sdmmc_send_cmd_start(host, SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT); - if(ret != SDM_SUCCESS) - { - host->errorstep = 0x0E1; - goto SetFreq_error; - } - - if(host->old_div != div) - { - printk(KERN_INFO "%s..%d.. newDiv=%u, newCLK=%uKhz [%s]\n", \ - __FUNCTION__, __LINE__,div, host->clock/1000, host->dma_name); - } - - ret = rk29_sdmmc_control_clock(host, TRUE); - if(ret != SDM_SUCCESS) - { - goto SetFreq_error; - } - host->old_div = div; - - return SDM_SUCCESS; - -SetFreq_error: - - printk(KERN_WARNING "%s..%d.. change division fail, errorStep=0x%x,ret=%d [%s]\n",\ - __FILE__, __LINE__,host->errorstep,ret, host->dma_name); - - return ret; - -} - -int rk29_sdmmc_hw_init(void *data) -{ - struct rk29_sdmmc *host = (struct rk29_sdmmc *)data; - struct rk29_sdmmc_platform_data *pdata = host->pdev->dev.platform_data; - - //set the iomux - host->ctype = SDMMC_CTYPE_1BIT; - host->set_iomux(host->pdev->id, host->ctype); - - if( pdata && pdata->sd_vcc_reset ) - { - int cdetect = gpio_get_value(host->det_pin.io) ; - if(host->det_pin.enable) - { - cdetect = cdetect?1:0; - } - else - { - cdetect = cdetect?0:1; - } - - if( cdetect ) - { - pdata->sd_vcc_reset(); - } - } - - /* reset controller */ - rk29_sdmmc_reset_controller(host); - - rk29_sdmmc_change_clk_div(host, FOD_FREQ); - - return SDM_SUCCESS; -} - - - -int rk29_sdmmc_set_buswidth(struct rk29_sdmmc *host) -{ - //int ret; - switch (host->ctype) - { - case SDMMC_CTYPE_1BIT: - case SDMMC_CTYPE_4BIT: - break; - case SDMMC_CTYPE_8BIT: - return SDM_PARAM_ERROR; //Now, not support 8 bit width - default: - return SDM_PARAM_ERROR; - } - - host->set_iomux(host->pdev->id, host->ctype); - - /* Set the current bus width */ - rk29_sdmmc_write(host->regs, SDMMC_CTYPE, host->ctype); - - return SDM_SUCCESS; -} - - -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: - break; - case STATE_SENDING_CMD: - host->cmd_status |= SDMMC_INT_RTO; - host->cmd->error = -ETIME; - rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,(SDMMC_INT_CMD_DONE | SDMMC_INT_RTO)); // clear interrupt - rk29_sdmmc_set_pending(host, EVENT_CMD_COMPLETE); - tasklet_schedule(&host->tasklet); - break; - case STATE_DATA_BUSY: - host->data_status |= (SDMMC_INT_DCRC|SDMMC_INT_EBE); - host->cmd->data->error = -EILSEQ; - rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_DTO); // clear interrupt - rk29_sdmmc_set_pending(host, EVENT_DATA_COMPLETE); -#if SDMMC_USE_INT_UNBUSY - rk29_sdmmc_set_pending(host, EVENT_DATA_UNBUSY); -#endif - tasklet_schedule(&host->tasklet); - break; -#if SDMMC_USE_INT_UNBUSY - case STATE_DATA_UNBUSY: - host->data_status |= (SDMMC_INT_DCRC|SDMMC_INT_EBE); - host->cmd->data->error = -EILSEQ; - rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_UNBUSY); // clear interrupt - rk29_sdmmc_set_pending(host, EVENT_DATA_UNBUSY); - tasklet_schedule(&host->tasklet); - break; -#endif - case STATE_SENDING_STOP: - host->cmd_status |= SDMMC_INT_RTO; - host->cmd->error = -ETIME; - rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,(SDMMC_INT_CMD_DONE | SDMMC_INT_RTO)); // clear interrupt - rk29_sdmmc_set_pending(host, EVENT_CMD_COMPLETE); - tasklet_schedule(&host->tasklet); - break; - case STATE_DATA_END: - break; - default: - break; - } -} - - -static void rk29_sdmmc_INT_CMD_DONE_timeout(unsigned long host_data) -{ - struct rk29_sdmmc *host = (struct rk29_sdmmc *) host_data; - - rk29_sdmmc_enable_irq(host, false); - - if(STATE_SENDING_CMD == host->state) - { - if((0==host->cmd->retries)&&(12 != host->cmd->opcode)) - { - printk(KERN_WARNING "%d... cmd=%d(arg=0x%x), INT_CMD_DONE timeout, errorStep=0x%x, host->state=%x [%s]\n",\ - __LINE__,host->cmd->opcode, host->cmd->arg,host->errorstep,host->state,host->dma_name); - - if(++host->timeout_times >= 3) - { - printk(KERN_WARNING "I am very sorry to tell you,in order to make the machine correctly,you must remove-insert card again."); - host->mmc->re_initialized_flags = 0; - host->timeout_times = 0; - } - } - rk29_sdmmc_write(host->regs, SDMMC_RINTSTS, 0xFFFFFFFE); // clear INT,except for SDMMC_INT_CD - rk29_sdmmc_dealwith_timeout(host); - } - - rk29_sdmmc_enable_irq(host, true); -} - - -static void rk29_sdmmc_INT_DTO_timeout(unsigned long host_data) -{ - struct rk29_sdmmc *host = (struct rk29_sdmmc *) host_data; - - rk29_sdmmc_enable_irq(host, false); - -#if SDMMC_USE_INT_UNBUSY - if( (host->cmdr & SDMMC_CMD_DAT_EXP) &&((STATE_DATA_BUSY == host->state)||(STATE_DATA_UNBUSY == host->state) )) -#else - if( (host->cmdr & SDMMC_CMD_DAT_EXP) && (STATE_DATA_BUSY == host->state)) -#endif - { - if(0==host->cmd->retries) - { - printk(KERN_WARNING "%s..%d...cmd=%d DTO_timeout,cmdr=0x%x, errorStep=0x%x, Hoststate=%x [%s]\n", \ - __FUNCTION__, __LINE__,host->cmd->opcode,host->cmdr ,host->errorstep,host->state,host->dma_name); - - if(++host->timeout_times >= 3) - { - printk(KERN_WARNING "I am very sorry to tell you,in order to make the machine correctly,you must remove-insert card again."); - host->mmc->re_initialized_flags = 0; - host->timeout_times = 0; - } - } - rk29_sdmmc_write(host->regs, SDMMC_RINTSTS, 0xFFFFFFFE); // clear INT,except for SDMMC_INT_CD - rk29_sdmmc_dealwith_timeout(host); - } - rk29_sdmmc_enable_irq(host, true); - -} - - -//to excute a request -static int rk29_sdmmc_start_request(struct mmc_host *mmc ) -{ - struct rk29_sdmmc *host = mmc_priv(mmc); - struct mmc_request *mrq; - struct mmc_command *cmd; - - u32 cmdr, ret; - unsigned long iflags; - - spin_lock_irqsave(&host->lock, iflags); - - mrq = host->new_mrq; - cmd = mrq->cmd; - cmd->error = 0; - - cmdr = rk29_sdmmc_prepare_command(cmd); - ret = SDM_SUCCESS; - - - /*clean FIFO if it is a new request*/ - if((RK29_CTRL_SDMMC_ID == host->pdev->id) && ( !(cmdr & SDMMC_CMD_STOP))) - { - ret = rk29_sdmmc_reset_fifo(host); - if(SDM_SUCCESS != ret) - { - host->mrq = host->new_mrq;/// - cmd->error = -ENOMEDIUM; - host->errorstep = 0x0F; - ret = SDM_FALSE; - goto start_request_Err; - } - } - - //check data-busy if the current command has the bit13 in command register. - if( cmdr & SDMMC_CMD_PRV_DAT_WAIT ) - { - if(SDM_SUCCESS != rk29_sdmmc_wait_unbusy(host)) //if(rk29_sdmmc_read(host->regs, SDMMC_STATUS) & SDMMC_STAUTS_DATA_BUSY) - { - host->mrq = host->new_mrq;/// - cmd->error = -ETIMEDOUT; - ret = SDM_BUSY_TIMEOUT; - host->errorstep = 0x10; - if(0 == cmd->retries) - { - printk(KERN_WARNING "%s..Error happen in CMD_PRV_DAT_WAIT. STATUS-reg=0x%x [%s]\n", \ - __FUNCTION__, rk29_sdmmc_read(host->regs, SDMMC_STATUS),host->dma_name); - } - rk29_sdmmc_clear_fifo(host); - goto start_request_Err; - } - } - - host->state = STATE_SENDING_CMD; - host->mrq = host->new_mrq; - mrq = host->mrq; - cmd = mrq->cmd; - cmd->error = 0; - cmd->data = NULL; - - host->cmdr = cmdr; - host->cmd = cmd; - host->data_status = 0; - host->data = NULL; - - host->errorstep = 0; - host->dodma = 0; - - - - //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(). [%s]\n", \ - __FUNCTION__, __LINE__ , cmd->opcode,host->dma_name); - - if(RK29_CTRL_SDMMC_ID == host->pdev->id) - { - mod_timer(&host->request_timer, jiffies + msecs_to_jiffies(RK29_SDMMC_SEND_START_TIMEOUT+700)); - } - else - { - mod_timer(&host->request_timer, jiffies + msecs_to_jiffies(RK29_SDMMC_SEND_START_TIMEOUT+500)); - } - - - ret = rk29_sdmmc_start_command(host, cmd, host->cmdr); - if(SDM_SUCCESS != ret) - { - cmd->error = -ETIMEDOUT; - if(0==cmd->retries) - { - printk(KERN_WARNING "%s..%d... start_command(CMD%d, arg=%x, retries=%d) fail! ret=%d . [%s]\n",\ - __FUNCTION__, __LINE__ , cmd->opcode,cmd->arg, cmd->retries,ret, host->dma_name); - } - host->errorstep = 0x11; - del_timer_sync(&host->request_timer); - - goto start_request_Err; - } - host->errorstep = 0xfd; - -#if DRIVER_SDMMC_USE_IDMA - /* Check if it is a data command. If yes, we need to handle only IDMAC interrupts - ** So we disable the Slave mode interrupts and enable DMA mode interrupts. - ** CTRL and BMOD registers are set up for DMA mode of operation - */ - if(mrq->data) - { - rk29_sdmmc_write(host->regs, SDMMC_INTMASK, 0x00000000);//Mask all slave interrupts - rk29_sdmmc_write(host->regs, SDMMC_IDINTEN, IDMAC_EN_INT_ALL); - rk29_sdmmc_write(host->regs, SDMMC_CTRL, SDMMC_CTRL_USE_IDMAC); - rk29_sdmmc_write(host->regs, SDMMC_BMOD, BMOD_DE); - rk29_sdmmc_write(host->regs, SDMMC_BMOD, BMOD_DSL_TWO);// Program the BMOD register for DMA - rk29_sdmmc_write(host->regs, SDMMC_FIFOTH, FIFO_THRESHOLD_WATERMASK); - } -#endif - - 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 [%s]\n\n",\ - __FUNCTION__, __LINE__, host->cmd->opcode,ret, \ - host->state,host->cmd_status, host->pending_events,host->completed_events,host->dma_name); - - spin_unlock_irqrestore(&host->lock, iflags); - - return SDM_SUCCESS; - -start_request_Err: - rk29_sdmmc_start_error(host); - - if(0 == cmd->retries) - { - printk(KERN_WARNING "%s: CMD%d(arg=%x) fail to start request. err=%d, Errorstep=0x%x [%s]\n",\ - __FUNCTION__, cmd->opcode, cmd->arg,ret,host->errorstep,host->dma_name); - } - - host->state = STATE_IDLE; //modifyed by xbw at 2011-08-15 - - if(host->mrq && host->mmc->doneflag && host->complete_done) - { - host->mmc->doneflag = 0; - host->complete_done = 0; - spin_unlock_irqrestore(&host->lock, iflags); - - mmc_request_done(host->mmc, host->mrq); - } - else - { - spin_unlock_irqrestore(&host->lock, iflags); - } - - return ret; - -} - - -static void rk29_sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq) -{ - unsigned long iflags; - int i,ret; - struct rk29_sdmmc *host = mmc_priv(mmc); - - spin_lock_irqsave(&host->lock, iflags); - - #if 0 - //set 1 to close the controller for Debug. - if(RK29_CTRL_SDIO1_ID==host->pdev->id)//if(RK29_CTRL_SDMMC_ID==host->pdev->id)// - { - mrq->cmd->error = -ENOMEDIUM; - printk(KERN_WARNING "%s..%d.. ==== The %s had been closed by myself for the experiment. [%s]\n",\ - __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); - return; - } - #endif - - i=0; - while(++i>2) - { - ret = rk29_sdmmc_wait_unbusy(host); - if(SDM_SUCCESS == ret) - break; - } - - xbwprintk(6, "\n%s..%d..New cmd=%2d(arg=0x%8x)=== cardPresent=0x%lu, state=0x%x [%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) - { - if(!rk29_sdmmc_get_cd(mmc) || ((0==mmc->re_initialized_flags)&&(MMC_GO_IDLE_STATE != mrq->cmd->opcode))) - { - mrq->cmd->error = -ENOMEDIUM; - - if((RK29_CTRL_SDMMC_ID == host->pdev->id)&&(0==mrq->cmd->retries)) - { - if(host->old_cmd != mrq->cmd->opcode) - { - if( ((17==host->old_cmd)&&(18==mrq->cmd->opcode)) || ((18==host->old_cmd)&&(17==mrq->cmd->opcode)) ||\ - ((24==host->old_cmd)&&(25==mrq->cmd->opcode)) || ((25==host->old_cmd)&&(24==mrq->cmd->opcode))) - { - host->old_cmd = mrq->cmd->opcode; - if(host->error_times++ % (RK29_ERROR_PRINTK_INTERVAL*100) ==0) - { - printk(KERN_INFO "%s: Refuse to run CMD%2d(arg=0x%8x) due to the removal of card. 1==[%s]==\n", \ - __FUNCTION__, mrq->cmd->opcode, mrq->cmd->arg, host->dma_name); - } - } - else - { - host->old_cmd = mrq->cmd->opcode; - host->error_times = 0; - printk(KERN_INFO "%s: Refuse to run CMD%2d(arg=0x%8x) due to the removal of card. 2==[%s]==\n", \ - __FUNCTION__, mrq->cmd->opcode, mrq->cmd->arg, host->dma_name); - } - } - else - { - if(host->error_times++ % (RK29_ERROR_PRINTK_INTERVAL*100) ==0) - { - printk(KERN_INFO "%s: Refuse to run CMD%2d(arg=0x%8x) due to the removal of card. 3==[%s]==\n", \ - __FUNCTION__, mrq->cmd->opcode, mrq->cmd->arg, host->dma_name); - } - host->old_cmd = mrq->cmd->opcode; - } - } - host->state = STATE_IDLE; - spin_unlock_irqrestore(&host->lock, iflags); - - mmc_request_done(mmc, mrq); - return; - } - else - { - if(host->old_cmd != mrq->cmd->opcode) - { - 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; - } - - } - - host->new_mrq = mrq; - - spin_unlock_irqrestore(&host->lock, iflags); - - rk29_sdmmc_start_request(mmc); -} - - -extern void rk29_sdmmc_gpio_open(int device_id, int on); -static void rk29_sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - int timeout = 250; - unsigned int value; - struct rk29_sdmmc *host = mmc_priv(mmc); - - rk29_sdmmc_enable_irq(host, false); - - //if(host->bus_mode != ios->power_mode) - { - switch (ios->power_mode) - { - case MMC_POWER_UP: - rk29_sdmmc_write(host->regs, SDMMC_PWREN, POWER_ENABLE); - - //reset the controller if it is SDMMC0 - if(RK29_CTRL_SDMMC_ID == host->pdev->id) - { - xbwprintk(7, "%s..%d..POWER_UP, call reset_controller, initialized_flags=%d [%s]\n",\ - __FUNCTION__, __LINE__, host->mmc->re_initialized_flags,host->dma_name); - - //power-on; - gpio_direction_output(host->gpio_power_en, host->gpio_power_en_level); - - mdelay(5); - - rk29_sdmmc_hw_init(host); - } - - break; - case MMC_POWER_OFF: - - if(RK29_CTRL_SDMMC_ID == host->pdev->id) - { - mdelay(5); - rk29_sdmmc_control_clock(host, FALSE); - rk29_sdmmc_write(host->regs, SDMMC_PWREN, POWER_DISABLE); - mdelay(5); - if(5 == host->bus_mode) - { - mdelay(5); - xbwprintk(7, "%s..%d..Fisrt powerOFF, call reset_controller [%s]\n", \ - __FUNCTION__, __LINE__,host->dma_name); - - rk29_sdmmc_reset_controller(host); - } - - - rk29_sdmmc_gpio_open(0, 0); - //power-off - gpio_direction_output(host->gpio_power_en, !(host->gpio_power_en_level)); - goto out; - } - - break; - default: - break; - } - - host->bus_mode = ios->power_mode; - - } - - 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(KERN_WARNING "%s..%d...Waiting for SDMMC%d controller to be IDLE timeout.[%s]\n", \ - __FUNCTION__, __LINE__, host->pdev->id, host->dma_name); - - goto out; - } - } - - - if((!(test_bit(RK29_SDMMC_CARD_PRESENT, &host->flags))|| !rk29_sdmmc_get_cd(host->mmc)) - &&(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) - { - case MMC_BUS_WIDTH_1: - host->ctype = SDMMC_CTYPE_1BIT; - break; - case MMC_BUS_WIDTH_4: - host->ctype = SDMMC_CTYPE_4BIT; - break; - case MMC_BUS_WIDTH_8: - host->ctype = SDMMC_CTYPE_8BIT; - break; - default: - host->ctype = 0; - break; - } - - rk29_sdmmc_set_buswidth(host); - - } - - if (ios->clock && (ios->clock != host->clock)) - { - /* - * Use mirror of ios->clock to prevent race with mmc - * core ios update when finding the minimum. - */ - //host->clock = ios->clock; - rk29_sdmmc_change_clk_div(host, ios->clock); - } -out: - rk29_sdmmc_enable_irq(host, true); - -} - -static int rk29_sdmmc_get_ro(struct mmc_host *mmc) -{ - 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 = (host->protect_level == gpio_get_value(host->write_protect)?1:0; - - xbwprintk(7,"%s..%d.. write_prt_pin=%d, get_ro=%d. [%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; - -} - -#if defined(CONFIG_RK29_SDIO_IRQ_FROM_GPIO) -static irqreturn_t rk29_sdmmc_sdio_irq_cb(int irq, void *dev_id) -{ - struct rk29_sdmmc *host = dev_id; - - if(host && host->mmc) - mmc_signal_sdio_irq(host->mmc); - - return IRQ_HANDLED; -} -#endif - - -static void rk29_sdmmc_enable_sdio_irq(struct mmc_host *mmc, int enable) -{ -#if !defined(CONFIG_RK29_SDIO_IRQ_FROM_GPIO) - u32 intmask; - unsigned long flags; -#endif - struct rk29_sdmmc *host = mmc_priv(mmc); - -#if defined(CONFIG_RK29_SDIO_IRQ_FROM_GPIO) - if(enable) - { - enable_irq(host->sdio_irq); - - #if !defined(CONFIG_MTK_COMBO_DRIVER_VERSION_JB2) - enable_irq_wake(host->sdio_irq); - #endif - } - else - { - disable_irq_nosync(host->sdio_irq); - - #if !defined(CONFIG_MTK_COMBO_DRIVER_VERSION_JB2) - disable_irq_wake(host->sdio_irq); - #endif - } - -#else - spin_lock_irqsave(&host->lock, flags); - - intmask = rk29_sdmmc_read(host->regs, SDMMC_INTMASK); - if(enable) - rk29_sdmmc_write(host->regs, SDMMC_INTMASK, intmask | SDMMC_INT_SDIO); - else - rk29_sdmmc_write(host->regs, SDMMC_INTMASK, intmask & ~SDMMC_INT_SDIO); - - spin_unlock_irqrestore(&host->lock, flags); -#endif - - -} - -static void rk29_sdmmc_init_card(struct mmc_host *mmc, struct mmc_card *card) -{ - card->quirks = MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; - -} - -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; timeoutregs, 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 int rk_sdmmc_signal_voltage_switch(struct mmc_host *mmc, - struct mmc_ios *ios) -{ - struct rk29_sdmmc *host; - unsigned int value,uhs_reg; - - host = mmc_priv(mmc); - - /* - * We first check whether the request is to set signalling voltage - * to 3.3V. If so, we change the voltage to 3.3V and return quickly. - */ - uhs_reg = rk29_sdmmc_read(host->regs, SDMMC_UHS_REG); - if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) - { - //set 3.3v - #if SWITCH_VOLTAGE_18_33 - if(NULL != SWITCH_VOLTAGE_18_33) - gpio_direction_output(SWITCH_VOLTAGE_18_33, SWITCH_VOLTAGE_ENABLE_VALUE_33); - #endif - //set High-power mode - value = rk29_sdmmc_read(host->regs, SDMMC_CLKENA); - rk29_sdmmc_write(host->regs,SDMMC_CLKENA , value& ~SDMMC_CLKEN_LOW_PWR); - - //SDMMC_UHS_REG - rk29_sdmmc_write(host->regs,SDMMC_UHS_REG , uhs_reg & ~SDMMC_UHS_VOLT_REG_18); - - /* Wait for 5ms */ - usleep_range(5000, 5500); - - /* 3.3V regulator output should be stable within 5 ms */ - uhs_reg = rk29_sdmmc_read(host->regs, SDMMC_UHS_REG); - if( !(uhs_reg & SDMMC_UHS_VOLT_REG_18)) - return 0; - else - { - printk(KERN_INFO ": Switching to 3.3V " - "signalling voltage failed. [%s]\n", host->dma_name); - return -EIO; - } - - } - else if (!(uhs_reg & SDMMC_UHS_VOLT_REG_18) && (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180)) - { - /* Stop SDCLK */ - rk29_sdmmc_control_clock(host, FALSE); - - /* Check whether DAT[3:0] is 0000 */ - value = rk29_sdmmc_read(host->regs, SDMMC_STATUS); - if ((value & SDMMC_STAUTS_DATA_BUSY) == 0) - { - /* - * Enable 1.8V Signal Enable in the Host register - */ - rk29_sdmmc_write(host->regs,SDMMC_UHS_REG , uhs_reg |SDMMC_UHS_VOLT_REG_18); - - /* Wait for 5ms */ - usleep_range(5000, 5500); - - uhs_reg = rk29_sdmmc_read(host->regs, SDMMC_UHS_REG); - if( uhs_reg & SDMMC_UHS_VOLT_REG_18) - { - - /* Provide SDCLK again and wait for 1ms*/ - rk29_sdmmc_control_clock(host, TRUE); - usleep_range(1000, 1500); - - /* - * If DAT[3:0] level is 1111b, then the card - * was successfully switched to 1.8V signaling. - */ - value = rk29_sdmmc_read(host->regs, SDMMC_STATUS); - if ((value & SDMMC_STAUTS_DATA_BUSY) == 0) - return 0; - } - } - - /* - * If we are here, that means the switch to 1.8V signaling - * failed. We power cycle the card, and retry initialization - * sequence by setting S18R to 0. - */ - #if SWITCH_VOLTAGE_18_33 - if(NULL != SWITCH_VOLTAGE_18_33) - gpio_direction_output(SWITCH_VOLTAGE_18_33, !(SWITCH_VOLTAGE_ENABLE_VALUE_33)); - #endif - - /* Wait for 1ms as per the spec */ - usleep_range(1000, 1500); - - #if SWITCH_VOLTAGE_18_33 - if(NULL != SWITCH_VOLTAGE_18_33) - gpio_direction_output(SWITCH_VOLTAGE_18_33, SWITCH_VOLTAGE_ENABLE_VALUE_33); - #endif - - printk(KERN_INFO ": Switching to 1.8V signalling " - "voltage failed, retrying with S18R set to 0. [%s]\n", host->dma_name); - return -EAGAIN; - - } - else - { - /* No signal voltage switch required */ - return 0; - } -} - - -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, - .start_signal_voltage_switch = rk_sdmmc_signal_voltage_switch, - }, - { - .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 = host->data_status; - int output=SDM_SUCCESS; - - xbwprintk(7, "%s..%d... cmd=%d, host->state=0x%x,\n pendingEvent=0x%lu, completeEvents=0x%lu [%s]\n",\ - __FUNCTION__, __LINE__,cmd->opcode,host->state, host->pending_events,host->completed_events,host->dma_name); - - del_timer_sync(&host->DTO_timer); - - if(RK29_CTRL_SDMMC_ID == host->pdev->id) - { - rk29_sdmmc_write(host->regs, SDMMC_RINTSTS, 0xFFFFFFFF); //added by xbw at 2011-08-15 - } - - //stop DMA - if(host->dodma) - { - rk29_sdmmc_stop_dma(host); - rk29_sdmmc_control_host_dma(host, FALSE); - host->dodma = 0; - } - - if(cmd->error) - { - goto exit;//It need not to wait-for-busy if the CMD-ERROR happen. - } - host->errorstep = 0xf7; - if(cmd->data) - { - if(host->cmdr & SDMMC_CMD_DAT_WRITE) - { - if(status & (SDMMC_INT_DCRC | SDMMC_INT_EBE)) - { - cmd->data->error = -EILSEQ; - output = SDM_DATA_CRC_ERROR; - host->errorstep = 0x16; - } - else - { - output = rk29_sdmmc_wait_unbusy(host); - if(SDM_SUCCESS != output) - { - host->errorstep = 0x17; - cmd->data->error = -ETIMEDOUT; - } - - host->data->bytes_xfered = host->data->blocks * host->data->blksz; - } - } - else - { - if( status & SDMMC_INT_SBE) - { - cmd->data->error = -EIO; - host->errorstep = 0x18; - output = SDM_START_BIT_ERROR; - } - else if((status & SDMMC_INT_EBE) && (cmd->opcode != 14)) //MMC4.0, BUSTEST_R, A host read the reserved bus testing data parttern from a card. - { - cmd->data->error = -EILSEQ; - host->errorstep = 0x19; - output = SDM_END_BIT_ERROR; - } - else if(status & SDMMC_INT_DRTO) - { - cmd->data->error = -ETIMEDOUT; - host->errorstep = 0x1A; - output = SDM_DATA_READ_TIMEOUT; - } - else if(status & SDMMC_INT_DCRC) - { - host->errorstep = 0x1B; - cmd->data->error = -EILSEQ; - output = SDM_DATA_CRC_ERROR; - } - else - { - output = rk29_sdmmc_read_remain_data(host, (host->data->blocks * host->data->blksz), host->pbuf); - if(SDM_SUCCESS == output) - { - host->data->bytes_xfered = host->data->blocks * host->data->blksz; - } - } - } - } - - if(SDM_SUCCESS == output) - { - if ((mmc_resp_type(cmd) == MMC_RSP_R1B) || (MMC_STOP_TRANSMISSION == cmd->opcode)) - { - output = rk29_sdmmc_wait_unbusy(host); - if((SDM_SUCCESS != output) && (!host->mrq->cmd->error)) - { - printk(KERN_WARNING "%s..%d... CMD12 wait busy timeout!!!!! errorStep=0x%x [%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; - } - } - } - host->errorstep = 0xf6; - - //trace error - if(cmd->data && cmd->data->error) - { - if( (!cmd->error) && (0==cmd->retries)) - { - printk(KERN_WARNING "%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. [%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: - -#ifdef RK29_SDMMC_LIST_QUEUE - if (!list_empty(&host->queue)) - { - printk(KERN_WARNING "%s..%d.. Danger!Danger!. continue the next request in the queue. [%s]\n",\ - __FUNCTION__, __LINE__, host->dma_name); - - host = list_entry(host->queue.next, - struct rk29_sdmmc, queue_node); - list_del(&host->queue_node); - host->state = STATE_SENDING_CMD; - rk29_sdmmc_start_request(host->mmc); - } - else - { - dev_vdbg(&host->pdev->dev, "list empty\n"); - host->state = STATE_IDLE; - } -#else - dev_vdbg(&host->pdev->dev, "list empty\n"); - host->state = STATE_IDLE; -#endif - -} - -static int rk29_sdmmc_command_complete(struct rk29_sdmmc *host, - struct mmc_command *cmd) -{ - u32 value, status = host->cmd_status; - int timeout, output= SDM_SUCCESS; - - xbwprintk(7, "%s..%d. cmd=%d, host->state=0x%x, cmdINT=0x%x\n,pendingEvent=0x%lu,completeEvents=0x%lu. [%s]\n",\ - __FUNCTION__, __LINE__,cmd->opcode,host->state,status, host->pending_events,host->completed_events,host->dma_name); - - - del_timer_sync(&host->request_timer); - - host->cmd_status = 0; - - if((RK29_CTRL_SDMMC_ID == host->pdev->id) && (host->cmdr & SDMMC_CMD_STOP)) - { - output = rk29_sdmmc_reset_fifo(host); - if (SDM_SUCCESS != output) - { - printk(KERN_WARNING "%s..%d......reset fifo fail! CMD%d(arg=0x%x, Retries=%d) [%s]\n",__FUNCTION__, __LINE__, \ - cmd->opcode, cmd->arg, cmd->retries,host->dma_name); - - cmd->error = -ETIMEDOUT; - host->mrq->cmd->error = cmd->error; - output = SDM_ERROR; - host->errorstep = 0x1C; - goto CMD_Errror; - } - } - - if(status & SDMMC_INT_RTO) - { - cmd->error = -ENOMEM; - host->mrq->cmd->error = cmd->error; - output = SDM_BUSY_TIMEOUT; - host->errorstep = 0x1E; - - //rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_RTO); - rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,0xFFFFFFFF); //modifyed by xbw at 2011-08-15 - - if(host->use_dma)//if(host->dodma) - { - if(host->dodma) - { - rk29_sdmmc_stop_dma(host); - rk29_sdmmc_control_host_dma(host, FALSE); - host->dodma = 0; - } - - value = rk29_sdmmc_read(host->regs, SDMMC_CTRL); - value |= SDMMC_CTRL_FIFO_RESET; - rk29_sdmmc_write(host->regs, SDMMC_CTRL, value); - - timeout = 1000; - while (((value = rk29_sdmmc_read(host->regs, SDMMC_CTRL)) & (SDMMC_CTRL_FIFO_RESET)) && (timeout > 0)) - { - udelay(1); - timeout--; - } - if (timeout == 0) - { - output = SDM_FALSE; - host->errorstep = 0x1D; - printk(KERN_WARNING "%s..%d......reset CTRL fail! CMD%d(arg=0x%x, Retries=%d).[%s]\n",\ - __FUNCTION__, __LINE__, cmd->opcode, cmd->arg, cmd->retries,host->dma_name); - - goto CMD_Errror; - } - } - - } - - if(cmd->flags & MMC_RSP_PRESENT) - { - if(cmd->flags & MMC_RSP_136) - { - cmd->resp[3] = rk29_sdmmc_read(host->regs, SDMMC_RESP0); - cmd->resp[2] = rk29_sdmmc_read(host->regs, SDMMC_RESP1); - cmd->resp[1] = rk29_sdmmc_read(host->regs, SDMMC_RESP2); - cmd->resp[0] = rk29_sdmmc_read(host->regs, SDMMC_RESP3); - } - else - { - cmd->resp[0] = rk29_sdmmc_read(host->regs, SDMMC_RESP0); - } - } - - #if 1 - if(cmd->error) - { - del_timer_sync(&host->DTO_timer); - - //trace error - if((0==cmd->retries) && (host->error_times++%(RK29_ERROR_PRINTK_INTERVAL*3) == 0) && (12 != cmd->opcode)) - { - if( ((RK29_CTRL_SDMMC_ID==host->pdev->id)&&(MMC_SLEEP_AWAKE!=cmd->opcode)) || - ((RK29_CTRL_SDMMC_ID!=host->pdev->id)&&(MMC_SEND_EXT_CSD!=cmd->opcode)) ) - { - printk(KERN_WARNING "%s..%d...CMD%d(arg=0x%x), hoststate=%d, errorTimes=%d, errorStep=0x%x ! [%s]\n",\ - __FUNCTION__, __LINE__, cmd->opcode, cmd->arg, host->state,host->error_times,host->errorstep, host->dma_name); - } - } - - } - #endif - - del_timer_sync(&host->request_timer); - - - return SDM_SUCCESS; - -CMD_Errror: - del_timer_sync(&host->request_timer); - del_timer_sync(&host->DTO_timer); - - if((0==cmd->retries) && (host->error_times++%RK29_ERROR_PRINTK_INTERVAL == 0)) - { - printk(KERN_WARNING "%s..%d....command_complete(CMD=%d, arg=%x) error=%d. [%s]\n",\ - __FUNCTION__, __LINE__, host->cmd->opcode,host->cmd->arg, output, host->dma_name); - } - - return output; - -} - - -static void rk29_sdmmc_start_error(struct rk29_sdmmc *host) -{ - host->cmd->error = -EIO; - host->mrq->cmd->error = -EIO; - host->cmd_status |= SDMMC_INT_RTO; - - del_timer_sync(&host->request_timer); - - rk29_sdmmc_command_complete(host, host->mrq->cmd); - rk29_sdmmc_request_end(host, host->mrq->cmd); -} - -static void rk29_sdmmc_tasklet_func(unsigned long priv) -{ - struct rk29_sdmmc *host = (struct rk29_sdmmc *)priv; - struct mmc_data *data = host->cmd->data; - enum rk29_sdmmc_state state = host->state; - int pending_flag, stopflag; - - rk29_sdmmc_enable_irq(host, false); - spin_lock(&host->lock);//spin_lock_irqsave(&host->lock, iflags); - - state = host->state; - pending_flag = 0; - stopflag = 0; - - do - { - switch (state) - { - case STATE_IDLE: - { - xbwprintk(7, "%s..%d.. prev_state= STATE_IDLE [%s]\n", \ - __FUNCTION__, __LINE__, host->dma_name); - break; - } - - case STATE_SENDING_CMD: - { - xbwprintk(7, "%s..%d.. prev_state= STATE_SENDING_CMD, pendingEvernt=0x%lu [%s]\n",\ - __FUNCTION__, __LINE__,host->completed_events, host->dma_name); - if(host->cmd->error) - { - del_timer_sync(&host->request_timer); - } - - 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 - - rk29_sdmmc_set_completed(host, EVENT_CMD_COMPLETE); - rk29_sdmmc_command_complete(host, host->cmd); - - - if (!data) - { - rk29_sdmmc_request_end(host, host->cmd); - - xbwprintk(7, "%s..%d.. CMD%d call mmc_request_done() . [%s]\n", \ - __FUNCTION__, __LINE__,host->cmd->opcode,host->dma_name); - - host->complete_done = 1; - break; - } - host->errorstep = 0xfa; - if(host->cmd->error) - { - del_timer_sync(&host->DTO_timer); //delete the timer for INT_DTO - - if((data->stop) && (MMC_STOP_TRANSMISSION != host->cmd->opcode)) - { - xbwprintk(7, "%s..%d.. cmderr, so call send_stop_cmd() [%s]\n", \ - __FUNCTION__, __LINE__, host->dma_name); - - stopflag = 1; //Moidfyed by xbw at 2011-09-08 - - break; - } - - rk29_sdmmc_set_pending(host, EVENT_DATA_COMPLETE); - } - - host->errorstep = 0xf9; - state = STATE_DATA_BUSY; - /* fall through */ - } - - case STATE_DATA_BUSY: - { - xbwprintk(7, "%s..%d.. prev_state= STATE_DATA_BUSY, pendingEvernt=0x%lu [%s]\n", \ - __FUNCTION__, __LINE__,host->pending_events, host->dma_name); - - if (!rk29_sdmmc_test_and_clear_pending(host, EVENT_DATA_COMPLETE)) - break; - host->errorstep = 0xf8; - rk29_sdmmc_set_completed(host, EVENT_DATA_COMPLETE); - - #if SDMMC_USE_INT_UNBUSY - if((MMC_WRITE_BLOCK==host->cmd->opcode)||(MMC_WRITE_MULTIPLE_BLOCK==host->cmd->opcode)) - { - /* - ** use DTO_timer for waiting for INT_UNBUSY. - ** max 250ms in specification, but adapt 500 for the compatibility of all kinds of sick sdcard. - */ - mod_timer(&host->DTO_timer, jiffies + msecs_to_jiffies(5000)); - } - else - { - del_timer_sync(&host->DTO_timer); //delete the timer for INT_DTO - } - - state = STATE_DATA_UNBUSY; - - #else - del_timer_sync(&host->DTO_timer); //delete the timer for INT_DTO - #endif - } - - case STATE_DATA_UNBUSY: - { - #if SDMMC_USE_INT_UNBUSY - if((MMC_WRITE_BLOCK==host->cmd->opcode)||(MMC_WRITE_MULTIPLE_BLOCK==host->cmd->opcode)) - { - if (!rk29_sdmmc_test_and_clear_pending(host, EVENT_DATA_UNBUSY)) - break; - - del_timer_sync(&host->DTO_timer); - } - rk29_sdmmc_set_completed(host, EVENT_DATA_UNBUSY); - state = STATE_DATA_END; - #endif - rk29_sdmmc_request_end(host, host->cmd); - - if (data && !data->stop) - { - xbwprintk(7, "%s..%d.. CMD%d call mmc_request_done(). [%s]\n", \ - __FUNCTION__, __LINE__,host->cmd->opcode,host->dma_name); - - if(!( (MMC_READ_SINGLE_BLOCK == host->cmd->opcode)&&( -EIO == data->error))) //deal with START_BIT_ERROR - { - host->complete_done = 2; - break; - } - - } - host->errorstep = 0xf4; - xbwprintk(7, "%s..%d.. after DATA_COMPLETE, so call send_stop_cmd() [%s]\n", \ - __FUNCTION__, __LINE__, host->dma_name); - - stopflag = 2; //Moidfyed by xbw at 2011-09-08 - - break; - } - - case STATE_SENDING_STOP: - { - xbwprintk(7, "%s..%d.. prev_state= STATE_SENDING_STOP, pendingEvernt=0x%lu [%s]\n", \ - __FUNCTION__, __LINE__, host->pending_events, host->dma_name); - - if (!rk29_sdmmc_test_and_clear_pending(host, EVENT_CMD_COMPLETE)) - break; - - rk29_sdmmc_command_complete(host, host->cmd); - 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 = 3; - break; - } - - case STATE_DATA_END: - break; - default: - break; - } - - 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) ) \ - && test_bit(RK29_SDMMC_CARD_PRESENT, &host->flags); - - 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 [%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)); - - host->errorstep = 0xe0; - - if(test_bit(RK29_SDMMC_CARD_PRESENT, &host->flags)) - { - state = STATE_SENDING_CMD; - send_stop_cmd(host); //Moidfyed by xbw at 2011-09-08 - } - else - { - host->complete_done = 5; - } - } - - host->state = state; - - if((0==host->complete_done)&& host->mmc->doneflag && test_bit(RK29_SDMMC_CARD_PRESENT, &host->flags)) - { - host->errorstep = 0xf2; - - #if 0 - //debug - if(12==host->cmd->opcode) - { - printk(KERN_ERR "%d... cmd=%d(arg=0x%x),blksz=%d,blocks=%d,errorStep=0x%x,\n host->state=%x, statusReg=0x%x [%s]\n",\ - __LINE__,host->mrq->cmd->opcode, host->mrq->cmd->arg, host->mrq->cmd->data->blksz, host->mrq->cmd->data->blocks,\ - host->errorstep,host->state,rk29_sdmmc_read(host->regs, SDMMC_STATUS),host->dma_name); - } - #endif - - spin_unlock(&host->lock);//spin_unlock_irqrestore(&host->lock, iflags); - rk29_sdmmc_enable_irq(host, true); - return; - } - host->errorstep = 0xf3; - host->state = STATE_IDLE; - - if(host->mrq && host->mmc->doneflag && host->complete_done) - { - host->mmc->doneflag = 0; - host->complete_done = 0; - spin_unlock(&host->lock);//spin_unlock_irqrestore(&host->lock, iflags); - rk29_sdmmc_enable_irq(host, true); - mmc_request_done(host->mmc, host->mrq); - } - else - { - spin_unlock(&host->lock);//spin_unlock_irqrestore(&host->lock, iflags); - rk29_sdmmc_enable_irq(host, true); - } -} - - -static inline void rk29_sdmmc_cmd_interrupt(struct rk29_sdmmc *host, u32 status) -{ - u32 multi, unit; - - host->cmd_status |= status; - host->errorstep = 0xfc; - if((MMC_STOP_TRANSMISSION != host->cmd->opcode) && (host->cmdr & SDMMC_CMD_DAT_EXP)) - { - unit = 2*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; - 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(); - rk29_sdmmc_set_pending(host, EVENT_CMD_COMPLETE); - tasklet_schedule(&host->tasklet); -} - -static irqreturn_t rk29_sdmmc_interrupt(int irq, void *dev_id) -{ - struct rk29_sdmmc *host = dev_id; - u32 status, pending; - bool present; - bool present_old; - int sdio_irq=0; - - spin_lock(&host->lock); - - status = rk29_sdmmc_read(host->regs, SDMMC_RINTSTS); - pending = rk29_sdmmc_read(host->regs, SDMMC_MINTSTS);// read only mask reg - if (!pending) - { - goto Exit_INT; - } - - - if(pending & SDMMC_INT_CD) - { - //disable_irq_nosync(host->irq); - rk29_sdmmc_write(host->regs, SDMMC_RINTSTS, SDMMC_INT_CD); // clear sd detect int - present = rk29_sdmmc_get_cd(host->mmc); - present_old = test_bit(RK29_SDMMC_CARD_PRESENT, &host->flags); - - if(present != present_old) - { - printk(KERN_INFO "\n******************\n%s:INT_CD=0x%x,INT-En=%d,hostState=%d, present Old=%d ==> New=%d . [%s]\n",\ - __FUNCTION__, pending, host->mmc->re_initialized_flags, host->state, present_old, present, host->dma_name); - - rk28_send_wakeup_key(); //wake up backlight - host->error_times = 0; - - #if 1 - del_timer(&host->request_timer); - del_timer(&host->DTO_timer); - rk29_sdmmc_dealwith_timeout(host); - #endif - - if(present) - { - set_bit(RK29_SDMMC_CARD_PRESENT, &host->flags); - - if(host->mmc->re_initialized_flags) - { - mod_timer(&host->detect_timer, jiffies + msecs_to_jiffies(RK29_SDMMC_REMOVAL_DELAY)); - } - else - { - mod_timer(&host->detect_timer, jiffies + msecs_to_jiffies(RK29_SDMMC_REMOVAL_DELAY*2)); - } - } - else - { - clear_bit(RK29_SDMMC_CARD_PRESENT, &host->flags); - host->mmc->re_initialized_flags = 0; - - mmc_detect_change(host->mmc, 200); - } - - } - - goto Exit_INT; - - } - - if (pending & SDMMC_INT_CMD_DONE) { - - xbwprintk(6, "%s..%d.. CMD%d INT_CMD_DONE INT=0x%x [%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 !defined(CONFIG_RK29_SDIO_IRQ_FROM_GPIO) - if(pending & SDMMC_INT_SDIO) - { - xbwprintk(7, "%s..%d.. INT_SDIO INT=0x%x [%s]\n", \ - __FUNCTION__, __LINE__, pending, host->dma_name); - - rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_SDIO); - sdio_irq = 1; - - goto Exit_INT; - } -#endif - - if(pending & SDMMC_INT_RTO) - { - xbwprintk(7, "%s..%d.. CMD%d CMD_ERROR_FLAGS INT=0x%x [%s]\n", \ - __FUNCTION__, __LINE__, host->cmd->opcode,pending, host->dma_name); - - //rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_RTO); - rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,0xFFFFFFFF); //Modifyed by xbw at 2011-08-15 - host->cmd_status = status; - smp_wmb(); - rk29_sdmmc_set_pending(host, EVENT_CMD_COMPLETE); - - if(!(pending & SDMMC_INT_CMD_DONE)) - { - tasklet_schedule(&host->tasklet); - } - - goto Exit_INT; - } - - - if(pending & SDMMC_INT_HLE) - { - printk(KERN_WARNING "%s: Error due to hardware locked. Please check your hardware. INT=0x%x, CMD%d(arg=0x%x, retries=%d). [%s]\n",\ - __FUNCTION__, pending,host->cmd->opcode, host->cmd->arg, host->cmd->retries, host->dma_name); - - rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_HLE); - goto Exit_INT; - } - - - if(pending & SDMMC_INT_DTO) - { - xbwprintk(1,"%d..%s: INT=0x%x ,RINTSTS=0x%x, CMD%d(arg=0x%x, retries=%d),host->state=0x%x. [%s]\n", \ - __LINE__,__FUNCTION__, pending,status, host->cmd->opcode, host->cmd->arg, host->cmd->retries, host->state,host->dma_name); - - rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_DTO); - del_timer(&host->DTO_timer); //delete the timer for INT_DTO - - host->data_status |= status; - - smp_wmb(); - - rk29_sdmmc_set_pending(host, EVENT_DATA_COMPLETE); - tasklet_schedule(&host->tasklet); - goto Exit_INT; - } - - - if (pending & SDMMC_INT_FRUN) - { - printk(KERN_WARNING "%s: INT=0x%x Oh!My God,let me see!What happened?Why?Where? CMD%d(arg=0x%x, retries=%d). [%s]\n", \ - __FUNCTION__, pending, host->cmd->opcode, host->cmd->arg, host->cmd->retries,host->dma_name); - - //rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_FRUN); - rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,0xFFFFFFFE); - goto Exit_INT; - } - - if (pending & SDMMC_INT_RXDR) - { - xbwprintk(6, "%s..%d.. SDMMC_INT_RXDR INT=0x%x [%s]\n", \ - __FUNCTION__, __LINE__, pending, host->dma_name); - - rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_RXDR); // clear interrupt - rk29_sdmmc_read_data_pio(host); - } - - if (pending & SDMMC_INT_TXDR) - { - xbwprintk(6, "%s..%d.. SDMMC_INT_TXDR INT=0x%x [%s]\n", \ - __FUNCTION__, __LINE__, pending, host->dma_name); - - rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_TXDR); // clear interrupt - rk29_sdmmc_write_data_pio(host); - } - -#if SDMMC_USE_INT_UNBUSY - if(pending & SDMMC_INT_UNBUSY) - { - xbwprintk(1, "%d..%s: INT=0x%x ,RINTSTS=0x%x, CMD%d(arg=0x%x, retries=%d),host->state=0x%x. [%s]\n", \ - __LINE__,__FUNCTION__, pending,status, host->cmd->opcode, host->cmd->arg, host->cmd->retries, \ - host->state,host->dma_name); - - rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_UNBUSY); - - host->data_status = status; - smp_wmb(); - rk29_sdmmc_set_pending(host, EVENT_DATA_UNBUSY); - tasklet_schedule(&host->tasklet); - - goto Exit_INT; - } -#endif - -Exit_INT: - - spin_unlock(&host->lock); - - if(1 == sdio_irq) - { - mmc_signal_sdio_irq(host->mmc); - } - - return IRQ_HANDLED; -} - -/* - * - * MMC card detect thread, kicked off from detect interrupt, 1 timer - * - */ -static void rk29_sdmmc_detect_change(unsigned long data) -{ - struct rk29_sdmmc *host = (struct rk29_sdmmc *)data; - - if(!host->mmc) - return; - - smp_rmb(); - - if((RK29_CTRL_SDMMC_ID == host->pdev->id) && rk29_sdmmc_get_cd(host->mmc)) - { - host->mmc->re_initialized_flags =1; - } - - mmc_detect_change(host->mmc, 0); - -} - -static void rk29_sdmmc1_check_status(unsigned long data) -{ - struct rk29_sdmmc *host = (struct rk29_sdmmc *)data; - struct rk29_sdmmc_platform_data *pdata = host->pdev->dev.platform_data; - 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) - { - if (status) - { - #if RK_SDMMC_USE_SDIO_SUSPEND_RESUME - if(host->pdev->id == RK29_CTRL_SDIO1_ID) - host->mmc->pm_caps |= (MMC_PM_KEEP_POWER|MMC_PM_WAKE_SDIO_IRQ); - #endif - - rk29_sdmmc_hw_init(host); - set_bit(RK29_SDMMC_CARD_PRESENT, &host->flags); - mod_timer(&host->detect_timer, jiffies + msecs_to_jiffies(200)); - } - else - { - clear_bit(RK29_SDMMC_CARD_PRESENT, &host->flags); - rk29_sdmmc_detect_change((unsigned long)host); - } - } - - host->oldstatus = status; -} - -static void rk29_sdmmc1_status_notify_cb(int card_present, void *dev_id) -{ - struct rk29_sdmmc *host = dev_id; - - rk29_sdmmc1_check_status((unsigned long)host); -} - - -#if defined(CONFIG_SDMMC0_RK29_SDCARD_DET_FROM_GPIO) -static irqreturn_t det_keys_isr(int irq, void *dev_id); -static void rk29_sdmmc_detect_change_work(struct work_struct *work) -{ - int ret; - struct rk29_sdmmc *host = container_of(work, struct rk29_sdmmc, work.work); - - rk28_send_wakeup_key(); - rk29_sdmmc_detect_change(host); -} -#endif - -static irqreturn_t det_keys_isr(int irq, void *dev_id) -{ - struct rk29_sdmmc *host = dev_id; - -#if defined(CONFIG_SDMMC0_RK29_SDCARD_DET_FROM_GPIO) - bool present; - bool present_old; - int value; - - present = rk29_sdmmc_get_cd(host->mmc); - present_old = test_bit(RK29_SDMMC_CARD_PRESENT, &host->flags); - - if(present != present_old) - { - printk(KERN_INFO "\n******************\n%s: present Old=%d ==> New=%d . [%s]\n",\ - __FUNCTION__, present_old, present, host->dma_name); - - #if 1 - value = gpio_get_value(host->det_pin.io) ?IRQ_TYPE_EDGE_FALLING : IRQ_TYPE_EDGE_RISING; - - irq_set_irq_type(host->gpio_irq, value); - #endif - - #if 1 - del_timer(&host->request_timer); - del_timer(&host->DTO_timer); - rk29_sdmmc_dealwith_timeout(host); - #endif - enable_irq_wake(host->gpio_irq); - - if(present) - { - set_bit(RK29_SDMMC_CARD_PRESENT, &host->flags); - schedule_delayed_work(&host->work, msecs_to_jiffies(500)); - } - else - { - clear_bit(RK29_SDMMC_CARD_PRESENT, &host->flags); - host->mmc->re_initialized_flags = 0; - schedule_delayed_work(&host->work, 0); - } - } -#else - dev_info(&host->pdev->dev, "sd det_gpio changed(%s), send wakeup key!\n", - gpio_get_value(host->det_pin.io)?"removed":"insert"); - rk29_sdmmc_detect_change((unsigned long)dev_id); -#endif - return IRQ_HANDLED; -} - -static int rk29_sdmmc_probe(struct platform_device *pdev) -{ - struct mmc_host *mmc; - struct rk29_sdmmc *host; - struct resource *regs; - struct rk29_sdmmc_platform_data *pdata; - int level_value; - int ret = 0; - -#if defined(CONFIG_RK29_SDIO_IRQ_FROM_GPIO) - unsigned long trigger_flags; -#endif - - /* must have platform data */ - pdata = pdev->dev.platform_data; - if (!pdata) { - dev_err(&pdev->dev, "Platform data missing\n"); - ret = -ENODEV; - goto out; - } - - regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!regs) - { - return -ENXIO; - } - - mmc = mmc_alloc_host(sizeof(struct rk29_sdmmc), &pdev->dev); - if (!mmc) - { - ret = -ENOMEM; - goto rel_regions; - } - - host = mmc_priv(mmc); - host->mmc = mmc; - host->pdev = pdev; - - host->ctype = 0; // set default 1 bit mode - host->errorstep = 0; - host->bus_mode = 5; - host->old_cmd = 100; - host->clock =0; - host->old_div = 0xFF; - host->error_times = 0; - host->state = STATE_IDLE; - host->complete_done = 0; - host->retryfunc = 0; - host->mrq = NULL; - host->new_mrq = NULL; - host->irq_state = true; - host->timeout_times = 0; - - //detect pin info - host->det_pin.io = pdata->det_pin_info.io; - host->det_pin.enable = pdata->det_pin_info.enable; - host->det_pin.iomux.name = pdata->det_pin_info.iomux.name; - host->det_pin.iomux.fgpio = pdata->det_pin_info.iomux.fgpio; - host->det_pin.iomux.fmux = pdata->det_pin_info.iomux.fmux; - //power pin info - host->gpio_power_en = pdata->power_en; - host->gpio_power_en_level = pdata->power_en_level; - - host->set_iomux = pdata->set_iomux; - -#if defined(CONFIG_RK29_SDIO_IRQ_FROM_GPIO) - if(RK29_CTRL_SDIO1_ID == host->pdev->id) - { - host->sdio_INT_gpio = pdata->sdio_INT_gpio; - #ifdef USE_SDIO_INT_LEVEL - host->trigger_level = pdata->sdio_INT_level; - #endif - } -#endif - - if(pdata->io_init) - pdata->io_init(); - - spin_lock_init(&host->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 - if(RK29_CTRL_SDMMC_ID== host->pdev->id) - 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")); - - ret = -ENOMEM; - host->regs = ioremap(regs->start, regs->end - regs->start + 1); - if (!host->regs) - { - host->errorstep = 0x8A; - goto err_freemap; - } - - 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 - mmc->f_max = SDHC_FPP_FREQ; -#else - if(RK29_CTRL_SDMMC_ID== host->pdev->id) - { - mmc->f_max = SDHC_FPP_FREQ; - } - else - { - mmc->f_max = RK29_MAX_SDIO_FREQ; - } - -#endif - //mmc->ocr_avail = pdata->host_ocr_avail; - mmc->ocr_avail = MMC_VDD_27_28|MMC_VDD_28_29|MMC_VDD_29_30|MMC_VDD_30_31 - | 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 -#if 1 - - mmc->ocr_avail = mmc->ocr_avail |MMC_VDD_26_27 |MMC_VDD_25_26 |MMC_VDD_24_25 |MMC_VDD_23_24 - |MMC_VDD_22_23 |MMC_VDD_21_22 |MMC_VDD_20_21 |MMC_VDD_165_195; -#endif - mmc->caps = pdata->host_caps; -#if 1 - mmc->caps = mmc->caps | MMC_CAP_1_8V_DDR |MMC_CAP_1_2V_DDR /*|MMC_CAP_DRIVER_TYPE_A |MMC_CAP_DRIVER_TYPE_C |MMC_CAP_DRIVER_TYPE_D*/ - |MMC_CAP_UHS_SDR12 |MMC_CAP_UHS_SDR25 |MMC_CAP_UHS_SDR50 |MMC_CAP_UHS_SDR104 |MMC_CAP_UHS_DDR50 - /* |MMC_CAP_MAX_CURRENT_200 |MMC_CAP_MAX_CURRENT_400 |MMC_CAP_MAX_CURRENT_600 |MMC_CAP_MAX_CURRENT_800 - |MMC_CAP_SET_XPC_330*/; -#endif - 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. - */ - mmc->max_blk_size = 4095; - - /* - * No limit on the number of blocks transferred. - */ - mmc->max_blk_count = 4096; - - /* - * Since we only have a 16-bit data length register, we must - * ensure that we don't exceed 2^16-1 bytes in a single request. - */ - mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; //8M bytes(2K*4K) - - /* - * Set the maximum segment size. Since we aren't doing DMA - * (yet) we are only limited by the data length register. - */ - mmc->max_seg_size = mmc->max_req_size; - - 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); - - host->irq = platform_get_irq(pdev, 0); - if (host->irq < 0) - { - host->errorstep = 0x8B; - ret = -EINVAL; - goto err_freemap; - } - - memcpy(host->dma_name, pdata->dma_name, 8); - host->use_dma = pdata->use_dma; - - xbwprintk(7,"%s..%s..%d..*********** Bus clock= %d Khz **** [%s]\n",\ - __FILE__, __FUNCTION__,__LINE__,clk_get_rate(host->clk)/1000, host->dma_name); - - /*DMA init*/ - if(host->use_dma) - { - host->dma_info = rk29_sdmmc_dma_infos[host->pdev->id]; - ret = rk29_dma_request(host->dma_info.chn, &(host->dma_info.client), NULL); - if (ret < 0) - { - printk(KERN_WARNING "%s..%d...rk29_dma_request error=%d. [%s]\n", \ - __FUNCTION__, __LINE__,ret, host->dma_name); - host->errorstep = 0x97; - goto err_freemap; - } - -#if 0 //deal with the old API of DMA-module - ret = rk29_dma_config(host->dma_info.chn, 4); -#else //deal with the new API of DMA-module - if(RK29_CTRL_SDMMC_ID== host->pdev->id) - { - ret = rk29_dma_config(host->dma_info.chn, 4, 16); - } - else - { - #if defined(CONFIG_ARCH_RK29) - // to maintain set this value to 1 in RK29,noted at 2012-07-16 - ret = rk29_dma_config(host->dma_info.chn, 4, 1); - #else - // a unified set the burst value to 16 in RK30,noted at 2012-07-16 - ret = rk29_dma_config(host->dma_info.chn, 4, 16); - #endif - } -#endif - if(ret < 0) - { - printk(KERN_WARNING "%s..%d.. rk29_dma_config error=%d. [%s]\n", \ - __FUNCTION__, __LINE__, ret, host->dma_name); - host->errorstep = 0x98; - goto err_dmaunmap; - } - - ret = rk29_dma_set_buffdone_fn(host->dma_info.chn, rk29_sdmmc_dma_complete); - if(ret < 0) - { - printk(KERN_WARNING "%s..%d.. dma_set_buffdone_fn error=%d. [%s]\n", \ - __FUNCTION__, __LINE__, ret, host->dma_name); - host->errorstep = 0x99; - goto err_dmaunmap; - } - - 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; -#endif - -#if defined(CONFIG_ARCH_RK29) - if(RK29_CTRL_SDMMC_ID == host->pdev->id) - { - rk29_sdmmc_hw_init(host); - } -#endif - - ret = request_irq(host->irq, rk29_sdmmc_interrupt, 0, dev_name(&pdev->dev), host); - if (ret) - { - - printk(KERN_WARNING "%s..%d.. request_irq error=%d. [%s]\n", \ - __FUNCTION__, __LINE__, ret, host->dma_name); - host->errorstep = 0x8C; - goto err_dmaunmap; - } - - //gpio request for switch_voltage - if(RK29_CTRL_SDMMC_ID == host->pdev->id) - gpio_request(SWITCH_VOLTAGE_18_33, "sd_volt_switch"); - -#if defined(CONFIG_SDMMC0_RK29_SDCARD_DET_FROM_GPIO) - if((RK29_CTRL_SDMMC_ID == host->pdev->id) && (INVALID_GPIO != host->det_pin.io)) - { - INIT_DELAYED_WORK(&host->work, rk29_sdmmc_detect_change_work); - ret = gpio_request(host->det_pin.io, "sd_detect"); - if(ret < 0) { - dev_err(&pdev->dev, "gpio_request error\n"); - goto err_dmaunmap; - } - gpio_direction_input(host->det_pin.io); - - level_value = gpio_get_value(host->det_pin.io); - - host->gpio_irq = gpio_to_irq(host->det_pin.io); - ret = request_irq(host->gpio_irq, det_keys_isr, - level_value?IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING, - "sd_detect", - host); - if(ret < 0) { - dev_err(&pdev->dev, "gpio request_irq error\n"); - goto err_dmaunmap; - } - - enable_irq_wake(host->gpio_irq); - } -#elif DRIVER_SDMMC_USE_NEW_IOMUX_API - if(RK29_CTRL_SDMMC_ID == host->pdev->id) - { - iomux_set(MMC0_DETN); - } - -#endif - -#ifndef CONFIG_BCM_OOB_ENABLED -#if defined(CONFIG_RK29_SDIO_IRQ_FROM_GPIO) - if(RK29_CTRL_SDIO1_ID == host->pdev->id) - { - gpio_request(host->sdio_INT_gpio, "sdio_interrupt"); - - // intput + pull_Up, - gpio_direction_input(host->sdio_INT_gpio); - //gpio_direction_output(host->sdio_INT_gpio, GPIO_HIGH); - gpio_pull_updown(host->sdio_INT_gpio, 0); //disable default internal pull-down - - host->sdio_irq = gpio_to_irq(host->sdio_INT_gpio); - #ifdef USE_SDIO_INT_LEVEL - trigger_flags = (host->trigger_level==GPIO_HIGH)?IRQF_TRIGGER_HIGH:IRQF_TRIGGER_LOW; - #else - trigger_flags = IRQF_TRIGGER_LOW; - #endif - //printk("%d..%s sdio interrupt gpio level=%lu ====[%s]====\n", __LINE__, __FUNCTION__, trigger_flags, host->dma_name); - ret = request_irq(host->sdio_irq, rk29_sdmmc_sdio_irq_cb, - trigger_flags, - "sdio_interrupt", - host); - if (ret) - { - - printk("%s..%d.. sdio_request_INT_irq error=%d ====xbw[%s]====\n", \ - __FUNCTION__, __LINE__, ret, host->dma_name); - host->errorstep = 0x8D; - goto err_dmaunmap; - } - - disable_irq_nosync(host->sdio_irq); - enable_irq_wake(host->sdio_irq); - } - -#endif -#endif //#ifndef CONFIG_BCM_OOB_ENABLE - - /* setup sdmmc1 wifi card detect change */ - if (pdata->register_status_notify) { - pdata->register_status_notify(rk29_sdmmc1_status_notify_cb, host); - } - - if(RK29_CTRL_SDMMC_ID== host->pdev->id) - { - 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 - } - - - /* sdmmc1 wifi card slot status initially */ - if (pdata->status) { - host->oldstatus = pdata->status(mmc_dev(host->mmc)); - if (host->oldstatus) { - set_bit(RK29_SDMMC_CARD_PRESENT, &host->flags); - }else { - clear_bit(RK29_SDMMC_CARD_PRESENT, &host->flags); - } - } - - - platform_set_drvdata(pdev, mmc); - - mmc_add_host(mmc); - -#ifdef RK29_SDMMC_NOTIFY_REMOVE_INSERTION - - globalSDhost[pdev->id] = (struct rk29_sdmmc *)host; - if(0== host->pdev->id) - { - rk29_sdmmc_progress_add_attr(pdev); - } -#endif - - printk(KERN_INFO ".Line%d..The End of SDMMC-probe %s. [%s]\n", __LINE__, RK29_SDMMC_VERSION,host->dma_name); - return 0; - - -err_dmaunmap: - if(host->use_dma) - { - rk29_dma_free(host->dma_info.chn, &host->dma_info.client); - } - -err_freemap: - iounmap(host->regs); - -rel_regions: - mmc_free_host(mmc); - -out: - - return ret; -} - - - -static int __exit rk29_sdmmc_remove(struct platform_device *pdev) -{ - - struct mmc_host *mmc = platform_get_drvdata(pdev); - struct rk29_sdmmc *host; - struct resource *regs; - - if (!mmc) - return -1; - - host = mmc_priv(mmc); - - smp_wmb(); - rk29_sdmmc_control_clock(host, 0); - - /* Shutdown detect IRQ and kill detect thread */ - del_timer_sync(&host->detect_timer); - del_timer_sync(&host->request_timer); - del_timer_sync(&host->DTO_timer); - - tasklet_disable(&host->tasklet); - free_irq(platform_get_irq(pdev, 0), host); - if(host->use_dma) - { - rk29_dma_free(host->dma_info.chn, &host->dma_info.client); - } - - mmc_remove_host(mmc); - - iounmap(host->regs); - - regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(regs->start,resource_size(regs)); - - mmc_free_host(mmc); - platform_set_drvdata(pdev, NULL); - - return 0; -} - - -#ifdef CONFIG_PM - -static int rk29_sdmmc_sdcard_suspend(struct rk29_sdmmc *host) -{ - int ret = 0; -#if !defined(CONFIG_SDMMC0_RK29_SDCARD_DET_FROM_GPIO) - rk29_sdmmc_enable_irq(host,false); - #if DRIVER_SDMMC_USE_NEW_IOMUX_API - //need not to change mode to gpio. - #else - rk29_mux_api_set(host->det_pin.iomux.name, host->det_pin.iomux.fgpio); - #endif - gpio_request(host->det_pin.io, "sd_detect"); - gpio_direction_output(host->det_pin.io, GPIO_HIGH); - gpio_direction_input(host->det_pin.io); - - host->gpio_irq = gpio_to_irq(host->det_pin.io); - ret = request_irq(host->gpio_irq, det_keys_isr, - (gpio_get_value(host->det_pin.io))?IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING, - "sd_detect", - host); - - enable_irq_wake(host->gpio_irq); - -#endif - return ret; -} - -static void rk29_sdmmc_sdcard_resume(struct rk29_sdmmc *host) -{ -#if !defined(CONFIG_SDMMC0_RK29_SDCARD_DET_FROM_GPIO) - disable_irq_wake(host->gpio_irq); - free_irq(host->gpio_irq,host); - gpio_free(host->det_pin.io); - #if DRIVER_SDMMC_USE_NEW_IOMUX_API - iomux_set(MMC0_DETN); - #else - rk29_mux_api_set(host->det_pin.iomux.name, host->det_pin.iomux.fmux); - #endif - rk29_sdmmc_enable_irq(host, true); -#endif -} - -static int rk29_sdmmc_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct mmc_host *mmc = platform_get_drvdata(pdev); - struct rk29_sdmmc *host = mmc_priv(mmc); - int ret = 0; - - 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 !defined(CONFIG_SDMMC0_RK29_SDCARD_DET_FROM_GPIO) - if(rk29_sdmmc_sdcard_suspend(host) < 0) - dev_info(&host->pdev->dev, "rk29_sdmmc_sdcard_suspend error\n"); -#endif - } -#if RK_SDMMC_USE_SDIO_SUSPEND_RESUME - else if(host && host->pdev && (RK29_CTRL_SDIO1_ID == host->pdev->id)) - { - 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(!ret) - { - clk_disable(host->clk); - clk_disable(clk_get(&pdev->dev, "hclk_mmc")); - } - } -#endif // --#if RK_SDMMC_USE_SDIO_SUSPEND_RESUME - - return ret; -} - -static int rk29_sdmmc_resume(struct platform_device *pdev) -{ - struct mmc_host *mmc = platform_get_drvdata(pdev); - struct rk29_sdmmc *host = mmc_priv(mmc); - int ret = 0; - - if(host && host->pdev && (RK29_CTRL_SDMMC_ID == host->pdev->id)) //only the SDMMC0 have suspend-resume; noted by xbw - { - if (mmc) - { - - #if !defined(CONFIG_SDMMC0_RK29_SDCARD_DET_FROM_GPIO) - rk29_sdmmc_sdcard_resume(host); - #endif - - ret = mmc_resume_host(mmc); - } - } -#if RK_SDMMC_USE_SDIO_SUSPEND_RESUME - else if(host && host->pdev && (RK29_CTRL_SDIO1_ID == host->pdev->id)) - { - if (mmc) - { - clk_enable(host->clk); - clk_enable(clk_get(&pdev->dev, "hclk_mmc")); - mdelay(20); - ret = mmc_resume_host(mmc); - } - } -#endif // --#if RK_SDMMC_USE_SDIO_SUSPEND_RESUME - - return ret; -} -#else -#define rk29_sdmmc_suspend NULL -#define rk29_sdmmc_resume NULL -#endif - -static struct platform_driver rk29_sdmmc_driver = { - .suspend = rk29_sdmmc_suspend, - .resume = rk29_sdmmc_resume, - .remove = __exit_p(rk29_sdmmc_remove), - .driver = { - .name = "rk29_sdmmc", - }, -}; - -static int __init rk29_sdmmc_init(void) -{ - return platform_driver_probe(&rk29_sdmmc_driver, rk29_sdmmc_probe); -} - -static void __exit rk29_sdmmc_exit(void) -{ - platform_driver_unregister(&rk29_sdmmc_driver); -} - -module_init(rk29_sdmmc_init); -module_exit(rk29_sdmmc_exit); - -MODULE_DESCRIPTION("Rk29 Multimedia Card Interface driver"); -MODULE_AUTHOR("xbw@rock-chips.com"); -MODULE_LICENSE("GPL v2"); - diff --git a/drivers/mmc/host/rk29_sdmmc.h b/drivers/mmc/host/rk29_sdmmc.h deleted file mode 100755 index d7998672831d..000000000000 --- a/drivers/mmc/host/rk29_sdmmc.h +++ /dev/null @@ -1,600 +0,0 @@ -/* drivers/mmc/host/rk29_sdmmc.h - * - * Copyright (C) 2011 ROCKCHIP, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef __RK2918_SDMMC_H -#define __RK2918_SDMMC_H - -#include - -#define MAX_SG_CHN 2 - - -#define SDMMC_CTRL (0x000) //SDMMC Control register -#define SDMMC_PWREN (0x004) //Power enable register -#define SDMMC_CLKDIV (0x008) //Clock divider register -#define SDMMC_CLKSRC (0x00c) //Clock source register -#define SDMMC_CLKENA (0x010) //Clock enable register -#define SDMMC_TMOUT (0x014) //Time out register -#define SDMMC_CTYPE (0x018) //Card type register -#define SDMMC_BLKSIZ (0x01c) //Block size register -#define SDMMC_BYTCNT (0x020) //Byte count register -#define SDMMC_INTMASK (0x024) //Interrupt mask register -#define SDMMC_CMDARG (0x028) //Command argument register -#define SDMMC_CMD (0x02c) //Command register -#define SDMMC_RESP0 (0x030) //Response 0 register -#define SDMMC_RESP1 (0x034) //Response 1 register -#define SDMMC_RESP2 (0x038) //Response 2 register -#define SDMMC_RESP3 (0x03c) //Response 3 register -#define SDMMC_MINTSTS (0x040) //Masked interrupt status register -#define SDMMC_RINTSTS (0x044) //Raw interrupt status register -#define SDMMC_STATUS (0x048) //Status register -#define SDMMC_FIFOTH (0x04c) //FIFO threshold register -#define SDMMC_CDETECT (0x050) //Card detect register -#define SDMMC_WRTPRT (0x054) //Write protect register -#define SDMMC_TCBCNT (0x05c) //Transferred CIU card byte count -#define SDMMC_TBBCNT (0x060) //Transferred host/DMA to/from BIU_FIFO byte count -#define SDMMC_DEBNCE (0x064) //Card detect debounce register -#define SDMMC_USRID (0x068) //User ID register - -#if defined(CONFIG_ARCH_RK29) -#define SDMMC_DATA (0x100) //FIFO data read write -#else -#define SDMMC_VERID (0x06c) //Version ID register -#define SDMMC_UHS_REG (0x074) //UHS-I register -#define SDMMC_RST_n (0x078) //Hardware reset register -#define SDMMC_BMOD (0x080) //Bus mode register, control IMAC -#define SDMMC_PLDMND (0x084) //Poll Demand Register -#define SDMMC_DBADDR (0x088) //Descriptor List Base Address Register for 32-bit. -#define SDMMC_IDSTS (0x08c) //Internal DMAC Status register -#define SDMMC_IDINTEN (0x090) //Internal DMAC Interrupt Enable Register -#define SDMMC_DSCADDR (0x094) //Current Host Descriptor Address Register for 32-bit -#define SDMMC_BUFADDR (0x098) //Current Buffer Descriptor Address Register for 32-bit -#define SDMMC_CARDTHRCTL (0x100) //Card Read Threshold Enable -#define SDMMC_BACK_END_POWER (0x104) //Back-end Power -#define SDMMC_FIFO_BASE (0x200) //FIFO data read write - -#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)) - - -/* Control register defines (base+ 0x00)*/ -#define SDMMC_CTRL_USE_IDMAC BIT(25) -#define SDMMC_CTRL_OD_PULLUP BIT(24) -#define SDMMC_CTRL_CEATA_INT_EN BIT(11) -#define SDMMC_CTRL_SEND_AS_CCSD BIT(10) -#define SDMMC_CTRL_SEND_CCSD BIT(9) -#define SDMMC_CTRL_ABRT_READ_DATA BIT(8) -#define SDMMC_CTRL_SEND_IRQ_RESP BIT(7) -#define SDMMC_CTRL_READ_WAIT BIT(6) -#define SDMMC_CTRL_DMA_ENABLE BIT(5) -#define SDMMC_CTRL_INT_ENABLE BIT(4) -#define SDMMC_CTRL_DMA_RESET BIT(2) -#define SDMMC_CTRL_FIFO_RESET BIT(1) -#define SDMMC_CTRL_RESET BIT(0) - -/* Power Enable Register(base+ 0x04) */ -#define POWER_ENABLE BIT(0) //Power enable -#define POWER_DISABLE RK_CLEAR_BIT(0) //Power off - -/* SDMMC Clock source Register(base+ 0x0C) */ -#define CLK_DIV_SRC_0 (0x0) //clock divider 0 selected -#define CLK_DIV_SRC_1 (0x1) //clock divider 1 selected -#define CLK_DIV_SRC_2 (0x2) //clock divider 2 selected -#define CLK_DIV_SRC_3 (0x3) //clock divider 3 selected - - -/* Clock Enable register defines(base+0x10) */ -#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(0) //clock disabled - -/* time-out register defines(base+0x14) */ -#define SDMMC_TMOUT_DATA(n) _SBF(8, (n)) -#define SDMMC_TMOUT_DATA_MSK 0xFFFFFF00 -#define SDMMC_TMOUT_RESP(n) ((n) & 0xFF) -#define SDMMC_TMOUT_RESP_MSK 0xFF - -/* card-type register defines(base+0x18) */ -#define SDMMC_CTYPE_8BIT BIT(16) -#define SDMMC_CTYPE_4BIT BIT(0) -#define SDMMC_CTYPE_1BIT RK_CLEAR_BIT(0) - -/* Interrupt status & mask register defines(base+0x24) */ -#if defined(CONFIG_ARCH_RK29) -#define SDMMC_INT_SDIO BIT(16) //SDIO interrupt -#else -#define SDMMC_INT_SDIO BIT(24) //SDIO interrupt -#define SDMMC_INT_UNBUSY BIT(16) //data no busy interrupt -#endif - -#define SDMMC_INT_EBE BIT(15) //End Bit Error(read)/Write no CRC -#define SDMMC_INT_ACD BIT(14) //Auto Command Done -#define SDMMC_INT_SBE BIT(13) //Start Bit Error -#define SDMMC_INT_HLE BIT(12) //Hardware Locked Write Error -#define SDMMC_INT_FRUN BIT(11) //FIFO Underrun/Overrun Error -#define SDMMC_INT_HTO BIT(10) //Data Starvation by Host Timeout -#define SDMMC_INT_VSI SDMMC_INT_HTO // VSI => Voltage Switch Interrupt,Volt_Switch_int -#define SDMMC_INT_DRTO BIT(9) //Data Read TimeOut -#define SDMMC_INT_RTO BIT(8) //Response TimeOut -#define SDMMC_INT_DCRC BIT(7) //Data CRC Error -#define SDMMC_INT_RCRC BIT(6) //Response CRC Error -#define SDMMC_INT_RXDR BIT(5) //Receive FIFO Data Request -#define SDMMC_INT_TXDR BIT(4) //Transmit FIFO Data Request -#define SDMMC_INT_DTO BIT(3) //Data Transfer Over -#define SDMMC_INT_CMD_DONE BIT(2) //Command Done -#define SDMMC_INT_RE BIT(1) //Response Error -#define SDMMC_INT_CD BIT(0) //Card Detect - -/* Command register defines(base+0x2C) */ -#define SDMMC_CMD_START BIT(31) //start command -#if !defined(CONFIG_ARCH_RK29) -#define SDMMC_CMD_USE_HOLD_REG BIT(29) //Use hold register. -#define SDMMC_CMD_VOLT_SWITCH BIT(28) //Voltage switch bit -#define SDMMC_CMD_BOOT_MODE BIT(27) //set boot mode. -#define SDMMC_CMD_DISABLE_BOOT BIT(26) //disable boot. -#define SDMMC_CMD_EXPECT_BOOT_ACK BIT(25) //Expect Boot Acknowledge. -#define SDMMC_CMD_ENABLE_BOOT BIT(24) //be set only for mandatory boot mode. -#define SDMMC_CMD_CCS_EXP BIT(23) //expect Command Completion Signal(CCS) from the CE-ATA device. -#define SDMMC_CMD_CEATA_RD BIT(22) //software should set this bit to indicate that CE-ATA device -#endif -#define SDMMC_CMD_UPD_CLK BIT(21) //update clock register only -#define SDMMC_CMD_INIT BIT(15) //send initialization sequence -#define SDMMC_CMD_STOP BIT(14) //stop abort command -#define SDMMC_CMD_PRV_DAT_NO_WAIT RK_CLEAR_BIT(13) //not wait previous data transfer complete, send command at once -#define SDMMC_CMD_PRV_DAT_WAIT BIT(13) //wait previous data transfer complete -#define SDMMC_CMD_SEND_STOP BIT(12) //send auto stop command at end of data transfer -#define SDMMC_CMD_BLOCK_MODE RK_CLEAR_BIT(11) //block data transfer command -#define SDMMC_CMD_STRM_MODE BIT(11) //stream data transfer command -#define SDMMC_CMD_DAT_READ RK_CLEAR_BIT(10) //read from card -#define SDMMC_CMD_DAT_WRITE BIT(10) //write to card; -#define SDMMC_CMD_DAT_WR BIT(10) //write to card; -#define SDMMC_CMD_DAT_NO_EXP RK_CLEAR_BIT(9) //no data transfer expected -#define SDMMC_CMD_DAT_EXP BIT(9) //data transfer expected -#define SDMMC_CMD_RESP_NO_CRC RK_CLEAR_BIT(8) //do not check response crc -#define SDMMC_CMD_RESP_CRC BIT(8) //check response crc -#define SDMMC_CMD_RESP_CRC_NOCARE SDMMC_CMD_RESP_CRC //not care response crc -#define SDMMC_CMD_RESP_SHORT RK_CLEAR_BIT(7) //short response expected from card -#define SDMMC_CMD_RESP_LONG BIT(7) //long response expected from card; -#define SDMMC_CMD_RESP_NOCARE SDMMC_CMD_RESP_SHORT //not care response length -#define SDMMC_CMD_RESP_NO_EXP RK_CLEAR_BIT(6) //no response expected from card -#define SDMMC_CMD_RESP_EXP BIT(6) //response expected from card -#define SDMMC_CMD_INDX(n) ((n) & 0x1F) - - -/* Status register defines (base+0x48)*/ -#define SDMMC_STAUTS_MC_BUSY BIT(10) -#define SDMMC_STAUTS_DATA_BUSY BIT(9) //Card busy -#define SDMMC_CMD_FSM_MASK (0x0F << 4) //Command FSM status mask -#define SDMMC_CMD_FSM_IDLE (0x00) //CMD FSM is IDLE -#define SDMMC_STAUTS_FIFO_FULL BIT(3) //FIFO is full status -#define SDMMC_STAUTS_FIFO_EMPTY BIT(2) //FIFO is empty status - -/* Status register defines */ -#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)*/ -#define SD_MSIZE_1 (0x0 << 28) //DW_DMA_Multiple_Transaction_Size -#define SD_MSIZE_4 (0x1 << 28) -#define SD_MSIZE_8 (0x1 << 28) -#define SD_MSIZE_16 (0x3 << 28) -#define SD_MSIZE_32 (0x4 << 28) -#define SD_MSIZE_64 (0x5 << 28) -#define SD_MSIZE_128 (0x6 << 28) -#define SD_MSIZE_256 (0x7 << 28) - - -#if defined(CONFIG_ARCH_RK29) -#define FIFO_DEPTH (0x20) //FIFO depth = 32 word -#define RX_WMARK_SHIFT (16) -#define TX_WMARK_SHIFT (0) - -/* FIFO watermark */ -#define RX_WMARK (0xF) //RX watermark level set to 15 -#define TX_WMARK (0x10) //TX watermark level set to 16 - -#else -#define FIFO_DEPTH (0x100) //FIFO depth = 256 word -#define RX_WMARK_SHIFT (16) -#define TX_WMARK_SHIFT (0) - -/* FIFO watermark */ -#define RX_WMARK (FIFO_DEPTH/2-1) //RX watermark level set to 127 -#define TX_WMARK (FIFO_DEPTH/2) //TX watermark level set to 128 -#endif - -#define FIFO_THRESHOLD_WATERMASK (SD_MSIZE_16 |(RX_WMARK << RX_WMARK_SHIFT)|(TX_WMARK << TX_WMARK_SHIFT)) - -/* CDETECT register defines (base+0x50)*/ -#define SDMMC_CARD_DETECT_N BIT(0) //0--represents presence of card. - -/* WRIPRT register defines (base+0x54)*/ -#define SDMMC_WRITE_PROTECT BIT(0) // 1--represents write protect - -/* Control SDMMC_UHS_REG defines (base+ 0x74)*/ -#define SDMMC_UHS_DDR_MODE BIT(16) // 0--Non DDR Mode; 1--DDR mode -#define SDMMC_UHS_VOLT_REG_18 BIT(0) // 0--3.3v; 1--1.8V - - -// #ifdef IDMAC_SUPPORT - -/* Bus Mode Register (base + 0x80) */ -#define BMOD_SWR BIT(0) // Software Reset: Auto cleared after one clock cycle 0 -#define BMOD_FB BIT(1) // Fixed Burst Length: when set SINGLE/INCR/INCR4/INCR8/INCR16 used at the start 1 -#define BMOD_DE BIT(7) // Idmac Enable: When set IDMAC is enabled 7 -#define BMOD_DSL_MSK 0x0000007C // Descriptor Skip length: In Number of Words 6:2 -#define BMOD_DSL_Shift 2 // Descriptor Skip length Shift value -#define BMOD_DSL_ZERO 0x00000000 // No Gap between Descriptors -#define BMOD_DSL_TWO 0x00000008 // 2 Words Gap between Descriptors -#define BMOD_PBL 0x00000400 // MSIZE in FIFOTH Register - -/* Internal DMAC Status Register(base + 0x8c)*/ -/* Internal DMAC Interrupt Enable Register Bit Definitions */ -#define IDMAC_AI 0x00000200 // Abnormal Interrupt Summary Enable/ Status 9 -#define IDMAC_NI 0x00000100 // Normal Interrupt Summary Enable/ Status 8 -#define IDMAC_CES 0x00000020 // Card Error Summary Interrupt Enable/ status 5 -#define IDMAC_DU 0x00000010 // Descriptor Unavailabe Interrupt Enable /Status 4 -#define IDMAC_FBE 0x00000004 // Fata Bus Error Enable/ Status 2 -#define IDMAC_RI 0x00000002 // Rx Interrupt Enable/ Status 1 -#define IDMAC_TI 0x00000001 // Tx Interrupt Enable/ Status 0 - -#define IDMAC_EN_INT_ALL 0x00000337 // Enables all interrupts - -#define IDMAC_HOST_ABORT_TX 0x00000400 // Host Abort received during Transmission 12:10 -#define IDMAC_HOST_ABORT_RX 0x00000800 // Host Abort received during Reception 12:10 - -/* IDMAC FSM States */ -#define IDMAC_DMA_IDLE 0x00000000 // DMA is in IDLE state -#define IDMAC_DMA_SUSPEND 0x00002000 // DMA is in SUSPEND state -#define IDMAC_DESC_RD 0x00004000 // DMA is in DESC READ or FETCH State -#define IDMAC_DESC_CHK 0x00006000 // DMA is checking the Descriptor for Correctness -#define IDMAC_DMA_RD_REQ_WAIT 0x00008000 // DMA is in this state till dma_req is asserted (Read operation) -#define IDMAC_DMA_WR_REQ_WAIT 0x0000A000 // DMA is in this state till dma_req is asserted (Write operation) -#define IDMAC_DMA_RD 0x0000C000 // DMA is in Read mode -#define IDMAC_DMA_WR 0x0000E000 // DMA is in Write mode -#define IDMAC_DESC_CLOSE 0x00010000 // DMA is closing the Descriptor - -#define FIFOTH_MSIZE_1 0x00000000 // Multiple Trans. Size is 1 -#define FIFOTH_MSIZE_4 0x10000000 // Multiple Trans. Size is 4 -#define FIFOTH_MSIZE_8 0x20000000 // Multiple Trans. Size is 8 -#define FIFOTH_MSIZE_16 0x30000000 // Multiple Trans. Size is 16 -#define FIFOTH_MSIZE_32 0x40000000 // Multiple Trans. Size is 32 -#define FIFOTH_MSIZE_64 0x50000000 // Multiple Trans. Size is 64 -#define FIFOTH_MSIZE_128 0x60000000 // Multiple Trans. Size is 128 -#define FIFOTH_MSIZE_256 0x70000000 // Multiple Trans. Size is 256 -// #endif //#endif --#ifdef IDMAC_SUPPORT - - -/********************************************************************** -** Misc Defines -**********************************************************************/ -#define SDMMC_MAX_BUFF_SIZE_IDMAC 8192 -#define SDMMC_DEFAULT_DEBNCE_VAL 0x0FFFFFF - -/* Specifies how often in millisecs to poll for card removal-insertion changes - * when the timer switch is open */ -#define RK_SDMMC0_SWITCH_POLL_DELAY 35 - -/* SDMMC progress return value */ -#define SDM_SUCCESS (0) -#define SDM_FALSE (1) -#define SDM_PARAM_ERROR (2) -#define SDM_RESP_ERROR (3) -#define SDM_RESP_TIMEOUT (4) -#define SDM_DATA_CRC_ERROR (5) -#define SDM_DATA_READ_TIMEOUT (6) -#define SDM_END_BIT_ERROR (7) -#define SDM_START_BIT_ERROR (8) -#define SDM_BUSY_TIMEOUT (9) -#define SDM_ERROR (10) //SDMMC host controller error -#define SDM_START_CMD_FAIL (11) -#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) || defined(CONFIG_ESP8089) -#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 diff --git a/drivers/mmc/host/rk29_sdmmc_old.c b/drivers/mmc/host/rk29_sdmmc_old.c deleted file mode 100755 index 0685f70e701b..000000000000 --- a/drivers/mmc/host/rk29_sdmmc_old.c +++ /dev/null @@ -1,1584 +0,0 @@ -/* drivers/mmc/host/rk29_sdmmc.c - * - * Copyright (C) 2010 ROCKCHIP, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * mount -t debugfs debugfs /data/debugfs;cat /data/debugfs/mmc0/status - * echo 't' >/proc/sysrq-trigger - * echo 19 >/sys/module/wakelock/parameters/debug_mask - * vdc volume uevent on - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -#include "rk2818-sdmmc.h" - -#define RK29_SDMMC_DATA_ERROR_FLAGS (SDMMC_INT_DRTO | SDMMC_INT_DCRC | SDMMC_INT_HTO | SDMMC_INT_SBE | SDMMC_INT_EBE | SDMMC_INT_FRUN) -#define RK29_SDMMC_CMD_ERROR_FLAGS (SDMMC_INT_RTO | SDMMC_INT_RCRC | SDMMC_INT_RE | SDMMC_INT_HLE) -#define RK29_SDMMC_ERROR_FLAGS (RK29_SDMMC_DATA_ERROR_FLAGS | RK29_SDMMC_CMD_ERROR_FLAGS | SDMMC_INT_HLE) - -#define RK29_SDMMC_TMO_COUNT 10000 - -#define RK29_SDCARD_CLK 50 //48Mhz -#define RK29_SDIO_CLK 50 //36Mhz - -enum { - EVENT_CMD_COMPLETE = 0, - EVENT_XFER_COMPLETE, - EVENT_DATA_COMPLETE, - EVENT_DATA_ERROR, - EVENT_XFER_ERROR -}; -enum { - MRQ_REQUEST_START = 0, - MRQ_INT_CMD_DONE, //1 - MRQ_INT_CMD_ERR, //2 - MRQ_INT_DATA_DONE, //3 - MRQ_INT_DATA_ERR, //4 - MRQ_INT_CD, //5 - MRQ_INT_SDIO, //6 - MRQ_HAS_DATA, //7 - MRQ_HAS_STOP, //8 - MRQ_CMD_START_TMO, //9 - MRQ_CMD_START_DONE, //10 - MRQ_STOP_START_TMO, //11 - MRQ_STOP_START_DONE, //12 - MRQ_CLK_START_TMO, //13 - MRQ_CLK_START_DONE, //14 - MRQ_RESET_CTRL_ERR, //15 - MRQ_RESET_CTRL_DONE, //16 - MRQ_DMA_SET_ERR, //17 - MRQ_START_DMA, //18 - MRQ_STOP_DMA, //19 - MRQ_DMA_DONE, //20 - MRQ_REQUEST_DONE, //21 -}; -enum rk29_sdmmc_state { - STATE_IDLE = 0, - STATE_SENDING_CMD, - STATE_SENDING_DATA, - STATE_DATA_BUSY, - STATE_SENDING_STOP, - STATE_DATA_ERROR, -}; -#define rk29_sdmmc_test_and_clear_pending(host, event) \ - test_and_clear_bit(event, &host->pending_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) -#define rk29_sdmmc_set_mrq_status(host, status) \ - set_bit(status, &host->mrq_status) -#define rk29_sdmmc_test_mrq_status(host, status) \ - test_bit(status, &host->mrq_status) - -struct rk29_sdmmc_dma_info { - enum dma_ch chn; - char *name; - struct rk29_dma_client client; -}; -static struct rk29_sdmmc_dma_info dma_infos[] = { - { - .chn = DMACH_SDMMC, - .client = { - .name = "rk29-dma-sdmmc0", - } - }, - { - .chn = DMACH_SDIO, - .client = { - .name = "rk29-dma-sdio1", - } - }, -}; -static int rk29_sdmmc_is_sdio(struct rk29_sdmmc_platform_data *pdata) -{ - if(strncmp(pdata->dma_name, "sdio", strlen("sdio")) == 0) - return 1; - else - return 0; -} - -struct rk29_sdmmc { - struct device *dev; - - int is_sdio; - int is_init; - int gpio_det; - int gpio_irq; - int irq; - - int enable_sd_warkup; - - unsigned int clock; - unsigned int ios_clock; - unsigned int div; - spinlock_t lock; - unsigned int stop_cmdr; - unsigned int cmd_intsts; - unsigned int data_intsts; - unsigned long pending_events; - unsigned long completed_events; - unsigned long mrq_status; - unsigned long old_mrq_status; - - unsigned int bus_hz; - - - void __iomem *regs; - - struct mmc_host *mmc; - struct delayed_work work; - struct rk29_sdmmc_dma_info dma_info; - struct tasklet_struct tasklet; - struct mmc_request *mrq; - struct mmc_command *cmd; - struct clk *clk; - struct timer_list monitor_timer; - - enum rk29_sdmmc_state state; - dma_addr_t dma_addr; - - int (*get_wifi_cd)(struct device *); -#ifdef CONFIG_HAS_EARLYSUSPEND - struct early_suspend early_suspend; -#endif -}; -struct rk29_sdmmc *sdio_host = NULL; -static void rk29_sdmmc_write(unsigned char __iomem *regbase, unsigned int regOff,unsigned int val) -{ - __raw_writel(val,regbase + regOff); -} - -static unsigned int rk29_sdmmc_read(unsigned char __iomem *regbase, unsigned int regOff) -{ - return __raw_readl(regbase + regOff); -} - - -#if defined (CONFIG_DEBUG_FS) -/* - * 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_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; -} - -static int rk29_sdmmc_status_show(struct seq_file *s, void *v) -{ - struct rk29_sdmmc *host = s->private; - - seq_printf(s, "state: \t\t0x%08x\n", host->state); - seq_printf(s, "pending_events: \t0x%08lx\n", host->pending_events); - seq_printf(s, "completed_events: \t0x%08lx\n", host->completed_events); - seq_printf(s, "mrq_status: \t\t0x%08lx\n", host->mrq_status); - seq_printf(s, "old_mrq_status: \t0x%08lx\n", host->old_mrq_status); - - 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 int rk29_sdmmc_status_open(struct inode *inode, struct file *file) -{ - return single_open(file, rk29_sdmmc_status_show, inode->i_private); -} - -static const struct file_operations rk29_sdmmc_status_fops = { - .owner = THIS_MODULE, - .open = rk29_sdmmc_status_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 (!node) - goto err; - - node = debugfs_create_file("req", S_IRUSR, root, host, &rk29_sdmmc_req_fops); - if (!node) - goto err; - - node = debugfs_create_file("status", S_IRUSR, root, host, &rk29_sdmmc_status_fops); - if (!node) - goto err; - - return; - -err: - dev_err(&mmc->class_dev, "failed to initialize debugfs for host\n"); -} -#endif -static void rk29_sdmmc_show_info(struct rk29_sdmmc *host) -{ - dev_info(host->dev, "state: \t\t0x%08x\n", host->state); - dev_info(host->dev, "pending_events: \t0x%08lx\n", host->pending_events); - dev_info(host->dev, "completed_events: \t0x%08lx\n", host->completed_events); - dev_info(host->dev, "mrq_status: \t\t0x%08lx\n\n", host->mrq_status); - dev_info(host->dev, "old_mrq_status: \t0x%08lx\n\n", host->old_mrq_status); - dev_info(host->dev, "SDMMC_CTRL: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_CTRL)); - dev_info(host->dev, "SDMMC_PWREN: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_PWREN)); - dev_info(host->dev, "SDMMC_CLKDIV: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_CLKDIV)); - dev_info(host->dev, "SDMMC_CLKSRC: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_CLKSRC)); - dev_info(host->dev, "SDMMC_CLKENA: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_CLKENA)); - dev_info(host->dev, "SDMMC_TMOUT: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_TMOUT)); - dev_info(host->dev, "SDMMC_CTYPE: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_CTYPE)); - dev_info(host->dev, "SDMMC_BLKSIZ: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_BLKSIZ)); - dev_info(host->dev, "SDMMC_BYTCNT: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_BYTCNT)); - dev_info(host->dev, "SDMMC_INTMASK:\t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_INTMASK)); - dev_info(host->dev, "SDMMC_CMDARG: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_CMDARG)); - dev_info(host->dev, "SDMMC_CMD: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_CMD)); - dev_info(host->dev, "SDMMC_RESP0: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_RESP0)); - dev_info(host->dev, "SDMMC_RESP1: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_RESP1)); - dev_info(host->dev, "SDMMC_RESP2: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_RESP2)); - dev_info(host->dev, "SDMMC_RESP3: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_RESP3)); - dev_info(host->dev, "SDMMC_MINTSTS:\t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_MINTSTS)); - dev_info(host->dev, "SDMMC_RINTSTS:\t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_RINTSTS)); - dev_info(host->dev, "SDMMC_STATUS: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_STATUS)); - dev_info(host->dev, "SDMMC_FIFOTH: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_FIFOTH)); - dev_info(host->dev, "SDMMC_CDETECT:\t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_CDETECT)); - dev_info(host->dev, "SDMMC_WRTPRT: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_WRTPRT)); - dev_info(host->dev, "SDMMC_TCBCNT: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_TCBCNT)); - dev_info(host->dev, "SDMMC_TBBCNT: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_TBBCNT)); - dev_info(host->dev, "SDMMC_DEBNCE: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_DEBNCE)); -} -static int rk29_sdmmc_reset_fifo(struct rk29_sdmmc *host) -{ - int tmo; - int retry = RK29_SDMMC_TMO_COUNT; - if(!(rk29_sdmmc_read(host->regs, SDMMC_STATUS) & (SDMMC_STAUTS_MC_BUSY|SDMMC_STAUTS_DATA_BUSY)) && - (rk29_sdmmc_read(host->regs, SDMMC_STATUS) & SDMMC_STAUTS_FIFO_EMPTY)) - return 0; - - while(retry--) - { - tmo = RK29_SDMMC_TMO_COUNT; - rk29_sdmmc_write(host->regs, SDMMC_CTRL, rk29_sdmmc_read(host->regs, SDMMC_CTRL) | SDMMC_CTRL_FIFO_RESET); - while (--tmo && rk29_sdmmc_read(host->regs, SDMMC_CTRL) & SDMMC_CTRL_FIFO_RESET); - if(rk29_sdmmc_read(host->regs, SDMMC_STATUS) & (SDMMC_STAUTS_MC_BUSY|SDMMC_STAUTS_DATA_BUSY)) - udelay(5); - else - break; - } - if(retry <= 0){ - dev_dbg(host->dev, "%s error\n", __func__); - return -1; - } - else - return 0; -} -static int rk29_sdmmc_reset_ctrl(struct rk29_sdmmc *host) -{ - int tmo = RK29_SDMMC_TMO_COUNT; - /* - if(!(rk29_sdmmc_read(host->regs, SDMMC_STATUS) & (SDMMC_STAUTS_MC_BUSY|SDMMC_STAUTS_DATA_BUSY))) - return 0; - */ - rk29_sdmmc_write(host->regs, SDMMC_CTRL, (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET)); - while (--tmo && rk29_sdmmc_read(host->regs, SDMMC_CTRL) & (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET)); - rk29_sdmmc_write(host->regs, SDMMC_CTRL, rk29_sdmmc_read(host->regs, SDMMC_CTRL) | SDMMC_CTRL_INT_ENABLE); - - if(tmo > 0) { - rk29_sdmmc_set_mrq_status(host, MRQ_RESET_CTRL_DONE); - host->is_init = 1; - return 0; - } - else { - rk29_sdmmc_set_mrq_status(host, MRQ_RESET_CTRL_ERR); - dev_err(host->dev, "%s error\n", __func__); - return -1; - } -} - -static int rk29_sdmmc_start_command(struct rk29_sdmmc *host, - struct mmc_command *cmd, u32 cmd_flags) -{ - int tmo = RK29_SDMMC_TMO_COUNT; - unsigned long flags; - - local_irq_save(flags); - - rk29_sdmmc_write(host->regs, SDMMC_CMDARG, cmd->arg); - rk29_sdmmc_write(host->regs, SDMMC_CMD, cmd_flags | SDMMC_CMD_START); - local_irq_restore(flags); - - while (--tmo && rk29_sdmmc_read(host->regs, SDMMC_CMD) & SDMMC_CMD_START) - cpu_relax(); - if(tmo > 0) - return 0; - else - return -1; -} - -static int send_stop_cmd(struct rk29_sdmmc *host) -{ - dev_dbg(host->dev,"start cmd:%d ARGR=0x%08x CMDR=0x%08x\n", - host->mrq->data->stop->opcode, host->mrq->data->stop->arg, host->stop_cmdr); - if(rk29_sdmmc_start_command(host, host->mrq->data->stop, host->stop_cmdr)) { - rk29_sdmmc_set_mrq_status(host, MRQ_STOP_START_TMO); - return -1; - } - else { - rk29_sdmmc_set_mrq_status(host, MRQ_STOP_START_DONE); - return 0; - } -} -static void rk29_sdmmc_dma_cleanup(struct rk29_sdmmc *host) -{ - struct mmc_data *data = host->mrq->data; - if (data) - dma_unmap_sg(host->dev, data->sg, data->sg_len, - ((data->flags & MMC_DATA_WRITE) - ? DMA_TO_DEVICE : DMA_FROM_DEVICE)); -} - -static void rk29_sdmmc_stop_dma(struct rk29_sdmmc *host) -{ - int ret = 0; - rk29_sdmmc_set_mrq_status(host, MRQ_STOP_DMA); - rk29_sdmmc_dma_cleanup(host); - ret = rk29_dma_ctrl(host->dma_info.chn,RK29_DMAOP_STOP); - if(ret < 0) - dev_err(host->dev, "stop dma:rk29_dma_ctrl stop error\n"); - ret = rk29_dma_ctrl(host->dma_info.chn,RK29_DMAOP_FLUSH); - if(ret < 0) - dev_err(host->dev, "stop dma:rk29_dma_ctrl flush error\n"); - rk29_sdmmc_write(host->regs, SDMMC_CTRL, - (rk29_sdmmc_read(host->regs, SDMMC_CTRL))&(~SDMMC_CTRL_DMA_ENABLE)); -} - -static void rk29_sdmmc_request_done(struct rk29_sdmmc *host,struct mmc_request *mrq) -{ - int tmo = RK29_SDMMC_TMO_COUNT; - - spin_unlock(&host->lock); - rk29_sdmmc_write(host->regs, SDMMC_RINTSTS, ~SDMMC_INT_SDIO); - rk29_sdmmc_write(host->regs, SDMMC_INTMASK, - rk29_sdmmc_read(host->regs, SDMMC_INTMASK) & - ~(SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | RK29_SDMMC_ERROR_FLAGS)); - - if(!rk29_sdmmc_test_mrq_status(host, MRQ_STOP_DMA) && - rk29_sdmmc_test_mrq_status(host, MRQ_START_DMA)) - rk29_sdmmc_stop_dma(host); - if(mrq->stop && !rk29_sdmmc_test_mrq_status(host, MRQ_STOP_START_DONE)) - send_stop_cmd(host); - if(mrq->cmd->opcode == 17 && (host->data_intsts & SDMMC_INT_SBE)){ - rk29_sdmmc_write(host->regs, SDMMC_CMD, 12|SDMMC_CMD_STOP | SDMMC_CMD_START); - while (--tmo && rk29_sdmmc_read(host->regs, SDMMC_CMD) & SDMMC_CMD_START); - } - if(rk29_sdmmc_read(host->regs, SDMMC_STATUS) & SDMMC_STAUTS_FIFO_FULL ){ - rk29_sdmmc_read(host->regs, SDMMC_DATA); - rk29_sdmmc_read(host->regs, SDMMC_DATA); - } - //if(mrq->data && mrq->data->error) - rk29_sdmmc_reset_fifo(host); - - host->mrq = NULL; - host->state = STATE_IDLE; - rk29_sdmmc_set_mrq_status(host, MRQ_REQUEST_DONE); - mmc_request_done(host->mmc, mrq); - del_timer(&host->monitor_timer); - - spin_lock(&host->lock); -} - -static int sdmmc_send_cmd(struct rk29_sdmmc *host, unsigned int cmd, int arg) -{ - int tmo = RK29_SDMMC_TMO_COUNT; - rk29_sdmmc_write(host->regs, SDMMC_CMDARG, arg); - rk29_sdmmc_write(host->regs, SDMMC_CMD, SDMMC_CMD_START | cmd); - while (--tmo && readl(host->regs + SDMMC_CMD) & SDMMC_CMD_START); - if(tmo > 0) - return 0; - else - return -1; -} -static int rk29_sdmmc_get_div(unsigned int bus_hz, unsigned int ios_clock) -{ - unsigned int div, real_clock; - - if(ios_clock >= bus_hz) - return 0; - for(div = 1; div < 255; div++) - { - real_clock = bus_hz/(2*div); - if(real_clock <= ios_clock) - break; - } - if(div > 255) - div = 255; - return div; -} - -int rk29_sdmmc_set_clock(struct rk29_sdmmc *host) -{ - unsigned int div; - if(!host->ios_clock) - return 0; - //div = (((host->bus_hz + (host->bus_hz / 5)) / host->ios_clock)) >> 1; - //if(host->mrq && host->mrq->cmd->opcode == 25) - //host->ios_clock = 500000; - div = rk29_sdmmc_get_div(host->bus_hz, host->ios_clock); -/* - if(div == 0) - div = 1; -*/ - if(host->div == div) - return 0; - dev_info(host->dev, "div = %u, bus_hz = %u, ios_clock = %u\n", - div, host->bus_hz, host->ios_clock); - rk29_sdmmc_write(host->regs, SDMMC_CLKENA, 0); - rk29_sdmmc_write(host->regs, SDMMC_CLKSRC,0); - if(sdmmc_send_cmd(host, SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0)) - goto send_cmd_err; - rk29_sdmmc_write(host->regs, SDMMC_CLKDIV, div); - host->div = div; - host->clock = (div == 0)? host->bus_hz :(host->bus_hz / div) >> 1; - if(sdmmc_send_cmd(host, SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0)) - goto send_cmd_err; - rk29_sdmmc_write(host->regs, SDMMC_CLKENA, SDMMC_CLKEN_ENABLE); - if(sdmmc_send_cmd(host, SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0)) - goto send_cmd_err; - - rk29_sdmmc_set_mrq_status(host, MRQ_CLK_START_DONE); - return 0; -send_cmd_err: - rk29_sdmmc_set_mrq_status(host, MRQ_CLK_START_TMO); - return -1; -} - -static void rk29_sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - struct rk29_sdmmc *host = mmc_priv(mmc);; - - - switch (ios->bus_width) { - case MMC_BUS_WIDTH_1: - rk29_sdmmc_write(host->regs, SDMMC_CTYPE, 0); - break; - case MMC_BUS_WIDTH_4: - rk29_sdmmc_write(host->regs, SDMMC_CTYPE, SDMMC_CTYPE_4BIT); - break; - } - host->ios_clock = ios->clock; - - switch (ios->power_mode) { - case MMC_POWER_UP: - host->is_init = 1; - rk29_sdmmc_write(host->regs, SDMMC_PWREN, 1); - break; - default: - break; - } -} - -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); - - return (wrtprt & SDMMC_WRITE_PROTECT)?1:0; -} - - -static int rk29_sdmmc_get_cd(struct mmc_host *mmc) -{ - struct rk29_sdmmc *host = mmc_priv(mmc); - - if(host->is_sdio) - return host->get_wifi_cd(mmc_dev(host->mmc)); - else if(host->gpio_det == INVALID_GPIO) - return 1; - else - return gpio_get_value(host->gpio_det)?0:1; -} - -static inline unsigned ns_to_clocks(unsigned clkrate, unsigned ns) -{ - u32 clks; - if (clkrate > 1000000) - clks = (ns * (clkrate / 1000000) + 999) / 1000; - else - clks = ((ns/1000) * (clkrate / 1000) + 999) / 1000; - - return clks; -} - -static void rk29_sdmmc_set_timeout(struct rk29_sdmmc *host,struct mmc_data *data) -{ - unsigned timeout; - unsigned int clock; - - if(host->div == -1) - return; - else if(host->div == 0) - clock = host->bus_hz; - else - clock = (host->bus_hz / host->div) >> 1; - timeout = ns_to_clocks(clock, data->timeout_ns) + data->timeout_clks; - rk29_sdmmc_write(host->regs, SDMMC_TMOUT, 0xffffffff); - //rk29_sdmmc_write(host->regs, SDMMC_TMOUT, (timeout << 8) | (70)); -} -static u32 rk29_sdmmc_prepare_command(struct mmc_host *mmc, - struct mmc_command *cmd) -{ - struct mmc_data *data; - u32 cmdr; - - cmd->error = -EINPROGRESS; - cmdr = cmd->opcode; - - if(cmdr == 12) - cmdr |= SDMMC_CMD_STOP; - else if(cmdr == 13) - cmdr &= ~SDMMC_CMD_PRV_DAT_WAIT; - else - cmdr |= SDMMC_CMD_PRV_DAT_WAIT; - - if (cmd->flags & MMC_RSP_PRESENT) { - cmdr |= SDMMC_CMD_RESP_EXP; // expect the respond, need to set this bit - if (cmd->flags & MMC_RSP_136) - cmdr |= SDMMC_CMD_RESP_LONG; // expect long respond - - if(cmd->flags & MMC_RSP_CRC) - cmdr |= SDMMC_CMD_RESP_CRC; - } - - data = cmd->data; - if (data) { - cmdr |= SDMMC_CMD_DAT_EXP; - if (data->flags & MMC_DATA_STREAM) - cmdr |= SDMMC_CMD_STRM_MODE; // set stream mode - if (data->flags & MMC_DATA_WRITE) - cmdr |= SDMMC_CMD_DAT_WR; - } - return cmdr; -} -static int rk29_sdmmc_submit_data(struct rk29_sdmmc *host, struct mmc_data *data) -{ - struct scatterlist *sg; - unsigned int i,direction; - int dma_len=0, ret = 0; - - if (data->blksz & 3){ - dev_info(host->dev, "data->blksz = %d\n", data->blksz); - return -EINVAL; - } - for_each_sg(data->sg, sg, data->sg_len, i) { - if (sg->offset & 3 || sg->length & 3){ - dev_info(host->dev, "sg->offset = %d, sg->length = %d\n", - sg->offset, sg->length); - return -EINVAL; - } - } - if (data->flags & MMC_DATA_READ) - direction = RK29_DMASRC_HW; - else - direction = RK29_DMASRC_MEM; - - ret = rk29_dma_ctrl(host->dma_info.chn,RK29_DMAOP_STOP); - if(ret < 0) - dev_err(host->dev, "rk29_dma_ctrl stop error\n"); - ret = rk29_dma_ctrl(host->dma_info.chn,RK29_DMAOP_FLUSH); - if(ret < 0) - dev_err(host->dev, "rk29_dma_ctrl flush error\n"); - ret = rk29_dma_devconfig(host->dma_info.chn, direction, (unsigned long )(host->dma_addr)); - if(ret < 0) - dev_err(host->dev, "rk29_dma_devconfig error\n"); - dma_len = dma_map_sg(host->dev, data->sg, data->sg_len, - (data->flags & MMC_DATA_READ)? DMA_FROM_DEVICE : DMA_TO_DEVICE); - for (i = 0; i < dma_len; i++) { - ret = rk29_dma_enqueue(host->dma_info.chn, host, sg_dma_address(&data->sg[i]),sg_dma_len(&data->sg[i])); // data->sg->dma_address, data->sg->length); - if(ret < 0) - dev_err(host->dev, "rk29 dma enqueue error\n"); - } - rk29_sdmmc_write(host->regs, SDMMC_CTRL, (rk29_sdmmc_read(host->regs, SDMMC_CTRL))|SDMMC_CTRL_DMA_ENABLE);// enable dma - ret = rk29_dma_ctrl(host->dma_info.chn, RK29_DMAOP_START); - if(ret < 0) - dev_err(host->dev, "rk29_dma_ctrl start error\n"); - rk29_sdmmc_set_mrq_status(host, MRQ_START_DMA); - return 0; -} -static int rk29_sdmmc_test_cmd_start(struct rk29_sdmmc *host) -{ - return rk29_sdmmc_read(host->regs, SDMMC_CMD) & SDMMC_CMD_START; -} -static int rk29_sdmmc_start_request(struct rk29_sdmmc *host,struct mmc_request *mrq) -{ - int ret = 0; - struct mmc_command *cmd; - u32 cmdflags; - - BUG_ON(host->state != STATE_IDLE); - - spin_lock(&host->lock); - - if(rk29_sdmmc_test_cmd_start(host)){ - dev_info(host->dev, "cmd_start bit is set ,reset ctroller\n"); - ret = rk29_sdmmc_reset_ctrl(host); - } - if(ret < 0) - goto start_err; - - host->state = STATE_SENDING_CMD; - - if (mrq->data) { - rk29_sdmmc_set_timeout(host,mrq->data); - rk29_sdmmc_write(host->regs, SDMMC_BYTCNT,mrq->data->blksz*mrq->data->blocks); - rk29_sdmmc_write(host->regs, SDMMC_BLKSIZ,mrq->data->blksz); - } - cmd = mrq->cmd; - cmdflags = rk29_sdmmc_prepare_command(host->mmc, cmd); - if (host->is_init) { - host->is_init = 0; - cmdflags |= SDMMC_CMD_INIT; - } - - if (mrq->data) { - rk29_sdmmc_set_mrq_status(host, MRQ_HAS_DATA); - ret = rk29_sdmmc_submit_data(host, mrq->data); - } - if(ret < 0) { - rk29_sdmmc_set_mrq_status(host, MRQ_DMA_SET_ERR); - goto start_err; - } - dev_dbg(host->dev,"start cmd:%d ARGR=0x%08x CMDR=0x%08x\n", - cmd->opcode, cmd->arg, cmdflags); - - rk29_sdmmc_write(host->regs, SDMMC_RINTSTS, ~SDMMC_INT_SDIO); - rk29_sdmmc_write(host->regs, SDMMC_INTMASK, - rk29_sdmmc_read(host->regs, SDMMC_INTMASK) | - (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | RK29_SDMMC_ERROR_FLAGS)); - ret = rk29_sdmmc_start_command(host, cmd, cmdflags); - if(ret < 0) { - rk29_sdmmc_set_mrq_status(host, MRQ_CMD_START_TMO); - goto start_err; - } - rk29_sdmmc_set_mrq_status(host, MRQ_CMD_START_DONE); - if (mrq->stop) { - rk29_sdmmc_set_mrq_status(host, MRQ_HAS_STOP); - host->stop_cmdr = rk29_sdmmc_prepare_command(host->mmc, mrq->stop); - if(mrq->cmd->opcode == 25) - host->stop_cmdr |= SDMMC_CMD_DAT_WR; - } - spin_unlock(&host->lock); - return 0; -start_err: - spin_unlock(&host->lock); - return ret; -} - -static void rk29_sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq) -{ - int timeout; - struct rk29_sdmmc *host = mmc_priv(mmc); - - if(!mrq) - dev_info(host->dev, "mrq = NULL!!!!!\n"); - if(host->mrq){ - dev_info(host->dev, "%s-> host->mrq = NULL\n", __func__); - rk29_sdmmc_show_info(host); - } - if((!rk29_sdmmc_test_mrq_status(host, MRQ_STOP_DMA) && - rk29_sdmmc_test_mrq_status(host, MRQ_START_DMA)) || - (rk29_sdmmc_test_mrq_status(host, MRQ_STOP_DMA) && - !rk29_sdmmc_test_mrq_status(host, MRQ_START_DMA))) - dev_warn(host->dev, "start_dma but no stop_dma, or no start_dma but stop_dma\n"); - WARN_ON(host->mrq); - host->old_mrq_status = host->mrq_status; - host->mrq_status = 0; - host->pending_events = 0; - host->completed_events= 0; - host->cmd_intsts = 0; - host->data_intsts = 0; - host->mrq = mrq; - - if(!mrq->data) - timeout = 5000; - else - timeout = 5000 + mrq->data->timeout_ns/1000000; - mod_timer(&host->monitor_timer, jiffies + msecs_to_jiffies(timeout)); - - if (!rk29_sdmmc_get_cd(mmc)) { - mrq->cmd->error = -ENOMEDIUM; - rk29_sdmmc_request_done(host, mrq); - dev_dbg(host->dev, "mrq_status = 0x%08lx\n", host->mrq_status); - return; - } - - if(rk29_sdmmc_set_clock(host)) { - mrq->cmd->error = -EINPROGRESS; - dev_info(host->dev, "rk29_sdmmc_set_clock timeout, ios_clock = %d, clock = %d\n", host->ios_clock, host->clock); - rk29_sdmmc_request_done(host, mrq); - rk29_sdmmc_reset_ctrl(host); - rk29_sdmmc_show_info(host); - return; - } - if(rk29_sdmmc_start_request(host,mrq)) { - dev_info(host->dev, "rk29_sdmmc_start_request timeout\n"); - mrq->cmd->error = -EINPROGRESS; - rk29_sdmmc_request_done(host, mrq); - rk29_sdmmc_reset_ctrl(host); - rk29_sdmmc_show_info(host); - } - return; -} - -static void rk29_sdmmc_enable_sdio_irq(struct mmc_host *mmc, int enable) -{ - u32 intmask; - unsigned long flags; - struct rk29_sdmmc *host = mmc_priv(mmc); - - spin_lock_irqsave(&host->lock, flags); - intmask = rk29_sdmmc_read(host->regs, SDMMC_INTMASK); - if(enable) - rk29_sdmmc_write(host->regs, SDMMC_INTMASK, intmask | SDMMC_INT_SDIO); - else - rk29_sdmmc_write(host->regs, SDMMC_INTMASK, intmask & ~SDMMC_INT_SDIO); - spin_unlock_irqrestore(&host->lock, flags); -} - -static void rk29_sdmmc_init_card(struct mmc_host *mmc, struct mmc_card *card) -{ - card->quirks = MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; - -} -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, - }, - { - .request = rk29_sdmmc_request, - .set_ios = rk29_sdmmc_set_ios, - .enable_sdio_irq = rk29_sdmmc_enable_sdio_irq, - .init_card = rk29_sdmmc_init_card, - }, -}; - -static void rk29_sdmmc_request_end(struct rk29_sdmmc *host) - __releases(&host->lock) - __acquires(&host->lock) -{ - if(host->mrq) - rk29_sdmmc_request_done(host, host->mrq); -} - -static void rk29_sdmmc_command_complete(struct rk29_sdmmc *host, - struct mmc_command *cmd) -{ - unsigned int intsts = host->cmd_intsts; - - host->cmd_intsts = 0; - if(cmd->flags & MMC_RSP_PRESENT) { - - if(cmd->flags & MMC_RSP_136) { - cmd->resp[3] = rk29_sdmmc_read(host->regs, SDMMC_RESP0); - cmd->resp[2] = rk29_sdmmc_read(host->regs, SDMMC_RESP1); - cmd->resp[1] = rk29_sdmmc_read(host->regs, SDMMC_RESP2); - cmd->resp[0] = rk29_sdmmc_read(host->regs, SDMMC_RESP3); - } else { - cmd->resp[0] = rk29_sdmmc_read(host->regs, SDMMC_RESP0); - cmd->resp[1] = 0; - cmd->resp[2] = 0; - cmd->resp[3] = 0; - } - } - - if (intsts & SDMMC_INT_RTO) - cmd->error = -ETIMEDOUT; - else if ((cmd->flags & MMC_RSP_CRC) && (intsts & SDMMC_INT_RCRC)) - cmd->error = -EILSEQ; - else if (intsts & SDMMC_INT_RE) - cmd->error = -EIO; - else if(intsts & SDMMC_INT_HLE) - cmd->error = -EIO; - else - cmd->error = 0; - - if (cmd->error) { - dev_dbg(host->dev, - "command error: status=0x%08x resp=0x%08x\n" - "cmd=0x%08x arg=0x%08x flg=0x%08x err=%d\n", - intsts, cmd->resp[0], - cmd->opcode, cmd->arg, cmd->flags, cmd->error); - - if (cmd->data) { - rk29_sdmmc_stop_dma(host); - } - } -} - -static void rk29_sdmmc_tasklet_func(unsigned long priv) -{ - struct rk29_sdmmc *host = (struct rk29_sdmmc *)priv; - enum rk29_sdmmc_state state; - enum rk29_sdmmc_state prev_state; - unsigned int intsts; - - spin_lock(&host->lock); - state = host->state; - - do { - prev_state = state; - switch (state) { - case STATE_IDLE: - break; - - case STATE_SENDING_CMD: - if (!rk29_sdmmc_test_and_clear_pending(host, - EVENT_CMD_COMPLETE)) - break; - rk29_sdmmc_set_completed(host, EVENT_CMD_COMPLETE); - if(!host->mrq){ - dev_info(host->dev, "sending cmd, host->mrq = NULL\n"); - rk29_sdmmc_show_info(host); - }else{ - rk29_sdmmc_command_complete(host, host->mrq->cmd); - if (!host->mrq->data || (host->mrq->cmd->error)) { - rk29_sdmmc_request_end(host); - goto unlock; - } - prev_state = state = STATE_SENDING_DATA; - } - case STATE_SENDING_DATA: - if (rk29_sdmmc_test_and_clear_pending(host, - EVENT_DATA_ERROR)) { - if(!host->mrq){ - dev_info(host->dev, "sending data, host->mrq = NULL\n"); - rk29_sdmmc_show_info(host); - } - if(!rk29_sdmmc_test_mrq_status(host, MRQ_DMA_DONE) && - rk29_sdmmc_test_mrq_status(host, MRQ_START_DMA)) - dev_info(host->dev, "dma is running...\n"); - rk29_sdmmc_stop_dma(host); - if (host->mrq->data->stop) - send_stop_cmd(host); - state = STATE_DATA_ERROR; - break; - } - prev_state = state = STATE_DATA_BUSY; - - case STATE_DATA_BUSY: - if (!rk29_sdmmc_test_and_clear_pending(host,EVENT_DATA_COMPLETE) && - !(host->data_intsts & SDMMC_INT_SBE)) - break; - - rk29_sdmmc_set_completed(host, EVENT_DATA_COMPLETE); - intsts = host->data_intsts; - if(!host->mrq){ - dev_info(host->dev, "%s-> host->mrq = NULL\n", __func__); - rk29_sdmmc_show_info(host); - } - if(host->mrq->data) { - if (unlikely(intsts & RK29_SDMMC_DATA_ERROR_FLAGS)) { - if (intsts & SDMMC_INT_DRTO) { - dev_err(host->dev,"data timeout error\n"); - host->mrq->data->error = -ETIMEDOUT; - } else if (intsts & SDMMC_INT_DCRC) { - dev_err(host->dev,"data CRC error\n"); - host->mrq->data->error = -EILSEQ; - } else if (intsts & SDMMC_INT_SBE) { - dev_err(host->dev,"data start bit error\n"); - host->mrq->data->error = -EILSEQ; - }else { - dev_err(host->dev,"data FIFO error (status=%08x)\n",intsts); - host->mrq->data->error = -EIO; - } - rk29_sdmmc_show_info(host); - }else { - host->mrq->data->bytes_xfered = host->mrq->data->blocks * host->mrq->data->blksz; - host->mrq->data->error = 0; - } - } - if (!host->mrq->data->stop) { - rk29_sdmmc_request_end(host); - goto unlock; - } - - prev_state = state = STATE_SENDING_STOP; - if (host->mrq->data && !host->mrq->data->error) - send_stop_cmd(host); - /* fall through */ - - case STATE_SENDING_STOP: - if (!rk29_sdmmc_test_and_clear_pending(host, - EVENT_CMD_COMPLETE)) - break; - if(!host->mrq){ - dev_info(host->dev, "%s-> host->mrq = NULL\n", __func__); - rk29_sdmmc_show_info(host); - } - if(host->mrq->stop) - rk29_sdmmc_command_complete(host, host->mrq->stop); - rk29_sdmmc_request_end(host); - goto unlock; - case STATE_DATA_ERROR: - state = STATE_DATA_BUSY; - break; - } - } while (state != prev_state); - - host->state = state; - -unlock: - spin_unlock(&host->lock); - -} - - - -static irqreturn_t rk29_sdmmc_isr(int irq, void *dev_id) -{ - struct rk29_sdmmc *host = dev_id; - unsigned int intsts; - - intsts = rk29_sdmmc_read(host->regs, SDMMC_MINTSTS); - - spin_lock(&host->lock); - if(intsts & RK29_SDMMC_CMD_ERROR_FLAGS) { - rk29_sdmmc_set_mrq_status(host, MRQ_INT_CMD_ERR); - rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,RK29_SDMMC_CMD_ERROR_FLAGS); - host->cmd_intsts = intsts; - smp_wmb(); - rk29_sdmmc_set_pending(host, EVENT_CMD_COMPLETE); - if(!host->mrq){ - dev_info(host->dev, "%s-> host->mrq = NULL\n", __func__); - rk29_sdmmc_show_info(host); - } - else - dev_info(host->dev, "[cmd%d] cmd error(intsts 0x%x, host->state %d, pending_events %ld)\n", - host->mrq->cmd->opcode,intsts,host->state,host->pending_events); - tasklet_schedule(&host->tasklet); - } - - if (intsts & RK29_SDMMC_DATA_ERROR_FLAGS) { - rk29_sdmmc_set_mrq_status(host, MRQ_INT_DATA_ERR); - rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,RK29_SDMMC_DATA_ERROR_FLAGS); - host->data_intsts = intsts; - smp_wmb(); - rk29_sdmmc_set_pending(host, EVENT_DATA_ERROR); - if(!host->mrq){ - dev_info(host->dev, "%s-> host->mrq = NULL\n", __func__); - rk29_sdmmc_show_info(host); - } - else - dev_info(host->dev, "[cmd%d] data error(intsts 0x%x, host->state %d, pending_events %ld)\n", - host->mrq->cmd->opcode, intsts,host->state,host->pending_events); - tasklet_schedule(&host->tasklet); - } - - if(intsts & SDMMC_INT_DTO) { - rk29_sdmmc_set_mrq_status(host, MRQ_INT_DATA_DONE); - rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_DTO); - if (!host->data_intsts) - host->data_intsts = intsts; - smp_wmb(); - rk29_sdmmc_set_pending(host, EVENT_DATA_COMPLETE); - tasklet_schedule(&host->tasklet); - } - if (intsts & SDMMC_INT_CMD_DONE) { - rk29_sdmmc_set_mrq_status(host, MRQ_INT_CMD_DONE); - rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_CMD_DONE); - if(!host->cmd_intsts) - host->cmd_intsts = intsts; - - smp_wmb(); - rk29_sdmmc_set_pending(host, EVENT_CMD_COMPLETE); - tasklet_schedule(&host->tasklet); - } - if(host->is_sdio && (intsts & SDMMC_INT_SDIO)) { - rk29_sdmmc_set_mrq_status(host, MRQ_INT_SDIO); - rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_SDIO); - mmc_signal_sdio_irq(host->mmc); - } - spin_unlock(&host->lock); - return IRQ_HANDLED; -} - -static void rk29_sdmmc_dma_complete(void *arg, int size, enum rk29_dma_buffresult result) -{ - struct rk29_sdmmc *host = arg; - - dev_dbg(host->dev, "DMA complete\n"); - rk29_sdmmc_set_mrq_status(host, MRQ_DMA_DONE); -} - -static void rk29_sdmmc_detect_change(struct rk29_sdmmc *host) -{ - spin_lock(&host->lock); - - del_timer(&host->monitor_timer); - rk29_sdmmc_write(host->regs, SDMMC_RINTSTS, ~SDMMC_INT_SDIO); - rk29_sdmmc_write(host->regs, SDMMC_INTMASK, - rk29_sdmmc_read(host->regs, SDMMC_INTMASK) & - ~(SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | RK29_SDMMC_ERROR_FLAGS)); - if (host->mrq) { - switch (host->state) { - case STATE_IDLE: - break; - case STATE_SENDING_CMD: - if(host->mrq->cmd) - host->mrq->cmd->error = -ENOMEDIUM; - if (!host->mrq->data) - break; - /* fall through */ - case STATE_SENDING_DATA: - if(host->mrq->data) - host->mrq->data->error = -ENOMEDIUM; - rk29_sdmmc_stop_dma(host); - break; - case STATE_DATA_BUSY: - case STATE_DATA_ERROR: - if (host->mrq->data && host->mrq->data->error == -EINPROGRESS) - host->mrq->data->error = -ENOMEDIUM; - if (!host->mrq->stop) - break; - /* fall through */ - case STATE_SENDING_STOP: - if(host->mrq->stop) { - host->mrq->stop->error = -ENOMEDIUM; - } - break; - } - rk29_sdmmc_request_end(host); - } - rk29_sdmmc_reset_fifo(host); - spin_unlock(&host->lock); - mmc_detect_change(host->mmc, 0); -} - -static void rk29_sdmmc1_status_notify_cb(int card_present, void *dev_id) -{ - struct rk29_sdmmc *host = dev_id; - - card_present = rk29_sdmmc_get_cd(host->mmc); - dev_info(host->dev, "sdio change detected,status is %d\n",card_present); - - rk29_sdmmc_detect_change(host); -} - -static void rk29_sdmmc_get_dma_dma_info(struct rk29_sdmmc *host) -{ - if(host->is_sdio) - host->dma_info = dma_infos[1]; - else - host->dma_info = dma_infos[0]; -} - -static irqreturn_t rk29_sdmmc_detect_change_isr(int irq, void *dev_id); -static void rk29_sdmmc_detect_change_work(struct work_struct *work) -{ - int ret; - struct rk29_sdmmc *host = container_of(work, struct rk29_sdmmc, work.work); - - dev_info(host->dev, "sd detect change, card is %s\n", - rk29_sdmmc_get_cd(host->mmc)?"inserted":"removed"); - if(host->enable_sd_warkup && rk29_sdmmc_get_cd(host->mmc)) - rk28_send_wakeup_key(); - rk29_sdmmc_detect_change(host); - - free_irq(host->gpio_irq, host); - ret = request_irq(host->gpio_irq, - rk29_sdmmc_detect_change_isr, - rk29_sdmmc_get_cd(host->mmc)?IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING, - "sd_detect", - host); - if(ret < 0) - dev_err(host->dev, "gpio request_irq error\n"); -} -static irqreturn_t rk29_sdmmc_detect_change_isr(int irq, void *dev_id) -{ - struct rk29_sdmmc *host = dev_id; - - disable_irq_nosync(host->gpio_irq); - if(rk29_sdmmc_get_cd(host->mmc)) - schedule_delayed_work(&host->work, msecs_to_jiffies(500)); - else - schedule_delayed_work(&host->work, 0); - - return IRQ_HANDLED; -} -static void rk29_sdmmc_monitor_timer(unsigned long data) -{ - struct rk29_sdmmc *host = (struct rk29_sdmmc *)data; - - if(!rk29_sdmmc_test_mrq_status(host, MRQ_REQUEST_DONE)){ - dev_info(host->dev, "no dto interrupt\n"); - rk29_sdmmc_show_info(host); - host->mrq->cmd->error = -ETIMEDOUT; - if(host->mrq->data) - host->mrq->data->error = -ETIMEDOUT; - rk29_sdmmc_request_end(host); - //rk29_sdmmc_reset_ctrl(host); - } - -} - -#ifdef CONFIG_HAS_EARLYSUSPEND -static void rk29_sdmmc_early_suspend(struct early_suspend *h) -{ - struct rk29_sdmmc *host = container_of(h, - struct rk29_sdmmc, - early_suspend); - - dev_dbg(host->dev, "Enter rk29_sdmmc_early_suspend\n"); -} - -static void rk29_sdmmc_early_resume(struct early_suspend *h) -{ - struct rk29_sdmmc *host = container_of(h, - struct rk29_sdmmc, - early_suspend); - - dev_dbg(host->dev, "Exit rk29_sdmmc_early_resume\n"); -} -#endif - - -static int rk29_sdmmc_probe(struct platform_device *pdev) -{ - struct mmc_host *mmc; - struct rk29_sdmmc *host; - struct resource *regs; - struct rk29_sdmmc_platform_data *pdata; - int ret = 0; - - pdata = pdev->dev.platform_data; - if (!pdata) { - dev_err(&pdev->dev, "Platform data missing\n"); - return -ENODEV; - } - if(pdata->io_init) - pdata->io_init(); - - mmc = mmc_alloc_host(sizeof(struct rk29_sdmmc), &pdev->dev); - if (!mmc) - return -ENOMEM; - - host = mmc_priv(mmc); - host->mmc = mmc; - host->dev = &pdev->dev; - host->mrq = NULL; - host->state = STATE_IDLE; - host->div = -1; - host->is_init = 1; - host->is_sdio = rk29_sdmmc_is_sdio(pdata); - - if(host->is_sdio) - sdio_host = host; - host->get_wifi_cd = pdata->status; - - host->irq = platform_get_irq(pdev, 0); - if (host->irq < 0) { - dev_err(&pdev->dev, "platform_get_irq error\n"); - ret = host->irq; - goto err_mmc_free_host; - } - - regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!regs) { - dev_err(&pdev->dev, "platform_get_resource error\n"); - ret = -ENXIO; - goto err_mmc_free_host; - } - - host->regs = ioremap(regs->start, regs->end - regs->start); - if (!host->regs){ - dev_err(&pdev->dev, "ioremap error\n"); - ret = ENXIO; - goto err_mmc_free_host; - } - spin_lock_init(&host->lock); - - /* dma init */ - rk29_sdmmc_get_dma_dma_info(host); - ret = rk29_dma_request(host->dma_info.chn, &(host->dma_info.client), NULL); - if (ret < 0){ - dev_err(&pdev->dev, "rk29_dma_request error\n"); - goto err_iounmap; - } - ret = rk29_dma_config(host->dma_info.chn, 4, 1); - - if (ret < 0){ - dev_err(&pdev->dev, "rk29_dma_config error\n"); - //goto err_rk29_dma_free; - } - ret = rk29_dma_set_buffdone_fn(host->dma_info.chn, rk29_sdmmc_dma_complete); - if (ret < 0){ - dev_err(&pdev->dev, "rk29_dma_set_buffdone_fn error\n"); - goto err_rk29_dma_free; - } - host->dma_addr = regs->start + SDMMC_DATA; - - /* clk init */ - host->clk = clk_get(&pdev->dev, "mmc"); - if(host->is_sdio) - clk_set_rate(host->clk,RK29_SDIO_CLK * 1000000); - else - clk_set_rate(host->clk,RK29_SDCARD_CLK * 1000000); - clk_enable(host->clk); - clk_enable(clk_get(&pdev->dev, "hclk_mmc")); - host->bus_hz = clk_get_rate(host->clk); - - /* reset all blocks */ - rk29_sdmmc_write(host->regs, SDMMC_CTRL,(SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET)); - /* wait till resets clear */ - while (rk29_sdmmc_read(host->regs, SDMMC_CTRL) & (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET)); - /* Clear the interrupts for the host controller */ - rk29_sdmmc_write(host->regs, SDMMC_RINTSTS, 0xFFFFFFFF); - rk29_sdmmc_write(host->regs, SDMMC_INTMASK, 0); // disable all mmc interrupt first - /* Put in max timeout */ - rk29_sdmmc_write(host->regs, SDMMC_TMOUT, 0xFFFFFFFF); - - /* FIFO threshold settings */ - rk29_sdmmc_write(host->regs, SDMMC_FIFOTH, ((0x3 << 28) | (0x0f << 16) | (0x10 << 0))); // RXMark = 15, TXMark = 16, DMA Size = 16 - /* disable clock to CIU */ - rk29_sdmmc_write(host->regs, SDMMC_CLKENA,0); - rk29_sdmmc_write(host->regs, SDMMC_CLKSRC,0); - rk29_sdmmc_write(host->regs, SDMMC_PWREN, 1); - - ret = request_irq(host->irq, rk29_sdmmc_isr, 0, dev_name(&pdev->dev), host); - if (ret < 0){ - dev_err(&pdev->dev, "request_irq error\n"); - goto err_rk29_dma_free; - } - - /* card insert flags init*/ - if (pdata->register_status_notify) { - pdata->register_status_notify(rk29_sdmmc1_status_notify_cb, host); - } - - /* add host */ - if(host->is_sdio) - mmc->ops = &rk29_sdmmc_ops[1]; - else - mmc->ops = &rk29_sdmmc_ops[0]; - if (host->is_sdio) - mmc->pm_flags = MMC_PM_IGNORE_PM_NOTIFY; //ignore pm notify - - mmc->f_min = DIV_ROUND_UP(host->bus_hz, 510); - mmc->f_max = host->bus_hz; - mmc->ocr_avail = pdata->host_ocr_avail; - mmc->caps = pdata->host_caps; -#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 - mmc->max_blk_size = 4096; - mmc->max_blk_count = 65535; - mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; - mmc->max_seg_size = mmc->max_req_size; - - ret = mmc_add_host(mmc); - if (ret < 0){ - dev_err(&pdev->dev, "mmc_add_host error\n"); - goto err_free_irq; - } - -#if defined (CONFIG_DEBUG_FS) - rk29_sdmmc_init_debugfs(host); -#endif - tasklet_init(&host->tasklet, rk29_sdmmc_tasklet_func, (unsigned long)host); - setup_timer(&host->monitor_timer, rk29_sdmmc_monitor_timer,(unsigned long)host); - - host->gpio_det = pdata->detect_irq; - if(!host->is_sdio && host->gpio_det != INVALID_GPIO) { - INIT_DELAYED_WORK(&host->work, rk29_sdmmc_detect_change_work); - ret = gpio_request(host->gpio_det, "sd_detect"); - if(ret < 0) { - dev_err(&pdev->dev, "gpio_request error\n"); - goto err_mmc_remove_host; - } - gpio_direction_input(host->gpio_det); - host->gpio_irq = gpio_to_irq(host->gpio_det); - - ret = request_irq(host->gpio_irq, - rk29_sdmmc_detect_change_isr, - rk29_sdmmc_get_cd(host->mmc)?IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING, - "sd_detect", - host); - if(ret < 0) { - dev_err(&pdev->dev, "gpio request_irq error\n"); - goto err_gpio_free; - } - host->enable_sd_warkup = pdata->enable_sd_wakeup; - if(host->enable_sd_warkup) - enable_irq_wake(host->gpio_irq); - } - platform_set_drvdata(pdev, host); - rk29_sdmmc_write(host->regs, SDMMC_CTYPE, 0); - rk29_sdmmc_write(host->regs, SDMMC_RINTSTS, 0xFFFFFFFF); - rk29_sdmmc_write(host->regs, SDMMC_INTMASK,SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | RK29_SDMMC_ERROR_FLAGS); - rk29_sdmmc_write(host->regs, SDMMC_CTRL,SDMMC_CTRL_INT_ENABLE); - rk29_sdmmc_write(host->regs, SDMMC_CLKENA,1); -#ifdef CONFIG_HAS_EARLYSUSPEND - host->early_suspend.suspend = rk29_sdmmc_early_suspend; - host->early_suspend.resume = rk29_sdmmc_early_resume; - host->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; - register_early_suspend(&host->early_suspend); -#endif - dev_info(host->dev, "RK29 SDMMC controller at irq %d\n", host->irq); - return 0; - free_irq(host->gpio_irq, host); -err_gpio_free: - gpio_free(host->gpio_det); -err_mmc_remove_host: - mmc_remove_host(host->mmc); -err_free_irq: - free_irq(host->irq, host); -err_rk29_dma_free: - rk29_dma_free(host->dma_info.chn, &host->dma_info.client); -err_iounmap: - iounmap(host->regs); -err_mmc_free_host: - mmc_free_host(host->mmc); - - while(1); - return ret; - -} - - - -static int __exit rk29_sdmmc_remove(struct platform_device *pdev) -{ - struct rk29_sdmmc *host = platform_get_drvdata(pdev); - - rk29_sdmmc_write(host->regs, SDMMC_RINTSTS, 0xFFFFFFFF); - rk29_sdmmc_write(host->regs, SDMMC_INTMASK, 0); // disable all mmc interrupt first - - smp_wmb(); - free_irq(host->gpio_irq, host); - gpio_free(host->gpio_det); - mmc_remove_host(host->mmc); - free_irq(host->irq, host); - rk29_dma_free(host->dma_info.chn, &host->dma_info.client); - - /* disable clock to CIU */ - rk29_sdmmc_write(host->regs, SDMMC_CLKENA,0); - rk29_sdmmc_write(host->regs, SDMMC_CLKSRC,0); - - iounmap(host->regs); - mmc_free_host(host->mmc); - return 0; -} -static int rk29_sdmmc_suspend(struct platform_device *pdev, pm_message_t state) -{ - int ret = 0; -#ifdef CONFIG_PM - struct rk29_sdmmc *host = platform_get_drvdata(pdev); - - dev_info(host->dev, "Enter rk29_sdmmc_suspend\n"); - if(host->mmc && !host->is_sdio && host->gpio_det != INVALID_GPIO){ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) - ret = mmc_suspend_host(host->mmc); -#else - ret = mmc_suspend_host(host->mmc,state); -#endif - if(!host->enable_sd_warkup) - free_irq(host->gpio_irq, host); - } - rk29_sdmmc_write(host->regs, SDMMC_CLKENA, 0); - clk_disable(host->clk); -#endif - return ret; -} - -static int rk29_sdmmc_resume(struct platform_device *pdev) -{ - int ret = 0; -#ifdef CONFIG_PM - struct rk29_sdmmc *host = platform_get_drvdata(pdev); - - dev_info(host->dev, "Exit rk29_sdmmc_suspend\n"); - clk_enable(host->clk); - rk29_sdmmc_write(host->regs, SDMMC_CLKENA, 1); - if(host->mmc && !host->is_sdio && host->gpio_det != INVALID_GPIO){ - if(!host->enable_sd_warkup){ - ret = request_irq(host->gpio_irq, - rk29_sdmmc_detect_change_isr, - rk29_sdmmc_get_cd(host->mmc)?IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING, - "sd_detect", - host); - if(ret < 0) - dev_err(host->dev, "gpio request_irq error\n"); - } - host->is_init = 1; - ret = mmc_resume_host(host->mmc); - mmc_detect_change(host->mmc, 0); - } -#endif - return ret; -} -static struct platform_driver rk29_sdmmc_driver = { - .suspend = rk29_sdmmc_suspend, - .resume = rk29_sdmmc_resume, - .remove = __exit_p(rk29_sdmmc_remove), - .driver = { - .name = "rk29_sdmmc", - }, -}; - -static int __init rk29_sdmmc_init(void) -{ - return platform_driver_probe(&rk29_sdmmc_driver, rk29_sdmmc_probe); -} - -static void __exit rk29_sdmmc_exit(void) -{ - platform_driver_unregister(&rk29_sdmmc_driver); -} - -module_init(rk29_sdmmc_init); -module_exit(rk29_sdmmc_exit); - -MODULE_DESCRIPTION("Rk29 Multimedia Card Interface driver"); -MODULE_AUTHOR("Rockchips"); -MODULE_LICENSE("GPL v2"); - diff --git a/drivers/mmc/host/rkemmc.c b/drivers/mmc/host/rkemmc.c deleted file mode 100644 index 92eef2ada133..000000000000 --- a/drivers/mmc/host/rkemmc.c +++ /dev/null @@ -1,1519 +0,0 @@ -/* - * Rockchip eMMC Interface driver - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "rkemmc.h" -struct rk29_dma_client mmc_client; - -static int rk_mmc_pre_dma_transfer(struct rk_mmc *host, - struct mmc_data *data, - bool next); -#if 0 -static int rk_mmc_show_regs(struct rk_mmc *host) -{ - mmc_info(host, "CTRL: 0x%08x\n", mmc_readl(host, CTRL)); - mmc_info(host, "PWREN: 0x%08x\n", mmc_readl(host, PWREN)); - mmc_info(host, "CLKDIV: 0x%08x\n", mmc_readl(host, CLKDIV)); - mmc_info(host, "CLKENA: 0x%08x\n", mmc_readl(host, CLKENA)); - mmc_info(host, "CLKSRC: 0x%08x\n", mmc_readl(host, CLKSRC)); - mmc_info(host, "TMOUT: 0x%08x\n", mmc_readl(host, TMOUT)); - mmc_info(host, "CTYPE: 0x%08x\n", mmc_readl(host, CTYPE)); - mmc_info(host, "BLKSIZ: 0x%08x\n", mmc_readl(host, BLKSIZ)); - mmc_info(host, "BYTCNT: 0x%08x\n", mmc_readl(host, BYTCNT)); - mmc_info(host, "INTMASK: 0x%08x\n", mmc_readl(host, INTMASK)); - mmc_info(host, "CMDARG: 0x%08x\n", mmc_readl(host, CMDARG)); - mmc_info(host, "CMD: 0x%08x\n", mmc_readl(host, CMD)); - mmc_info(host, "RESP0: 0x%08x\n", mmc_readl(host, RESP0)); - mmc_info(host, "RESP1: 0x%08x\n", mmc_readl(host, RESP1)); - mmc_info(host, "RESP2: 0x%08x\n", mmc_readl(host, RESP2)); - mmc_info(host, "RESP3: 0x%08x\n", mmc_readl(host, RESP3)); - mmc_info(host, "MINTSTS: 0x%08x\n", mmc_readl(host, MINTSTS)); - mmc_info(host, "STATUS: 0x%08x\n", mmc_readl(host, STATUS)); - mmc_info(host, "FIFOTH: 0x%08x\n", mmc_readl(host, FIFOTH)); - mmc_info(host, "CDETECT: 0x%08x\n", mmc_readl(host, CDETECT)); - mmc_info(host, "WRTPRT: 0x%08x\n", mmc_readl(host, WRTPRT)); - mmc_info(host, "TCBCNT: 0x%08x\n", mmc_readl(host, TCBCNT)); - mmc_info(host, "TBBCNT: 0x%08x\n", mmc_readl(host, TBBCNT)); - mmc_info(host, "DEBNCE: 0x%08x\n", mmc_readl(host, DEBNCE)); - mmc_info(host, "USRID: 0x%08x\n", mmc_readl(host, USRID)); - mmc_info(host, "VERID: 0x%08x\n", mmc_readl(host, VERID)); - mmc_info(host, "UHS_REG: 0x%08x\n", mmc_readl(host, UHS_REG)); - mmc_info(host, "RST_N: 0x%08x\n", mmc_readl(host, RST_N)); - - return 0; -} -#endif -/* Dma operation */ -#define MMC_DMA_CHN DMACH_EMMC -static void dma_callback_func(void *arg, int size, enum rk29_dma_buffresult result) -{ - struct rk_mmc *host = (struct rk_mmc *)arg; - - host->dma_xfer_size += size; - if (host->data) { - mmc_dbg(host, "total: %u, xfer: %u\n", host->data->blocks * host->data->blksz, host->dma_xfer_size); - if(host->dma_xfer_size == host->data->blocks * host->data->blksz){ - set_bit(EVENT_XFER_COMPLETE, &host->pending_events); - tasklet_schedule(&host->tasklet); - } - } - - return; -} -static int dma_init(struct rk_mmc *host) -{ - int res; - - res = rk29_dma_request(MMC_DMA_CHN, &mmc_client, NULL); - if(res < 0) - return res; - - res = rk29_dma_config(MMC_DMA_CHN, 4, 16); - if(res < 0) - return res; - - res = rk29_dma_set_buffdone_fn(MMC_DMA_CHN, dma_callback_func); - - return res; -} -static void dma_exit(struct rk_mmc *host) -{ - rk29_dma_free(MMC_DMA_CHN, NULL); -} -static int dma_start(struct rk_mmc *host) -{ - int i, res, direction, sg_len; - enum rk29_dmasrc src; - struct mmc_data *data = host->data; - - BUG_ON(!data); - - host->dma_xfer_size = 0; - - if (data->flags & MMC_DATA_READ){ - direction = DMA_FROM_DEVICE; - src = RK29_DMASRC_HW; - }else{ - direction = DMA_TO_DEVICE; - src = RK29_DMASRC_MEM; - } - - sg_len = rk_mmc_pre_dma_transfer(host, host->data, 0); - if(sg_len < 0){ - host->ops->stop(host); - return sg_len; - } - res = rk29_dma_devconfig(MMC_DMA_CHN, src, host->dma_addr); - if(unlikely(res < 0)) - return res; - - for(i = 0; i < sg_len; i++){ - res = rk29_dma_enqueue(MMC_DMA_CHN, host, - sg_dma_address(&data->sg[i]), - sg_dma_len(&data->sg[i])); - if(unlikely(res < 0)) - return res; - } - res = rk29_dma_ctrl(MMC_DMA_CHN, RK29_DMAOP_START); - if(unlikely(res < 0)) - return res; - - return res; -} -static int dma_stop(struct rk_mmc *host) -{ - int res; - u32 temp; - - /* Disable and reset the DMA interface */ - temp = mmc_readl(host, CTRL); - temp &= ~MMC_CTRL_DMA_ENABLE; - temp |= MMC_CTRL_DMA_RESET; - mmc_writel(host, CTRL, temp); - - res = rk29_dma_ctrl(MMC_DMA_CHN, RK29_DMAOP_STOP); - if(unlikely(res < 0)) - return res; - - rk29_dma_ctrl(MMC_DMA_CHN, RK29_DMAOP_FLUSH); - - return 0; -} -struct rk_mmc_dma_ops dma_ops = { - .init = dma_init, - .stop = dma_stop, - .start = dma_start, - .exit = dma_exit, -}; - -#if defined(CONFIG_DEBUG_FS) -static int rk_mmc_req_show(struct seq_file *s, void *v) -{ - struct rk_mmc *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_bh(&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_bh(&host->lock); - - return 0; -} - -static int rk_mmc_req_open(struct inode *inode, struct file *file) -{ - return single_open(file, rk_mmc_req_show, inode->i_private); -} - -static const struct file_operations rk_mmc_req_fops = { - .owner = THIS_MODULE, - .open = rk_mmc_req_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int rk_mmc_regs_show(struct seq_file *s, void *v) -{ - struct rk_mmc *host = s->private; - - seq_printf(s, "CTRL: 0x%08x\n", mmc_readl(host, CTRL)); - seq_printf(s, "PWREN: 0x%08x\n", mmc_readl(host, PWREN)); - seq_printf(s, "CLKDIV: 0x%08x\n", mmc_readl(host, CLKDIV)); - seq_printf(s, "CLKENA: 0x%08x\n", mmc_readl(host, CLKENA)); - seq_printf(s, "CLKSRC: 0x%08x\n", mmc_readl(host, CLKSRC)); - seq_printf(s, "TMOUT: 0x%08x\n", mmc_readl(host, TMOUT)); - seq_printf(s, "CTYPE: 0x%08x\n", mmc_readl(host, CTYPE)); - seq_printf(s, "BLKSIZ: 0x%08x\n", mmc_readl(host, BLKSIZ)); - seq_printf(s, "BYTCNT: 0x%08x\n", mmc_readl(host, BYTCNT)); - seq_printf(s, "INTMASK: 0x%08x\n", mmc_readl(host, INTMASK)); - seq_printf(s, "CMDARG: 0x%08x\n", mmc_readl(host, CMDARG)); - seq_printf(s, "CMD: 0x%08x\n", mmc_readl(host, CMD)); - seq_printf(s, "RESP0: 0x%08x\n", mmc_readl(host, RESP0)); - seq_printf(s, "RESP1: 0x%08x\n", mmc_readl(host, RESP1)); - seq_printf(s, "RESP2: 0x%08x\n", mmc_readl(host, RESP2)); - seq_printf(s, "RESP3: 0x%08x\n", mmc_readl(host, RESP3)); - seq_printf(s, "MINTSTS: 0x%08x\n", mmc_readl(host, MINTSTS)); - seq_printf(s, "STATUS: 0x%08x\n", mmc_readl(host, STATUS)); - seq_printf(s, "FIFOTH: 0x%08x\n", mmc_readl(host, FIFOTH)); - seq_printf(s, "CDETECT: 0x%08x\n", mmc_readl(host, CDETECT)); - seq_printf(s, "WRTPRT: 0x%08x\n", mmc_readl(host, WRTPRT)); - seq_printf(s, "TCBCNT: 0x%08x\n", mmc_readl(host, TCBCNT)); - seq_printf(s, "TBBCNT: 0x%08x\n", mmc_readl(host, TBBCNT)); - seq_printf(s, "DEBNCE: 0x%08x\n", mmc_readl(host, DEBNCE)); - seq_printf(s, "USRID: 0x%08x\n", mmc_readl(host, USRID)); - seq_printf(s, "VERID: 0x%08x\n", mmc_readl(host, VERID)); - seq_printf(s, "UHS_REG: 0x%08x\n", mmc_readl(host, UHS_REG)); - seq_printf(s, "RST_N: 0x%08x\n", mmc_readl(host, RST_N)); - - return 0; -} - -static int rk_mmc_regs_open(struct inode *inode, struct file *file) -{ - return single_open(file, rk_mmc_regs_show, inode->i_private); -} - -static const struct file_operations rk_mmc_regs_fops = { - .owner = THIS_MODULE, - .open = rk_mmc_regs_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static void rk_mmc_init_debugfs(struct rk_mmc *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, - &rk_mmc_regs_fops); - if (!node) - goto err; - - node = debugfs_create_file("req", S_IRUSR, root, host, - &rk_mmc_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 slot\n"); -} -#endif /* defined(CONFIG_DEBUG_FS) */ - -static void rk_mmc_set_timeout(struct rk_mmc *host) -{ - /* timeout (maximum) */ - mmc_writel(host, TMOUT, 0xffffffff); -} - -static bool mci_wait_reset(struct rk_mmc *host) -{ - unsigned long timeout = jiffies + msecs_to_jiffies(500); - unsigned int ctrl; - - mmc_writel(host, CTRL, (MMC_CTRL_RESET | MMC_CTRL_FIFO_RESET | - MMC_CTRL_DMA_RESET)); - - /* wait till resets clear */ - do { - ctrl = mmc_readl(host, CTRL); - if (!(ctrl & (MMC_CTRL_RESET | MMC_CTRL_FIFO_RESET | - MMC_CTRL_DMA_RESET))) - return true; - } while (time_before(jiffies, timeout)); - - mmc_err(host, "Timeout resetting block (ctrl %#x)\n", ctrl); - - return false; -} - - -static void mmc_wait_data_idle(struct rk_mmc *host) -{ - unsigned long timeout = jiffies + msecs_to_jiffies(500); - unsigned int status = 0; - - while (time_before(jiffies, timeout)) { - status = mmc_readl(host, STATUS); - if (!(status & MMC_DATA_BUSY) && !(status & MMC_MC_BUSY)) - return; - } - mmc_err(host, "Timeout waiting for data idle (status 0x%x)\n", status); -} - -static u32 rk_mmc_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd) -{ - struct mmc_data *data; - u32 cmdr; - cmd->error = -EINPROGRESS; - - cmdr = cmd->opcode; - - if (cmdr == MMC_STOP_TRANSMISSION) - cmdr |= MMC_CMD_STOP; - else - cmdr |= MMC_CMD_PRV_DAT_WAIT; - - if (cmd->flags & MMC_RSP_PRESENT) { - /* We expect a response, so set this bit */ - cmdr |= MMC_CMD_RESP_EXP; - if (cmd->flags & MMC_RSP_136) - cmdr |= MMC_CMD_RESP_LONG; - } - - if (cmd->flags & MMC_RSP_CRC) - cmdr |= MMC_CMD_RESP_CRC; - - data = cmd->data; - if (data) { - cmdr |= MMC_CMD_DAT_EXP; - if (data->flags & MMC_DATA_STREAM) - cmdr |= MMC_CMD_STRM_MODE; - if (data->flags & MMC_DATA_WRITE) - cmdr |= MMC_CMD_DAT_WR; - } - - return cmdr; -} - -static void rk_mmc_start_command(struct rk_mmc *host, - struct mmc_command *cmd, u32 cmd_flags) -{ - host->cmd = cmd; - - mmc_writel(host, CMDARG, cmd->arg); - - mmc_writel(host, CMD, cmd_flags | MMC_CMD_START | MMC_USE_HOLD_REG); -} -static void send_stop_cmd_ex(struct rk_mmc *host) -{ - struct mmc_command cmd; - u32 cmdflags; - - host->stop.opcode = MMC_STOP_TRANSMISSION; - host->stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; - host->stop.arg = 0; - host->stop.data = NULL; - host->stop.mrq = NULL; - host->stop.retries = 0; - host->stop.error = 0; - cmdflags = rk_mmc_prepare_command(host->mmc, &host->stop); - - host->stop_ex = 1; - mmc_dbg(host,"stop command ex: CMD%d, ARGR=0x%08x CMDR=0x%08x\n", - host->stop.opcode, host->stop.arg, cmdflags); - rk_mmc_start_command(host, &cmd, cmdflags); - -} -static void send_stop_cmd(struct rk_mmc *host, struct mmc_data *data) -{ - mmc_dbg(host,"stop command: CMD%d, ARGR=0x%08x CMDR=0x%08x\n", - data->stop->opcode, data->stop->arg, host->stop_cmdr); - rk_mmc_start_command(host, data->stop, host->stop_cmdr); -} - -static void rk_mmc_dma_cleanup(struct rk_mmc *host) -{ - struct mmc_data *data = host->data; - - if (data) - if (!data->host_cookie) - dma_unmap_sg(host->dev, data->sg, data->sg_len, - ((data->flags & MMC_DATA_WRITE) - ? DMA_TO_DEVICE : DMA_FROM_DEVICE)); -} - -/* DMA interface functions */ -static void rk_mmc_stop_dma(struct rk_mmc *host) -{ - if (host->use_dma) { - mmc_dbg(host, "stop dma\n"); - host->ops->stop(host); - rk_mmc_dma_cleanup(host); - } else { - /* Data transfer was stopped by the interrupt handler */ - set_bit(EVENT_XFER_COMPLETE, &host->pending_events); - } -} - -static int rk_mmc_submit_data_dma(struct rk_mmc *host, struct mmc_data *data) -{ - int res; - u32 temp; - - /* Enable the DMA interface */ - temp = mmc_readl(host, CTRL); - temp |= MMC_CTRL_DMA_ENABLE; - mmc_writel(host, CTRL, temp); - - /* Disable RX/TX IRQs, let DMA handle it */ - temp = mmc_readl(host, INTMASK); - temp &= ~(MMC_INT_RXDR | MMC_INT_TXDR); - mmc_writel(host, INTMASK, temp); - - res = host->ops->start(host); - return res; -} - -static void rk_mmc_submit_data(struct rk_mmc *host, struct mmc_data *data) -{ - u32 temp; - - data->error = -EINPROGRESS; - - WARN_ON(host->data); - host->sg = NULL; - host->data = data; - - if (rk_mmc_submit_data_dma(host, data)) { - mmc_dbg(host, "FIFO transfer\n"); - host->sg = data->sg; - host->pio_offset = 0; - if (data->flags & MMC_DATA_READ) - host->dir_status = MMC_RECV_DATA; - else - host->dir_status = MMC_SEND_DATA; - - mmc_writel(host, RINTSTS, MMC_INT_TXDR | MMC_INT_RXDR); - temp = mmc_readl(host, INTMASK); - temp |= MMC_INT_TXDR | MMC_INT_RXDR; - mmc_writel(host, INTMASK, temp); - - temp = mmc_readl(host, CTRL); - temp &= ~MMC_CTRL_DMA_ENABLE; - mmc_writel(host, CTRL, temp); - host->use_dma = 0; - }else{ - mmc_dbg(host, "DMA transfer\n"); - host->use_dma = 1; - } -} - -static void __rk_mmc_start_request(struct rk_mmc *host, struct mmc_command *cmd) -{ - struct mmc_request *mrq = host->mrq; - struct mmc_data *data; - u32 cmdflags; - - host->mrq = mrq; - - host->pending_events = 0; - host->completed_events = 0; - host->data_status = 0; - - data = cmd->data; - if (data) { - rk_mmc_set_timeout(host); - mmc_writel(host, BYTCNT, data->blksz*data->blocks); - mmc_writel(host, BLKSIZ, data->blksz); - } - - cmdflags = rk_mmc_prepare_command(host->mmc, cmd); - - /* this is the first command, send the initialization clock */ - if (test_and_clear_bit(MMC_NEED_INIT, &host->flags)) - cmdflags |= MMC_CMD_INIT; - - if(cmd->opcode == 0) - cmdflags |= MMC_CMD_INIT; - - if (data) { - rk_mmc_submit_data(host, data); - } - if(cmd->opcode == MMC_BUS_TEST_R || cmd->opcode == MMC_BUS_TEST_W) - host->bus_test = 1; - else - host->bus_test = 0; - - mmc_dbg(host,"start command: CMD%d, ARGR=0x%08x CMDR=0x%08x\n", - cmd->opcode, cmd->arg, cmdflags); - rk_mmc_start_command(host, cmd, cmdflags); - - if (mrq->stop) - host->stop_cmdr = rk_mmc_prepare_command(host->mmc, mrq->stop); -} - -static void rk_mmc_start_request(struct rk_mmc *host) -{ - struct mmc_request *mrq = host->mrq; - struct mmc_command *cmd; - - cmd = mrq->sbc ? mrq->sbc : mrq->cmd; - __rk_mmc_start_request(host, cmd); -} -static void rk_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) -{ - struct rk_mmc *host = mmc_priv(mmc); - - WARN_ON(host->mrq); - WARN_ON(host->state != STATE_IDLE); - WARN_ON(host->shutdown == 1); - - spin_lock_bh(&host->lock); - host->state = STATE_SENDING_CMD; - host->mrq = mrq; - rk_mmc_start_request(host); - spin_unlock_bh(&host->lock); -} - -static void mci_send_cmd(struct rk_mmc *host, u32 cmd, u32 arg) -{ - unsigned long timeout = jiffies + msecs_to_jiffies(500); - unsigned int cmd_status = 0; - - mmc_writel(host, CMDARG, arg); - mmc_writel(host, CMD, MMC_CMD_START | cmd); - - while (time_before(jiffies, timeout)) { - cmd_status = mmc_readl(host, CMD); - if (!(cmd_status & MMC_CMD_START)) - return; - } - mmc_err(host, "Timeout sending command (cmd %#x arg %#x status %#x)\n", - cmd, arg, cmd_status); -} - - -static void rk_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - struct rk_mmc *host = mmc_priv(mmc); - u32 regs, div; - - /* set default 1 bit mode */ - host->ctype = MMC_CTYPE_1BIT; - - switch (ios->bus_width) { - case MMC_BUS_WIDTH_1: - host->ctype = MMC_CTYPE_1BIT; - break; - case MMC_BUS_WIDTH_4: - host->ctype = MMC_CTYPE_4BIT; - break; - case MMC_BUS_WIDTH_8: - host->ctype = MMC_CTYPE_8BIT; - break; - } - /* DDR mode set */ - if (ios->timing == MMC_TIMING_UHS_DDR50){ - regs = mmc_readl(host, UHS_REG); - regs |= MMC_UHS_DDR_MODE; - mmc_writel(host, UHS_REG, regs); - } - if (ios->clock && ios->clock != host->curr_clock) { - if (host->bus_hz % ios->clock) - div = ((host->bus_hz / ios->clock) >> 1) + 1; - else - div = (host->bus_hz / ios->clock) >> 1; - - mmc_dbg(host, "Bus clock: %dHz, req: %dHz, actual: %dHz, div: %d\n", - host->bus_hz, ios->clock, - div ? ((host->bus_hz / div) >> 1) : host->bus_hz, div); - - /* disable clock */ - mmc_writel(host, CLKENA, 0); - mmc_writel(host, CLKSRC, 0); - - /* inform CIU */ - mci_send_cmd(host, - MMC_CMD_UPD_CLK | MMC_CMD_PRV_DAT_WAIT, 0); - - /* set clock to desired speed */ - mmc_writel(host, CLKDIV, div); - - /* inform CIU */ - mci_send_cmd(host, - MMC_CMD_UPD_CLK | MMC_CMD_PRV_DAT_WAIT, 0); - - /* enable clock */ - mmc_writel(host, CLKENA, MMC_CLKEN_ENABLE | MMC_CLKEN_LOW_PWR); - - /* inform CIU */ - mci_send_cmd(host, - MMC_CMD_UPD_CLK | MMC_CMD_PRV_DAT_WAIT, 0); - - host->curr_clock = ios->clock; - } - - switch (ios->power_mode) { - case MMC_POWER_UP: - mmc_dbg(host, "power up\n"); - mmc_writel(host, PWREN, MMC_PWREN_ON); -#if 0 - mmc_writel(host, RST_N, 0); - mdelay(60); - mmc_writel(host, RST_N, MMC_CARD_RESET); -#endif - set_bit(MMC_NEED_INIT, &host->flags); - break; - case MMC_POWER_OFF: - mmc_dbg(host, "power off\n"); - mmc_writel(host, PWREN, 0); - default: - break; - } - mmc_dbg(host, "ctype: 0x%x\n", host->ctype); - mmc_writel(host, CTYPE, host->ctype); -} - -static int rk_mmc_get_ro(struct mmc_host *mmc) -{ - //struct rk_mmc *host = mmc_priv(mmc); - - return 0; -} - -static int rk_mmc_get_cd(struct mmc_host *mmc) -{ - //struct rk_mmc *host = mmc_priv(mmc); - - return 1; -} - -static int rk_mmc_get_dma_dir(struct mmc_data *data) -{ - if (data->flags & MMC_DATA_WRITE) - return DMA_TO_DEVICE; - else - return DMA_FROM_DEVICE; -} - -static int rk_mmc_pre_dma_transfer(struct rk_mmc *host, - struct mmc_data *data, - bool next) -{ - struct scatterlist *sg; - unsigned int i, sg_len; - - if (!next && data->host_cookie) - return data->host_cookie; - - /* - * We don't do DMA on "complex" transfers, i.e. with - * non-word-aligned buffers or lengths. Also, we don't bother - * with all the DMA setup overhead for short transfers. - */ - if (data->blocks * data->blksz < MMC_DMA_THRESHOLD) - return -EINVAL; - if (data->blksz & 3) - return -EINVAL; - - for_each_sg(data->sg, sg, data->sg_len, i) { - if (sg->offset & 3 || sg->length & 3) - return -EINVAL; - } - - sg_len = dma_map_sg(host->dev, - data->sg, - data->sg_len, - rk_mmc_get_dma_dir(data)); - if (sg_len == 0) - return -EINVAL; - if (next) - data->host_cookie = sg_len; - - return sg_len; -} -static void rk_mmc_pre_req(struct mmc_host *mmc, - struct mmc_request *mrq, - bool is_first_req) -{ - struct rk_mmc *host = mmc_priv(mmc); - struct mmc_data *data = mrq->data; - - if(!data) - return; - if (data->host_cookie) { - data->host_cookie = 0; - return; - } - if (rk_mmc_pre_dma_transfer(host, mrq->data, 1) < 0) - data->host_cookie = 0; - -} -static void rk_mmc_post_req(struct mmc_host *mmc, - struct mmc_request *mrq, - int err) -{ - struct rk_mmc *host = mmc_priv(mmc); - struct mmc_data *data = mrq->data; - - if(!data) - return; - if (data->host_cookie) - dma_unmap_sg(host->dev, - data->sg, - data->sg_len, - rk_mmc_get_dma_dir(data)); - data->host_cookie = 0; -} - -static const struct mmc_host_ops rk_mmc_ops = { - .request = rk_mmc_request, - .set_ios = rk_mmc_set_ios, - .get_ro = rk_mmc_get_ro, - .get_cd = rk_mmc_get_cd, - .pre_req = rk_mmc_pre_req, - .post_req = rk_mmc_post_req, -}; - -static void rk_mmc_request_end(struct rk_mmc *host, struct mmc_request *mrq) - __releases(&host->lock) - __acquires(&host->lock) - -{ - WARN_ON(host->cmd || host->data); - host->mrq = NULL; - host->state = STATE_IDLE; - spin_unlock(&host->lock); - mmc_wait_data_idle(host); - mmc_dbg(host, "mmc request done, RINSTS: 0x%x, pending_events: %lu\n", - mmc_readl(host, RINTSTS), host->pending_events); - if(host->bus_test && mrq->data && mrq->data->error == 0){ - u32 ctype, div; - - ctype = mmc_readl(host, CTYPE); - div = mmc_readl(host, CLKDIV); - - if(ctype & MMC_CTYPE_8BIT) - mmc_info(host, "bus width: 8 bit, clock: %uHz\n", - host->bus_hz/(div+1)); - else if(ctype & MMC_CTYPE_4BIT) - mmc_info(host, "bus width: 4 bit, clock: %uHz\n", - host->bus_hz/(div+1)); - else - mmc_info(host, "bus width: 1 bit, clock: %uHz\n", - host->bus_hz/(div+1)); - } - mmc_request_done(host->mmc, mrq); - spin_lock(&host->lock); -} - -static void rk_mmc_command_complete(struct rk_mmc *host, struct mmc_command *cmd) -{ - u32 status = host->cmd_status; - - host->cmd_status = 0; - - /* Read the response from the card (up to 16 bytes) */ - if (cmd->flags & MMC_RSP_PRESENT) { - if (cmd->flags & MMC_RSP_136) { - cmd->resp[3] = mmc_readl(host, RESP0); - cmd->resp[2] = mmc_readl(host, RESP1); - cmd->resp[1] = mmc_readl(host, RESP2); - cmd->resp[0] = mmc_readl(host, RESP3); - } else { - cmd->resp[0] = mmc_readl(host, RESP0); - cmd->resp[1] = 0; - cmd->resp[2] = 0; - cmd->resp[3] = 0; - } - } - - if (status & MMC_INT_RTO){ - mmc_dbg(host, "CMD%d response timeout\n", cmd->opcode); - cmd->error = -ETIMEDOUT; - } - else if ((cmd->flags & MMC_RSP_CRC) && (status & MMC_INT_RCRC)){ - mmc_dbg(host, "CMD%d crc error\n", cmd->opcode); - cmd->error = -EILSEQ; - } - else if (status & MMC_INT_RESP_ERR){ - mmc_dbg(host, "CMD%d response error\n", cmd->opcode); - cmd->error = -EIO; - } - else - cmd->error = 0; - - if (cmd->error) { - /* newer ip versions need a delay between retries */ - mdelay(20); - - if (cmd->data) { - host->data = NULL; - rk_mmc_stop_dma(host); - } - } -} - -static void rk_mmc_tasklet_func(unsigned long priv) -{ - struct rk_mmc *host = (struct rk_mmc *)priv; - struct mmc_data *data; - struct mmc_command *cmd; - enum rk_mmc_state state; - enum rk_mmc_state prev_state; - u32 status; - - spin_lock(&host->lock); - - state = host->state; - data = host->data; - - do { - prev_state = state; - - switch (state) { - case STATE_IDLE: - break; - - case STATE_SENDING_CMD: - mmc_dbg(host, "sending cmd, pending_events: %lx\n", host->pending_events); - if (!test_and_clear_bit(EVENT_CMD_COMPLETE, - &host->pending_events)) - break; - - cmd = host->cmd; - host->cmd = NULL; - set_bit(EVENT_CMD_COMPLETE, &host->completed_events); - rk_mmc_command_complete(host, cmd); - if (cmd == host->mrq->sbc && !cmd->error) { - prev_state = state = STATE_SENDING_CMD; - __rk_mmc_start_request(host, host->mrq->cmd); - goto unlock; - } - - if (!host->mrq->data || cmd->error) { - rk_mmc_request_end(host, host->mrq); - goto unlock; - } - - prev_state = state = STATE_SENDING_DATA; - /* fall through */ - - case STATE_SENDING_DATA: - mmc_dbg(host, "sending data, pending_events: %lx\n", host->pending_events); - if (test_and_clear_bit(EVENT_DATA_ERROR, - &host->pending_events)) { - rk_mmc_stop_dma(host); - if (data->stop) - send_stop_cmd(host, data); - else - send_stop_cmd_ex(host); - state = STATE_DATA_ERROR; - break; - } - - if (!test_and_clear_bit(EVENT_XFER_COMPLETE, - &host->pending_events)) - break; - - set_bit(EVENT_XFER_COMPLETE, &host->completed_events); - prev_state = state = STATE_DATA_BUSY; - /* fall through */ - - case STATE_DATA_BUSY: - mmc_dbg(host, "data busy, pending_events: %lx, data_status: %08x, status: %08x\n", - host->pending_events, host->data_status, mmc_readl(host, STATUS)); - if (!test_and_clear_bit(EVENT_DATA_COMPLETE, - &host->pending_events)){ - break; - } - host->data = NULL; - set_bit(EVENT_DATA_COMPLETE, &host->completed_events); - status = host->data_status; - - if (status & MMC_DATA_ERROR_FLAGS) { - if (status & MMC_INT_DTO) { - if(!host->bus_test) - mmc_err(host, "data timeout error " - "(data_status=%08x)\n", status); - data->error = -ETIMEDOUT; - } else if (status & MMC_INT_DCRC) { - if(!host->bus_test) - mmc_err(host, "data CRC error " - "(data_status=%08x)\n", status); - data->error = -EILSEQ; - } else { - if(!host->bus_test) - mmc_err(host, "data FIFO error " - "(data_status=%08x)\n", status); - data->error = -EIO; - } - } else { - data->bytes_xfered = data->blocks * data->blksz; - data->error = 0; - } - - if (!data->stop && !host->stop_ex) { - rk_mmc_request_end(host, host->mrq); - goto unlock; - } - - if (host->mrq->sbc && !data->error) { - data->stop->error = 0; - rk_mmc_request_end(host, host->mrq); - goto unlock; - } - - prev_state = state = STATE_SENDING_STOP; - if (!data->error && data->stop) - send_stop_cmd(host, data); - /* fall through */ - - case STATE_SENDING_STOP: - mmc_dbg(host, "sending stop, pending_events: %lx\n", host->pending_events); - if (!test_and_clear_bit(EVENT_CMD_COMPLETE, - &host->pending_events)) - break; - - host->cmd = NULL; - if(host->stop_ex){ - host->stop_ex = 0; - rk_mmc_command_complete(host, &host->stop); - } - else - rk_mmc_command_complete(host, host->mrq->stop); - rk_mmc_request_end(host, host->mrq); - goto unlock; - - case STATE_DATA_ERROR: - mmc_dbg(host, "data error, pending_events: %lx\n", host->pending_events); - if (!test_and_clear_bit(EVENT_XFER_COMPLETE, - &host->pending_events)) - break; - - state = STATE_DATA_BUSY; - break; - } - } while (state != prev_state); - - host->state = state; -unlock: - spin_unlock(&host->lock); - -} - - -static void rk_mmc_push_data(struct rk_mmc *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) { - mmc_writel(host, DATA, *pdata++); - cnt--; - } -} - -static void rk_mmc_pull_data(struct rk_mmc *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++ = mmc_readl(host, DATA); - cnt--; - } -} - -static void rk_mmc_read_data_pio(struct rk_mmc *host) -{ - struct scatterlist *sg = host->sg; - void *buf = sg_virt(sg); - unsigned int offset = host->pio_offset; - struct mmc_data *data = host->data; - u32 status; - unsigned int nbytes = 0, len; - - mmc_dbg(host, "read data pio\n"); - - do { - len = MMC_GET_FCNT(mmc_readl(host, STATUS)) << 2; - if (offset + len <= sg->length) { - rk_mmc_pull_data(host, (void *)(buf + offset), len); - - offset += len; - nbytes += len; - - if (offset == sg->length) { - flush_dcache_page(sg_page(sg)); - host->sg = sg = sg_next(sg); - if (!sg) - goto done; - - offset = 0; - buf = sg_virt(sg); - } - } else { - unsigned int remaining = sg->length - offset; - rk_mmc_pull_data(host, (void *)(buf + offset), - remaining); - nbytes += remaining; - - flush_dcache_page(sg_page(sg)); - host->sg = sg = sg_next(sg); - if (!sg) - goto done; - - offset = len - remaining; - buf = sg_virt(sg); - rk_mmc_pull_data(host, buf, offset); - nbytes += offset; - } - - status = mmc_readl(host, MINTSTS); - mmc_writel(host, RINTSTS, MMC_INT_RXDR); - if (status & MMC_DATA_ERROR_FLAGS) { - host->data_status = status; - data->bytes_xfered += nbytes; - - set_bit(EVENT_DATA_ERROR, &host->pending_events); - - tasklet_schedule(&host->tasklet); - return; - } - } while (status & MMC_INT_RXDR); /*if the RXDR is ready read again*/ - len = MMC_GET_FCNT(mmc_readl(host, STATUS)); - host->pio_offset = offset; - data->bytes_xfered += nbytes; - return; - -done: - data->bytes_xfered += nbytes; - set_bit(EVENT_XFER_COMPLETE, &host->pending_events); -} - -static void rk_mmc_write_data_pio(struct rk_mmc *host) -{ - struct scatterlist *sg = host->sg; - void *buf = sg_virt(sg); - unsigned int offset = host->pio_offset; - struct mmc_data *data = host->data; - u32 status; - unsigned int nbytes = 0, len; - - mmc_dbg(host, "write data pio\n"); - do { - len = FIFO_DETH - - (MMC_GET_FCNT(mmc_readl(host, STATUS)) << 2); - if (offset + len <= sg->length) { - rk_mmc_push_data(host, (void *)(buf + offset), len); - - offset += len; - nbytes += len; - if (offset == sg->length) { - host->sg = sg = sg_next(sg); - if (!sg) - goto done; - - offset = 0; - buf = sg_virt(sg); - } - } else { - unsigned int remaining = sg->length - offset; - - rk_mmc_push_data(host, (void *)(buf + offset), - remaining); - nbytes += remaining; - - host->sg = sg = sg_next(sg); - if (!sg) - goto done; - - offset = len - remaining; - buf = sg_virt(sg); - rk_mmc_push_data(host, (void *)buf, offset); - nbytes += offset; - } - - status = mmc_readl(host, MINTSTS); - mmc_writel(host, RINTSTS, MMC_INT_TXDR); - if (status & MMC_DATA_ERROR_FLAGS) { - host->data_status = status; - data->bytes_xfered += nbytes; - - set_bit(EVENT_DATA_ERROR, &host->pending_events); - - tasklet_schedule(&host->tasklet); - return; - } - } while (status & MMC_INT_TXDR); /* if TXDR write again */ - - host->pio_offset = offset; - data->bytes_xfered += nbytes; - - return; - -done: - data->bytes_xfered += nbytes; - set_bit(EVENT_XFER_COMPLETE, &host->pending_events); -} - -static void rk_mmc_cmd_interrupt(struct rk_mmc *host, u32 status) -{ - if (!host->cmd_status) - host->cmd_status = status; - - set_bit(EVENT_CMD_COMPLETE, &host->pending_events); - tasklet_schedule(&host->tasklet); -} - -static irqreturn_t rk_mmc_interrupt(int irq, void *dev_id) -{ - struct rk_mmc *host = dev_id; - u32 status, pending; - unsigned int pass_count = 0; - - do { - status = mmc_readl(host, RINTSTS); - pending = mmc_readl(host, MINTSTS); /* read-only mask reg */ - mmc_dbg(host, "RINSTS: 0x%x, MINTSTS: 0x%x\n", status, pending); - - if (!pending) - break; - - if (pending & MMC_CMD_ERROR_FLAGS) { - mmc_writel(host, RINTSTS, MMC_CMD_ERROR_FLAGS); - host->cmd_status = status; - set_bit(EVENT_CMD_COMPLETE, &host->pending_events); - tasklet_schedule(&host->tasklet); - } - - if (pending & MMC_DATA_ERROR_FLAGS) { - /* if there is an error report DATA_ERROR */ - mmc_writel(host, RINTSTS, MMC_DATA_ERROR_FLAGS); - host->data_status = status; - set_bit(EVENT_DATA_ERROR, &host->pending_events); - tasklet_schedule(&host->tasklet); - } - - if (pending & MMC_INT_DATA_OVER) { - mmc_dbg(host, "data over int\n"); - mmc_writel(host, RINTSTS, MMC_INT_DATA_OVER); - if (!host->data_status) - host->data_status = status; - if (host->dir_status == MMC_RECV_DATA) { - if (host->sg != NULL) - rk_mmc_read_data_pio(host); - } - set_bit(EVENT_DATA_COMPLETE, &host->pending_events); - tasklet_schedule(&host->tasklet); - } - - if (pending & MMC_INT_RXDR) { - mmc_writel(host, RINTSTS, MMC_INT_RXDR); - if (host->sg) - rk_mmc_read_data_pio(host); - } - - if (pending & MMC_INT_TXDR) { - mmc_writel(host, RINTSTS, MMC_INT_TXDR); - if (host->sg) - rk_mmc_write_data_pio(host); - } - - if (pending & MMC_INT_CMD_DONE) { - mmc_writel(host, RINTSTS, MMC_INT_CMD_DONE); - rk_mmc_cmd_interrupt(host, status); - } - } while (pass_count++ < 5); - - return IRQ_HANDLED; -} - -#define EMMC_FLAHS_SEL (1<<11) -static int internal_storage_is_emmc(void) -{ -#ifdef CONFIG_ARCH_RK3026 - if((iomux_is_set(EMMC_CLKOUT) == 1) && - (iomux_is_set(EMMC_CMD) == 1) && - (iomux_is_set(EMMC_D0) == 1)) - return 1; -#else - if(readl_relaxed(RK30_GRF_BASE + GRF_SOC_CON0) & EMMC_FLAHS_SEL) - return 1; -#endif - return 0; -} -static void rk_mmc_set_iomux(void) -{ - iomux_set(EMMC_CLKOUT); - iomux_set(EMMC_CMD); - iomux_set(EMMC_RSTNOUT); -#ifdef CONFIG_ARCH_RK3026 - iomux_set(EMMC_PWREN); - iomux_set(EMMC_D0); - iomux_set(EMMC_D1); - iomux_set(EMMC_D2); - iomux_set(EMMC_D3); - iomux_set(EMMC_D4); - iomux_set(EMMC_D5); - iomux_set(EMMC_D6); - iomux_set(EMMC_D7); -#endif -} - -static int rk_mmc_probe(struct platform_device *pdev) -{ - struct rk_mmc *host; - struct mmc_host *mmc; - struct resource *regs; - int res; - - if(!internal_storage_is_emmc()){ - dev_err(&pdev->dev, "internal_storage is NOT emmc\n"); - return -ENXIO; - } - - rk_mmc_set_iomux(); - - regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!regs) - return -ENXIO; - - mmc = mmc_alloc_host(sizeof(struct rk_mmc), &pdev->dev); - if (!mmc) - return -ENOMEM; - - host = mmc_priv(mmc); - host->mmc = mmc; - - mmc->ops = &rk_mmc_ops; - mmc->unused = 1; - - host->irq = platform_get_irq(pdev, 0); - if (host->irq < 0) - return host->irq; - - host->dev = &pdev->dev; - host->ops = &dma_ops; - host->state = STATE_IDLE; - - res = -ENOMEM; - host->clk = clk_get(&pdev->dev, "emmc"); - if(!host->clk) - goto err_freehost; - clk_set_rate(host->clk, MMC_BUS_CLOCK); - host->bus_hz = clk_get_rate(host->clk); - - clk_enable(host->clk); - clk_enable(clk_get(&pdev->dev, "hclk_emmc")); - - spin_lock_init(&host->lock); - - host->regs = ioremap(regs->start, regs->end - regs->start + 1); - if (!host->regs) - goto err_putclk; - - host->dma_addr = regs->start + MMC_DATA; - - res = host->ops->init(host); - if(res < 0) - goto err_iounmap; - - /* Reset all blocks */ - if (!mci_wait_reset(host)) { - res = -ENODEV; - goto err_exitdma; - } - - /* Clear the interrupts for the host controller */ - mmc_writel(host, RINTSTS, 0xFFFFFFFF); - mmc_writel(host, INTMASK, 0); /* disable all mmc interrupt first */ - - /* Put in max timeout */ - mmc_writel(host, TMOUT, 0xFFFFFFFF); - mmc_writel(host, FIFOTH, - (0x3 << 28) | ((FIFO_DETH/2 - 1) << 16) | ((FIFO_DETH/2) << 0)); - /* disable clock to CIU */ - mmc_writel(host, CLKENA, 0); - mmc_writel(host, CLKSRC, 0); - tasklet_init(&host->tasklet, rk_mmc_tasklet_func, (unsigned long)host); - - res = request_irq(host->irq, rk_mmc_interrupt, 0, "emmc", host); - if (res < 0) - goto err_exitdma; - - mmc->f_min = DIV_ROUND_UP(host->bus_hz, 510); - mmc->f_max = host->bus_hz/2; - - mmc->ocr_avail = MMC_VDD_165_195| MMC_VDD_29_30 | MMC_VDD_30_31 | - MMC_VDD_31_32 | MMC_VDD_32_33 | MMC_VDD_33_34; - - mmc->caps = MMC_CAP_4_BIT_DATA| MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE | - MMC_CAP_1_8V_DDR | MMC_CAP_UHS_DDR50 | - MMC_CAP_BUS_WIDTH_TEST | - MMC_CAP_ERASE | - MMC_CAP_CMD23 | - /*MMC_CAP_WAIT_WHILE_BUSY |*/ - MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED; - - //mmc->caps2 = MMC_CAP2_CACHE_CTRL; - - mmc->max_segs = 64; - mmc->max_blk_size = 512; - mmc->max_blk_count = 4096; - mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; - mmc->max_seg_size = mmc->max_req_size; -#if 0 - if(grf_get_io_power_domain_voltage(IO_PD_FLASH) == IO_PD_VOLTAGE_1_8V) - mmc_writel(host, UHS_REG, MMC_UHS_VOLT_18); -#endif - mmc_writel(host, RINTSTS, 0xFFFFFFFF); - mmc_writel(host, INTMASK, MMC_INT_CMD_DONE | MMC_INT_DATA_OVER | - MMC_INT_TXDR | MMC_INT_RXDR | MMC_ERROR_FLAGS); - mmc_writel(host, CTRL, MMC_CTRL_INT_ENABLE); /* Enable mci interrupt */ - platform_set_drvdata(pdev, host); - - mmc_add_host(mmc); - -#if defined(CONFIG_DEBUG_FS) - rk_mmc_init_debugfs(host); -#endif - - mmc_info(host, "MMC controller initialized, bus_hz: %uHz\n", host->bus_hz); - - return 0; -err_exitdma: - host->ops->exit(host); -err_iounmap: - iounmap(host->regs); -err_putclk: - clk_disable(host->clk); - clk_disable(clk_get(&pdev->dev, "hclk_mmc")); - clk_put(host->clk); -err_freehost: - mmc_free_host(mmc); - - return res; -} -static void rk_mmc_shutdown(struct platform_device *pdev) -{ - struct rk_mmc *host = platform_get_drvdata(pdev); - //struct mmc_host *mmc = host->mmc; - - mmc_info(host, "shutdown\n"); - - host->shutdown = 1; - //card go pre-idle state - mmc_writel(host, CMDARG, 0xF0F0F0F0); - mmc_writel(host, CMD, 0 | MMC_CMD_INIT | MMC_CMD_START | MMC_USE_HOLD_REG); - mdelay(10); -#if 0 - host->shutdown = 1; - mmc_remove_host(host->mmc); - mmc_info(host, "mmc removed\n"); - platform_set_drvdata(pdev, NULL); - - host->ops->exit(host); - - free_irq(host->irq, host); - mmc_writel(host, RINTSTS, 0xFFFFFFFF); - mmc_writel(host, INTMASK, 0); /* disable all mmc interrupt first */ - mmc_writel(host, PWREN, 0); - mmc_writel(host, RST_N, 0); - - /* disable clock to CIU */ - mmc_writel(host, CLKENA, 0); - mmc_writel(host, CLKSRC, 0); - clk_disable(host->clk); - clk_disable(clk_get(&pdev->dev, "hclk_mmc")); - clk_put(host->clk); - - iounmap(host->regs); - - mmc_free_host(mmc); -#endif - mmc_writel(host, PWREN, 0); - mmc_writel(host, RST_N, 0); - - return; -} -static int __exit rk_mmc_remove(struct platform_device *pdev) -{ - rk_mmc_shutdown(pdev); - return 0; -} -#ifdef CONFIG_PM -static int rk_mmc_suspend(struct platform_device *pdev, pm_message_t mesg) -{ - int res = 0; - struct rk_mmc *host = platform_get_drvdata(pdev); - - res = mmc_suspend_host(host->mmc); - return res; -} - -static int rk_mmc_resume(struct platform_device *pdev) -{ - int res = 0; - - struct rk_mmc *host = platform_get_drvdata(pdev); - - if (!mci_wait_reset(host)) { - res = -ENODEV; - return res; - } - mmc_writel(host, FIFOTH, - (0x3 << 28) | ((FIFO_DETH/2 - 1) << 16) | ((FIFO_DETH/2) << 0)); - - mmc_writel(host, UHS_REG, 0); - - /* disable clock to CIU */ - mmc_writel(host, CLKENA, 0); - mmc_writel(host, CLKSRC, 0); - - mmc_writel(host, RINTSTS, 0xFFFFFFFF); - mmc_writel(host, INTMASK, MMC_INT_CMD_DONE | MMC_INT_DATA_OVER | - MMC_INT_TXDR | MMC_INT_RXDR | MMC_ERROR_FLAGS); - mmc_writel(host, CTRL, MMC_CTRL_INT_ENABLE); - - res = mmc_resume_host(host->mmc); - - return res; -} -#else -#define rk_mmc_suspend NULL -#define rk_mmc_resume NULL -#endif /* CONFIG_PM */ - -static struct platform_driver rk_mmc_driver = { - .remove = __exit_p(rk_mmc_remove), - .shutdown = rk_mmc_shutdown, - .suspend = rk_mmc_suspend, - .resume = rk_mmc_resume, - .driver = { - .name = "emmc", - }, -}; - -static int __init rk_mmc_init(void) -{ - return platform_driver_probe(&rk_mmc_driver, rk_mmc_probe); -} - -static void __exit rk_mmc_exit(void) -{ - platform_driver_unregister(&rk_mmc_driver); -} - -fs_initcall(rk_mmc_init); -module_exit(rk_mmc_exit); diff --git a/drivers/mmc/host/rkemmc_ops.c b/drivers/mmc/host/rkemmc_ops.c deleted file mode 100644 index 8d8d01fa17b9..000000000000 --- a/drivers/mmc/host/rkemmc_ops.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - * linux/drivers/mmchost/rkemmc_ops.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - */ - -#include -#include -#include -#include -#include - -#include -#include /* For nr_free_buffer_pages() */ -#include - -#include -#include -#include -#include -#include - -#define BLKSZ 512 - -struct mmc_card *this_card = NULL; -/* - * Fill in the mmc_request structure given a set of transfer parameters. - */ -static void rk_emmc_prepare_mrq(struct mmc_request *mrq, struct scatterlist *sg, - unsigned sg_len, unsigned dev_addr, unsigned blocks, unsigned blksz, int write) -{ - BUG_ON(!mrq || !mrq->cmd || !mrq->data || !mrq->stop); - - if (blocks > 1) { - mrq->cmd->opcode = write ? - MMC_WRITE_MULTIPLE_BLOCK : MMC_READ_MULTIPLE_BLOCK; - } else { - mrq->cmd->opcode = write ? - MMC_WRITE_BLOCK : MMC_READ_SINGLE_BLOCK; - } - - mrq->cmd->arg = dev_addr; - if (!mmc_card_blockaddr(this_card)) - mrq->cmd->arg <<= 9; - - mrq->cmd->flags = MMC_RSP_R1 | MMC_CMD_ADTC; - - if (blocks == 1) - mrq->stop = NULL; - else { - mrq->stop->opcode = MMC_STOP_TRANSMISSION; - mrq->stop->arg = 0; - mrq->stop->flags = MMC_RSP_R1B | MMC_CMD_AC; - } - - mrq->data->blksz = blksz; - mrq->data->blocks = blocks; - mrq->data->flags = write ? MMC_DATA_WRITE : MMC_DATA_READ; - mrq->data->sg = sg; - mrq->data->sg_len = sg_len; - mmc_set_data_timeout(mrq->data, this_card); -} - -static int rk_emmc_busy(struct mmc_command *cmd) -{ - return !(cmd->resp[0] & R1_READY_FOR_DATA) || - (R1_CURRENT_STATE(cmd->resp[0]) == 7); -} - -/* - * Wait for the card to finish the busy state - */ -static int rk_emmc_wait_busy(void) -{ - int ret, busy; - struct mmc_command cmd = {0}; - - busy = 0; - do { - memset(&cmd, 0, sizeof(struct mmc_command)); - - cmd.opcode = MMC_SEND_STATUS; - cmd.arg = this_card->rca << 16; - cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; - - ret = mmc_wait_for_cmd(this_card->host, &cmd, 0); - if (ret) - break; - - if (!busy && rk_emmc_busy(&cmd)) { - busy = 1; - if (this_card->host->caps & MMC_CAP_WAIT_WHILE_BUSY) - pr_info("%s: Warning: Host did not " - "wait for busy state to end.\n", - mmc_hostname(this_card->host)); - } - } while (rk_emmc_busy(&cmd)); - - return ret; -} - -/* - * Transfer a single sector of kernel addressable data - */ -int rk_emmc_transfer(u8 *buffer, unsigned addr, unsigned blksz, int write) -{ - int ret = 0; - - struct mmc_request mrq = {0}; - struct mmc_command cmd = {0}; - struct mmc_command stop = {0}; - struct mmc_data data = {0}; - - struct scatterlist sg; - - if(!this_card) - return -EIO; - - mrq.cmd = &cmd; - mrq.data = &data; - mrq.stop = &stop; - - sg_init_one(&sg, buffer, blksz); - - rk_emmc_prepare_mrq(&mrq, &sg, 1, addr, 1, blksz, write); - - mmc_claim_host(this_card->host); - mmc_wait_for_req(this_card->host, &mrq); - - if (cmd.error){ - ret = cmd.error; - goto exit; - } - if (data.error){ - ret = data.error; - goto exit; - } - - ret = rk_emmc_wait_busy(); -exit: - mmc_release_host(this_card->host); - return ret; -} -EXPORT_SYMBOL(rk_emmc_transfer);