From: xbw Date: Wed, 12 Mar 2014 06:37:47 +0000 (+0800) Subject: SDMMC: eMMC OK. It is good to run correctly from emmc X-Git-Tag: firefly_0821_release~6125 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=3bf6d8c0cc384190cae73beda2f592a6ce39e4f1;p=firefly-linux-kernel-4.4.55.git SDMMC: eMMC OK. It is good to run correctly from emmc --- diff --git a/arch/arm/boot/dts/rk3188-mmc.dtsi b/arch/arm/boot/dts/rk3188-mmc.dtsi index 7af74975f783..68817fb0f486 100755 --- a/arch/arm/boot/dts/rk3188-mmc.dtsi +++ b/arch/arm/boot/dts/rk3188-mmc.dtsi @@ -83,7 +83,7 @@ sdio: rksdmmc@10218000 { - compatible = "rockchip,rk_mmc"; + compatible = "rockchip,rk_mmc"; reg = <0x10218000 0x4000>; interrupts = ; #address-cells = <1>; diff --git a/arch/arm/boot/dts/rk3188-tb.dts b/arch/arm/boot/dts/rk3188-tb.dts index 01fc551f90c6..e3d379939cff 100755 --- a/arch/arm/boot/dts/rk3188-tb.dts +++ b/arch/arm/boot/dts/rk3188-tb.dts @@ -2,9 +2,11 @@ #include "rk3188.dtsi" #include "rk3188-clocks.dtsi" -#include "lcd-b101ew05.dtsi" -#include "rk3188-mmc.dtsi" #include + +#include "rk3188-mmc.dtsi" +#include "lcd-b101ew05.dtsi" + / { memory { device_type = "memory"; diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c old mode 100644 new mode 100755 index 41c27b74b003..93fc6a725dba --- a/drivers/mmc/host/dw_mmc-pltfm.c +++ b/drivers/mmc/host/dw_mmc-pltfm.c @@ -19,10 +19,11 @@ #include #include #include -#include +#include #include -#include "dw_mmc.h" +#include "rk_sdmmc.h" + int dw_mci_pltfm_register(struct platform_device *pdev, const struct dw_mci_drv_data *drv_data) diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c index e75585baa010..d62c3dc2eb77 100755 --- a/drivers/mmc/host/dw_mmc-rockchip.c +++ b/drivers/mmc/host/dw_mmc-rockchip.c @@ -155,7 +155,7 @@ static int dw_mci_rockchip_parse_dt(struct dw_mci *host) /* Common capabilities of RK32XX SoC */ static unsigned long rockchip_dwmmc_caps[4] = { - MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR | + /*MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR | //Temporarily comment out!!!!!!, deleted by xbw, at 2014-03-12*/ MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23, MMC_CAP_CMD23, MMC_CAP_CMD23, diff --git a/drivers/mmc/host/rk_sdmmc.c b/drivers/mmc/host/rk_sdmmc.c index 00c480dfadbe..259dda15dca8 100755 --- a/drivers/mmc/host/rk_sdmmc.c +++ b/drivers/mmc/host/rk_sdmmc.c @@ -58,6 +58,10 @@ #define DW_MCI_FREQ_MAX 50000000//200000000 /* unit: HZ */ #define DW_MCI_FREQ_MIN 300000//400000 /* unit: HZ */ +#define SDMMC_DATA_TIMEOUT_SD 500000; /*max is 250ms refer to Spec; Maybe adapt the value to the sick card.*/ +#define SDMMC_DATA_TIMEOUT_SDIO 250000 +#define SDMMC_DATA_TIMEOUT_EMMC 2500000 + #ifdef CONFIG_MMC_DW_IDMAC #define IDMAC_INT_CLR (SDMMC_IDMAC_INT_AI | SDMMC_IDMAC_INT_NI | \ SDMMC_IDMAC_INT_CES | SDMMC_IDMAC_INT_DU | \ @@ -339,7 +343,7 @@ static void dw_mci_start_command(struct dw_mci *host, mci_writel(host, CMDARG, cmd->arg); wmb(); - MMC_DBG_CMD_FUNC("%d..%s start cmd=%d, arg=0x%x[%s]",__LINE__, __FUNCTION__,cmd->opcode, cmd->arg,mmc_hostname(host->mmc)); + MMC_DBG_INFO_FUNC("%d..%s start cmd=%d, arg=0x%x[%s]",__LINE__, __FUNCTION__,cmd->opcode, cmd->arg,mmc_hostname(host->mmc)); //dw_mci_regs_printk(host); mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START|SDMMC_CMD_USE_HOLD_REG); //always use SDMMC_CMD_USE_HOLD_REG @@ -731,8 +735,8 @@ static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data) host->dir_status = DW_MCI_SEND_STATUS; } - // MMC_DBG_CMD_FUNC(" cmd=%d(arg=0x%x),blocks=%d,blksz=%d [%s]",\ - // host->cmd->opcode, host->cmd->arg, data->blocks, data->blksz, mmc_hostname(host->mmc)); + MMC_DBG_INFO_FUNC(" dw_mci_submit_data,blocks=%d,blksz=%d [%s]",\ + data->blocks, data->blksz, mmc_hostname(host->mmc)); if (dw_mci_submit_data_dma(host, data)) { int flags = SG_MITER_ATOMIC; @@ -856,6 +860,28 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit) mci_writel(host, CTYPE, (slot->ctype << slot->id)); } +static void dw_mci_wait_unbusy(struct dw_mci *host) +{ + unsigned int timeout= SDMMC_DATA_TIMEOUT_SDIO; + unsigned long time_loop; + unsigned int status; + + MMC_DBG_INFO_FUNC("dw_mci_wait_unbusy, status=0x%x ", mci_readl(host, STATUS)); + + if(host->mmc->restrict_caps & RESTRICT_CARD_TYPE_EMMC) + timeout = SDMMC_DATA_TIMEOUT_EMMC; + else if(host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SD) + timeout = SDMMC_DATA_TIMEOUT_SD; + + time_loop = jiffies + msecs_to_jiffies(timeout); + do { + status = mci_readl(host, STATUS); + if (!(status & (SDMMC_STAUTS_DATA_BUSY|SDMMC_STAUTS_MC_BUSY))) + break; + //MMC_DBG_INFO_FUNC("dw_mci_wait_unbusy, waiting for......"); + } while (time_before(jiffies, time_loop)); +} + static void __dw_mci_start_request(struct dw_mci *host, struct dw_mci_slot *slot, struct mmc_command *cmd) @@ -870,7 +896,16 @@ static void __dw_mci_start_request(struct dw_mci *host, host->cur_slot = slot; host->mrq = mrq; - +#if 0 //add by xbw,at 2014-03-12 + /*clean FIFO if it is a new request*/ + if(!(mrq->cmd->opcode & SDMMC_CMD_STOP)) { + MMC_DBG_INFO_FUNC("%d..%s: reset the ctrl.", __LINE__, __FUNCTION__); + mci_writel(host, CTRL, (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | + SDMMC_CTRL_DMA_RESET)); + } + #endif + dw_mci_wait_unbusy(host); + host->pending_events = 0; host->completed_events = 0; host->data_status = 0; @@ -905,7 +940,7 @@ static void dw_mci_start_request(struct dw_mci *host, struct mmc_request *mrq = slot->mrq; struct mmc_command *cmd; - MMC_DBG_CMD_FUNC(" Begin to start the new request. cmd=%d(arg=0x%x)[%s]", \ + MMC_DBG_INFO_FUNC(" Begin to start the new request. cmd=%d(arg=0x%x)[%s]", \ mrq->cmd->opcode, mrq->cmd->arg, mmc_hostname(host->mmc)); cmd = mrq->sbc ? mrq->sbc : mrq->cmd; @@ -1057,7 +1092,7 @@ static int dw_mci_get_cd(struct mmc_host *mmc) struct dw_mci *host = slot->host; int gpio_cd = mmc_gpio_get_cd(mmc); - if (mmc->cardtype_restrict & RESTRICT_CARD_TYPE_SDIO){ + if (mmc->restrict_caps & RESTRICT_CARD_TYPE_SDIO){ spin_lock_bh(&host->lock); set_bit(DW_MMC_CARD_PRESENT, &slot->flags); spin_unlock_bh(&host->lock); @@ -1203,6 +1238,27 @@ static const struct mmc_host_ops dw_mci_ops = { .execute_tuning = dw_mci_execute_tuning, }; +static void dw_mci_deal_data_end(struct dw_mci *host, struct mmc_request *mrq) + __releases(&host->lock) + __acquires(&host->lock) +{ + if(DW_MCI_SEND_STATUS == host->dir_status){ + #if 0 + if( MMC_BUS_TEST_W != host->cmd->opcode){ + if(host->data_status & SDMMC_INT_DCRC) + host->data->error = -EILSEQ; + else if(host->data_status & SDMMC_INT_EBE) + host->data->error = -ETIMEDOUT; + } else { + dw_mci_wait_unbusy(host); + } + #else + dw_mci_wait_unbusy(host); + #endif + + } +} + static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq) __releases(&host->lock) __acquires(&host->lock) @@ -1211,6 +1267,8 @@ static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq) struct mmc_host *prev_mmc = host->cur_slot->mmc; WARN_ON(host->cmd || host->data); + + dw_mci_deal_data_end(host, mrq); if(mrq->cmd) MMC_DBG_CMD_FUNC(" reqeust end--reqeuest done, cmd=%d, cmderr=%d, host->state=%d [%s]",\ @@ -1254,14 +1312,14 @@ static void dw_mci_command_complete(struct dw_mci *host, struct mmc_command *cmd cmd->resp[1] = mci_readl(host, RESP2); cmd->resp[0] = mci_readl(host, RESP3); - MMC_DBG_CMD_FUNC(" command complete [%s], \ncmd=%d,resp[3]=0x%x, resp[2]=0x%x,resp[1]=0x%x,resp[0]=0x%x", \ + MMC_DBG_INFO_FUNC(" command complete [%s], \ncmd=%d,resp[3]=0x%x, resp[2]=0x%x,resp[1]=0x%x,resp[0]=0x%x", \ mmc_hostname(host->mmc), cmd->opcode,cmd->resp[3], cmd->resp[2], cmd->resp[1], cmd->resp[0]); } else { cmd->resp[0] = mci_readl(host, RESP0); cmd->resp[1] = 0; cmd->resp[2] = 0; cmd->resp[3] = 0; - MMC_DBG_CMD_FUNC(" command complete [%s], cmd=%d,resp[0]=0x%x",\ + MMC_DBG_INFO_FUNC(" command complete [%s], cmd=%d,resp[0]=0x%x",\ mmc_hostname(host->mmc),cmd->opcode, cmd->resp[0]); } } @@ -1277,6 +1335,9 @@ static void dw_mci_command_complete(struct dw_mci *host, struct mmc_command *cmd MMC_DBG_CMD_FUNC(" command complete, cmd=%d,cmdError=0x%x [%s]",cmd->opcode, cmd->error,mmc_hostname(host->mmc)); if (cmd->error) { + MMC_DBG_ERR_FUNC(" command complete, cmd=%d,cmdError=0x%x [%s]",\ + cmd->opcode, cmd->error,mmc_hostname(host->mmc)); + /* newer ip versions need a delay between retries */ if (host->quirks & DW_MCI_QUIRK_RETRY_DELAY) mdelay(20); @@ -1366,7 +1427,7 @@ static void dw_mci_tasklet_func(unsigned long priv) if (!test_and_clear_bit(EVENT_XFER_COMPLETE, &host->pending_events)) break; - MMC_DBG_CMD_FUNC("Pre-state[%d]-->NowState[%d]: STATE_SENDING_DATA, wait for EVENT_DATA_COMPLETE. [%s]",\ + MMC_DBG_INFO_FUNC("Pre-state[%d]-->NowState[%d]: STATE_SENDING_DATA, wait for EVENT_DATA_COMPLETE. [%s]",\ prev_state,state,mmc_hostname(host->mmc)); set_bit(EVENT_XFER_COMPLETE, &host->completed_events); @@ -1377,7 +1438,9 @@ static void dw_mci_tasklet_func(unsigned long priv) if (!test_and_clear_bit(EVENT_DATA_COMPLETE, &host->pending_events)) break; - MMC_DBG_CMD_FUNC("Pre-state[%d]-->NowState[%d]: STATE_DATA_BUSY, after EVENT_DATA_COMPLETE. [%s]", \ + + dw_mci_deal_data_end(host, host->mrq); + MMC_DBG_INFO_FUNC("Pre-state[%d]-->NowState[%d]: STATE_DATA_BUSY, after EVENT_DATA_COMPLETE. [%s]", \ prev_state,state,mmc_hostname(host->mmc)); host->data = NULL; @@ -1385,7 +1448,7 @@ static void dw_mci_tasklet_func(unsigned long priv) status = host->data_status; if (status & DW_MCI_DATA_ERROR_FLAGS) { - MMC_DBG_CMD_FUNC("Pre-state[%d]-->NowState[%d]: DW_MCI_DATA_ERROR_FLAGS, datastatus=0x%x [%s]",\ + MMC_DBG_ERR_FUNC("Pre-state[%d]-->NowState[%d]: DW_MCI_DATA_ERROR_FLAGS, datastatus=0x%x [%s]",\ prev_state,state,status, mmc_hostname(host->mmc)); if (status & SDMMC_INT_DRTO) { data->error = -ETIMEDOUT; @@ -1442,7 +1505,6 @@ static void dw_mci_tasklet_func(unsigned long priv) dw_mci_request_end(host, host->mrq); goto unlock; } - printk("%d..%s: ===test===\n", __LINE__, __FUNCTION__); prev_state = state = STATE_SENDING_STOP; if (!data->error) @@ -1451,7 +1513,6 @@ static void dw_mci_tasklet_func(unsigned long priv) if (data->stop && !data->error) { /* stop command for open-ended transfer*/ - printk("%d..%s: ===test===\n", __LINE__, __FUNCTION__); send_stop_abort(host, data); } #endif @@ -1963,6 +2024,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) if (pending & SDMMC_INT_DATA_OVER) { mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER); + MMC_DBG_CMD_FUNC("SDMMC_INT_DATA_OVER, INT-pending=0x%x. [%s]",pending,mmc_hostname(host->mmc)); if (!host->data_status) host->data_status = pending; smp_wmb(); @@ -1987,6 +2049,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) } if (pending & SDMMC_INT_CMD_DONE) { + MMC_DBG_CMD_FUNC("SDMMC_INT_CMD_DONE, INT-pending=0x%x. [%s]",pending,mmc_hostname(host->mmc)); mci_writel(host, RINTSTS, SDMMC_INT_CMD_DONE); dw_mci_cmd_interrupt(host, pending); } @@ -2319,11 +2382,11 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) #endif if (of_find_property(host->dev->of_node, "supports-sd", NULL)) - mmc->cardtype_restrict |= RESTRICT_CARD_TYPE_SD; + mmc->restrict_caps |= RESTRICT_CARD_TYPE_SD; if (of_find_property(host->dev->of_node, "supports-sdio", NULL)) - mmc->cardtype_restrict |= RESTRICT_CARD_TYPE_SDIO; + mmc->restrict_caps |= RESTRICT_CARD_TYPE_SDIO; if (of_find_property(host->dev->of_node, "supports-emmc", NULL)) - mmc->cardtype_restrict |= RESTRICT_CARD_TYPE_EMMC; + mmc->restrict_caps |= RESTRICT_CARD_TYPE_EMMC; if (host->pdata->get_ocr) mmc->ocr_avail = host->pdata->get_ocr(id); diff --git a/drivers/mmc/host/rk_sdmmc.h b/drivers/mmc/host/rk_sdmmc.h index 1b8b109f0b9d..7dd14b54aee9 100755 --- a/drivers/mmc/host/rk_sdmmc.h +++ b/drivers/mmc/host/rk_sdmmc.h @@ -184,6 +184,13 @@ static struct sdmmc_reg dw_mci_regs[] = #define SDMMC_CMD_INDX(n) ((n) & 0x1F) /* Status register defines */ #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) +#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 + /* FIFOTH register defines */ #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ ((r) & 0xFFF) << 16 | \ diff --git a/drivers/mmc/host/rk_sdmmc_of.c b/drivers/mmc/host/rk_sdmmc_of.c index 76543a4e1dda..1030668ce99e 100755 --- a/drivers/mmc/host/rk_sdmmc_of.c +++ b/drivers/mmc/host/rk_sdmmc_of.c @@ -1,3 +1,13 @@ +/* + * Synopsys DesignWare Multimedia Card Interface driver + * + * Copyright (C) 2014 Fuzhou Rockchip Electronics Co.Ltd. + * + * 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 "rk_sdmmc_of.h" @@ -8,7 +18,7 @@ static void rockchip_mmc_of_dump(struct rk_sdmmc_of *rk_mmc_property) { mmc_debug_level = MMC_DBG_ERROR;//MMC_DBG_ALL;//set the value refer to file rk_sdmmc_of.h - MMC_DBG_BOOT_FUNC("=========rockchip mmc dts dump info start== 2014-03-10 11:59 ======"); + MMC_DBG_BOOT_FUNC("=========rockchip mmc dts dump info start== 2014-03-12 14:23 ======"); /* MMC_DBG_BOOT_FUNC("mmc,caps: 0x%x",rk_mmc_property->mmc_caps); MMC_DBG_BOOT_FUNC("mmc,ocr: 0x%x",rk_mmc_property->mmc_ocr); diff --git a/drivers/mmc/host/rk_sdmmc_of.h b/drivers/mmc/host/rk_sdmmc_of.h index c666d45671eb..da7269f8cd25 100755 --- a/drivers/mmc/host/rk_sdmmc_of.h +++ b/drivers/mmc/host/rk_sdmmc_of.h @@ -1,3 +1,14 @@ +/* + * Synopsys DesignWare Multimedia Card Interface driver + * + * Copyright (C) 2014 Fuzhou Rockchip Electronics Co.Ltd. + * + * 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. + */ + #ifndef __RK_SDMMC_OF_H #define __RK_SDMMC_OF_H diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 59f8afd0b8ce..c882e0075cd1 100755 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -286,7 +286,7 @@ struct mmc_host { mmc_pm_flag_t pm_caps; /* supported pm features */ - u32 cardtype_restrict; /*restrict the SDMMC controller to support card type;1--SD card; 2--sdio; 4--eMMC */ + u32 restrict_caps; /*restrict the SDMMC controller to support card type;1--SD card; 2--sdio; 4--eMMC */ #define RESTRICT_CARD_TYPE_SD (1 << 0) /*noted by XBW, Rockchip Co.Ld*/ #define RESTRICT_CARD_TYPE_SDIO (1 << 1) #define RESTRICT_CARD_TYPE_EMMC (1 << 2) diff --git a/include/linux/mmc/rk_mmc.h b/include/linux/mmc/rk_mmc.h index c14510e37c90..fab2825da2f8 100755 --- a/include/linux/mmc/rk_mmc.h +++ b/include/linux/mmc/rk_mmc.h @@ -172,6 +172,7 @@ struct dw_mci { struct clk *ciu_clk; struct dw_mci_slot *slot[MAX_MCI_SLOTS]; struct mmc_host *mmc; + struct mmc_command *pre_cmd; /* FIFO push and pull */ int fifo_depth;