mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-10 12:57:06 +09:00
SDMMC: eMMC OK. It is good to run correctly from emmc
This commit is contained in:
@@ -83,7 +83,7 @@
|
||||
|
||||
|
||||
sdio: rksdmmc@10218000 {
|
||||
compatible = "rockchip,rk_mmc";
|
||||
compatible = "rockchip,rk_mmc";
|
||||
reg = <0x10218000 0x4000>;
|
||||
interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
|
||||
#address-cells = <1>;
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
|
||||
#include "rk3188.dtsi"
|
||||
#include "rk3188-clocks.dtsi"
|
||||
#include "lcd-b101ew05.dtsi"
|
||||
#include "rk3188-mmc.dtsi"
|
||||
#include <dt-bindings/clock/ddr.h>
|
||||
|
||||
#include "rk3188-mmc.dtsi"
|
||||
#include "lcd-b101ew05.dtsi"
|
||||
|
||||
/ {
|
||||
memory {
|
||||
device_type = "memory";
|
||||
|
||||
5
drivers/mmc/host/dw_mmc-pltfm.c
Normal file → Executable file
5
drivers/mmc/host/dw_mmc-pltfm.c
Normal file → Executable file
@@ -19,10 +19,11 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mmc/host.h>
|
||||
#include <linux/mmc/mmc.h>
|
||||
#include <linux/mmc/dw_mmc.h>
|
||||
#include <linux/mmc/rk_mmc.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
@@ -870,7 +896,16 @@ static void __dw_mci_start_request(struct dw_mci *host,
|
||||
host->pdata->select_slot(slot->id);
|
||||
|
||||
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;
|
||||
@@ -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));
|
||||
|
||||
@@ -1057,7 +1092,7 @@ static int dw_mci_get_cd(struct mmc_host *mmc)
|
||||
struct dw_mci_board *brd = slot->host->pdata;
|
||||
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);
|
||||
@@ -1203,6 +1238,27 @@ static const struct mmc_host_ops dw_mci_ops = {
|
||||
.enable_sdio_irq = dw_mci_enable_sdio_irq,
|
||||
.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)
|
||||
@@ -1211,6 +1267,8 @@ static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq)
|
||||
struct dw_mci_slot *slot;
|
||||
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)
|
||||
@@ -1254,14 +1312,14 @@ static void dw_mci_command_complete(struct dw_mci *host, struct mmc_command *cmd
|
||||
cmd->resp[2] = mci_readl(host, RESP1);
|
||||
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;
|
||||
MMC_DBG_CMD_FUNC(" command complete [%s], cmd=%d,resp[0]=0x%x",\
|
||||
cmd->resp[3] = 0;
|
||||
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
|
||||
cmd->error = 0;
|
||||
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)
|
||||
@@ -1366,7 +1427,7 @@ static void dw_mci_tasklet_func(unsigned long priv)
|
||||
|
||||
if (!test_and_clear_bit(EVENT_XFER_COMPLETE,
|
||||
&host->pending_events))
|
||||
MMC_DBG_CMD_FUNC("Pre-state[%d]-->NowState[%d]: STATE_SENDING_DATA, wait for EVENT_DATA_COMPLETE. [%s]",\
|
||||
break;
|
||||
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));
|
||||
|
||||
@@ -1377,7 +1438,9 @@ static void dw_mci_tasklet_func(unsigned long priv)
|
||||
case STATE_DATA_BUSY:
|
||||
if (!test_and_clear_bit(EVENT_DATA_COMPLETE,
|
||||
&host->pending_events))
|
||||
MMC_DBG_CMD_FUNC("Pre-state[%d]-->NowState[%d]: STATE_DATA_BUSY, after EVENT_DATA_COMPLETE. [%s]", \
|
||||
break;
|
||||
|
||||
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));
|
||||
|
||||
@@ -1385,7 +1448,7 @@ static void dw_mci_tasklet_func(unsigned long priv)
|
||||
set_bit(EVENT_DATA_COMPLETE, &host->completed_events);
|
||||
status = host->data_status;
|
||||
|
||||
MMC_DBG_CMD_FUNC("Pre-state[%d]-->NowState[%d]: DW_MCI_DATA_ERROR_FLAGS, datastatus=0x%x [%s]",\
|
||||
if (status & DW_MCI_DATA_ERROR_FLAGS) {
|
||||
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) {
|
||||
@@ -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;
|
||||
@@ -1451,7 +1513,6 @@ static void dw_mci_tasklet_func(unsigned long priv)
|
||||
#if 0
|
||||
if (data->stop && !data->error) {
|
||||
/* stop command for open-ended transfer*/
|
||||
printk("%d..%s: ===test===\n", __LINE__, __FUNCTION__);
|
||||
|
||||
send_stop_abort(host, data);
|
||||
}
|
||||
@@ -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;
|
||||
@@ -1987,6 +2049,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
|
||||
dw_mci_write_data_pio(host);
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
mmc->cardtype_restrict |= RESTRICT_CARD_TYPE_SD;
|
||||
if (of_find_property(host->dev->of_node, "supports-sd", NULL))
|
||||
mmc->restrict_caps |= RESTRICT_CARD_TYPE_SD;
|
||||
mmc->cardtype_restrict |= RESTRICT_CARD_TYPE_SDIO;
|
||||
if (of_find_property(host->dev->of_node, "supports-sdio", NULL))
|
||||
mmc->restrict_caps |= RESTRICT_CARD_TYPE_SDIO;
|
||||
mmc->cardtype_restrict |= RESTRICT_CARD_TYPE_EMMC;
|
||||
if (of_find_property(host->dev->of_node, "supports-emmc", NULL))
|
||||
mmc->restrict_caps |= RESTRICT_CARD_TYPE_EMMC;
|
||||
|
||||
if (host->pdata->get_ocr)
|
||||
|
||||
@@ -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 | \
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user