#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/sd.h>
+#include <linux/mmc/card.h>
#include <linux/mmc/sdio.h>
#include <linux/mmc/rk_mmc.h>
#include <linux/bitops.h>
#include <linux/regulator/rockchip_io_vol_domain.h>
#include "../../clk/rockchip/clk-ops.h"
-#define RK_SDMMC_DRIVER_VERSION "Ver 1.12 2014-07-08"
+#define RK_SDMMC_DRIVER_VERSION "Ver 1.13 2014-09-05"
/* Common flag combinations */
#define DW_MCI_DATA_ERROR_FLAGS (SDMMC_INT_DRTO | SDMMC_INT_DCRC | \
static int dw_mci_edmac_init(struct dw_mci *host)
{
- /* 1) request external dma channel, SHOULD decide chn in dts */
- host->dms = (struct dw_mci_dma_slave *)kmalloc(sizeof(struct dw_mci_dma_slave),GFP_KERNEL);
+ /* Request external dma channel, SHOULD decide chn in dts */
+ host->dms = NULL;
+ host->dms = (struct dw_mci_dma_slave *)kmalloc
+ (sizeof(struct dw_mci_dma_slave), GFP_KERNEL);
+ if (NULL == host->dms) {
+ dev_err(host->dev, "No enough memory to alloc dms.\n");
+ goto err_exit;
+ }
+
host->dms->ch = dma_request_slave_channel(host->dev, "dw_mci");
- if (!host->dms->ch){
+ if (!host->dms->ch) {
dev_err(host->dev, "Failed to get external DMA channel: channel id = %d\n",
host->dms->ch->chan_id);
goto err_exit;
}
- /* anything? */
-
return 0;
err_exit:
- return -ENODEV;
+ if (NULL != host->dms) {
+ kfree(host->dms);
+ host->dms = NULL;
+ }
+ return -ENXIO;
}
static void dw_mci_edmac_exit(struct dw_mci *host)
{
- dma_release_channel(host->dms->ch);
+ if (NULL != host->dms) {
+ if (NULL != host->dms->ch) {
+ dma_release_channel(host->dms->ch);
+ host->dms->ch = NULL;
+ }
+ kfree(host->dms);
+ host->dms = NULL;
+ }
}
static const struct dw_mci_dma_ops dw_mci_edmac_ops = {
mmcblk0: retrying using single block read
mmcblk0: error -110 sending status command, retrying
- How to: If eMMC HW version < 4.51, or > 4.51 but no caps2-mmc-hs200 support in dts
- Please set dts emmc clk to 100M or 150M, I will workaround it!
+ We assume all eMMC in RK platform with 3.10 kernel, at least version 4.5
*/
+ if ((div == 0) &&
+ (host->mmc->caps & (MMC_CAP_1_8V_DDR | MMC_CAP_1_2V_DDR)) &&
+ !(host->mmc->caps2 & MMC_CAP2_HS200)) {
+ /* Fixup DDR MMC */
+ div = 1;
+ host->set_div = div;
+ host->bus_hz = host->set_speed * 2;
+ MMC_DBG_BOOT_FUNC(host->mmc,
+ "dw_mci_setup_bus: workaround div = %d, host->bus_hz = %d [%s]",
+ div, host->bus_hz, mmc_hostname(host->mmc));
+ }
if (host->verid < DW_MMC_240A)
clk_set_rate(host->clk_mmc,(host->bus_hz));
mci_writel(host, CTYPE, (slot->ctype << slot->id));
}
+extern struct mmc_card *this_card;
static void dw_mci_wait_unbusy(struct dw_mci *host)
{
- unsigned int timeout= SDMMC_DATA_TIMEOUT_SDIO;
- unsigned long time_loop;
- unsigned int status;
+ unsigned int timeout= SDMMC_DATA_TIMEOUT_SDIO;
+ unsigned long time_loop;
+ unsigned int status;
+ u32 se_flag = 0;
- MMC_DBG_INFO_FUNC(host->mmc, "dw_mci_wait_unbusy, status=0x%x ", mci_readl(host, STATUS));
+ MMC_DBG_INFO_FUNC(host->mmc, "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;
+ if (host->mmc->restrict_caps & RESTRICT_CARD_TYPE_EMMC) {
+ if (host->cmd && (host->cmd->opcode == MMC_ERASE)) {
+ /* Special care for (secure)erase timeout calculation */
+ if(this_card){
+ if((host->cmd->arg & (0x1 << 31)) == 1) /* secure erase */
+ se_flag = 0x1;
+
+ if (((this_card->ext_csd.erase_group_def) & 0x1) == 1) ;
+ se_flag ? (timeout = (this_card->ext_csd.hc_erase_timeout) *
+ 300000 * (this_card->ext_csd.sec_erase_mult)) :
+ (timeout = (this_card->ext_csd.hc_erase_timeout) * 300000);
+ }
+ }
- time_loop = jiffies + msecs_to_jiffies(timeout);
- do {
- status = mci_readl(host, STATUS);
- if (!(status & (SDMMC_STAUTS_DATA_BUSY | SDMMC_STAUTS_MC_BUSY)))
- break;
- } while (time_before(jiffies, time_loop));
+ if(timeout < SDMMC_DATA_TIMEOUT_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;
+ } while (time_before(jiffies, time_loop));
}
+
#ifdef CONFIG_MMC_DW_ROCKCHIP_SWITCH_VOLTAGE
/*
* result:
static int dw_mci_get_cd(struct mmc_host *mmc)
{
- int present;
- struct dw_mci_slot *slot = mmc_priv(mmc);
- struct dw_mci_board *brd = slot->host->pdata;
- struct dw_mci *host = slot->host;
- int gpio_cd = mmc_gpio_get_cd(mmc);
-
+ int present;
+ struct dw_mci_slot *slot = mmc_priv(mmc);
+ struct dw_mci_board *brd = slot->host->pdata;
+ struct dw_mci *host = slot->host;
+ int gpio_cd = mmc_gpio_get_cd(mmc);
+ int gpio_val;
+
+ if (cpu_is_rk312x() &&
+ soc_is_rk3126() &&
+ (mmc->restrict_caps & RESTRICT_CARD_TYPE_SD)) {
+ gpio_cd = slot->cd_gpio;
+ if (gpio_is_valid(gpio_cd)) {
+ gpio_val = gpio_get_value_cansleep(gpio_cd);
+ msleep(10);
+ if (gpio_val == gpio_get_value_cansleep(gpio_cd)) {
+ gpio_cd = gpio_get_value_cansleep(gpio_cd) == 0 ? 1 : 0;
+ if (gpio_cd == 0) {
+ /* Enable force_jtag wihtout card in slot, ONLY for NCD-package */
+ grf_writel((0x1 << 24) | (1 << 8), RK312X_GRF_SOC_CON0);
+ dw_mci_ctrl_all_reset(host);
+ } else {
+ /* Really card detected: SHOULD disable force_jtag */
+ grf_writel((0x1 << 24) | (0 << 8), RK312X_GRF_SOC_CON0);
+ }
+ } else {
+ /* Jitter */
+ return slot->last_detect_state;
+ }
+ } else {
+ dev_err(host->dev, "dw_mci_get_cd: invalid gpio_cd!\n");
+ }
+ }
+
if (mmc->restrict_caps & RESTRICT_CARD_TYPE_SDIO)
return test_bit(DW_MMC_CARD_PRESENT, &slot->flags);
else
present = (mci_readl(slot->host, CDETECT) & (1 << slot->id))
== 0 ? 1 : 0;
+
spin_lock_bh(&host->lock);
if (present) {
set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
{
struct dw_mci_slot *slot = mmc_priv(mmc);
struct dw_mci *host = slot->host;
+ //unsigned long flags;
u32 int_mask;
u32 sdio_int;
+ //spin_lock_irqsave(&host->lock, flags);
+
/* Enable/disable Slot Specific SDIO interrupt */
int_mask = mci_readl(host, INTMASK);
mci_writel(host, INTMASK,
(int_mask & ~sdio_int));
}
+
+ //spin_unlock_irqrestore(&host->lock, flags);
}
#ifdef CONFIG_MMC_DW_ROCKCHIP_SWITCH_VOLTAGE
struct dw_mci_tuning_data tuning_data;
int err = -ENOSYS;
- /* Fixme: 3036/3126 doesn't support 1.8 io domain, no sense exe tuning
- if(cpu_is_3036() || cpu_is_3126())
- return ENOSYS;
- AND
- what about audi-b?
- */
+ /* Fixme: 3036/3126 doesn't support 1.8 io domain, no sense exe tuning */
+ if(cpu_is_rk3036() || cpu_is_rk312x())
+ return err;
if (opcode == MMC_SEND_TUNING_BLOCK_HS200) {
if (mmc->ios.bus_width == MMC_BUS_WIDTH_8) {
del_timer_sync(&host->dto_timer);
if(MMC_SEND_STATUS != cmd->opcode)
if(host->cmd_rto >= SDMMC_CMD_RTO_MAX_HOLD){
- MMC_DBG_ERR_FUNC(host->mmc, " command complete, cmd=%d,cmdError=%d [%s]",\
+ MMC_DBG_CMD_FUNC(host->mmc, " command complete, cmd=%d,cmdError=%d [%s]",\
cmd->opcode, cmd->error,mmc_hostname(host->mmc));
host->cmd_rto = 0;
}
static void dw_mci_cmd_interrupt(struct dw_mci *host, u32 status)
{
- u32 multi, unit;
+ u32 multi, unit = SZ_2M;
if (!host->cmd_status)
host->cmd_status = status;
- if(!host->cmd)
+ if (!host->cmd)
goto cmd_exit;
- if((MMC_STOP_TRANSMISSION != host->cmd->opcode))
- {
- unit = 2*1024*1024;
- multi = mci_readl(host, BYTCNT)/unit;
- multi += ((mci_readl(host, 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(4500 * multi));//max wait 8s larger
+ if ((MMC_STOP_TRANSMISSION != host->cmd->opcode)) {
+ multi = (mci_readl(host, BYTCNT) / unit) +
+ ((mci_readl(host, BYTCNT) % unit) ? 1 :0 ) +
+ ((host->cmd->retries > 2) ? 2 : host->cmd->retries);
+ /* Max limit time: 8s for dto */
+ mod_timer(&host->dto_timer, jiffies + msecs_to_jiffies(4000 * multi));
}
cmd_exit:
#ifdef CONFIG_MMC_DW_IDMAC
/* External DMA Soc platform NOT need to ack interrupt IDSTS */
- if(!cpu_is_rk3036()){
+ if(!(cpu_is_rk3036() || cpu_is_rk312x())){
/* Handle DMA interrupts */
pending = mci_readl(host, IDSTS);
if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) {
/* Clear down the FIFO */
dw_mci_fifo_reset(host);
#ifdef CONFIG_MMC_DW_IDMAC
- if(!cpu_is_rk3036())
+ if(!(cpu_is_rk3036() || cpu_is_rk312x()))
dw_mci_idmac_reset(host);
#endif
if (mmc_gpio_request_cd(mmc, gpio, 0))
dev_warn(dev, "gpio [%d] request failed\n", gpio);
}
+
+static irqreturn_t dw_mci_gpio_cd_irqt(int irq, void *dev_id)
+{
+ struct mmc_host *mmc = dev_id;
+ struct dw_mci_slot *slot = mmc_priv(mmc);
+ struct dw_mci *host = slot->host;
+
+ #if 0
+ if (mmc->ops->card_event)
+ mmc->ops->card_event(mmc);
+
+ mmc_detect_change(mmc, msecs_to_jiffies(200));
+ #endif
+
+ queue_work(host->card_workqueue, &host->card_work);
+ return IRQ_HANDLED;
+}
+
+static void dw_mci_of_set_cd_gpio_irq(struct device *dev, u32 gpio,
+ struct mmc_host *mmc)
+{
+ struct dw_mci_slot *slot = mmc_priv(mmc);
+ struct dw_mci *host = slot->host;
+ int irq;
+ int ret;
+
+ /* Having a missing entry is valid; return silently */
+ if (!gpio_is_valid(gpio))
+ return;
+
+ irq = gpio_to_irq(gpio);
+ if (irq >= 0) {
+ ret = devm_request_threaded_irq(&mmc->class_dev, irq,
+ NULL, dw_mci_gpio_cd_irqt,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ "dw_mci_cd", mmc);
+ if (ret < 0) {
+ irq = ret;
+ dev_err(host->dev, "Request cd-gpio %d interrupt error!\n", gpio);
+ } else{
+ /* enable wakeup event for gpio-cd in idle or deep suspend*/
+ enable_irq_wake(irq);
+ }
+ } else {
+ dev_err(host->dev, "Cannot convert gpio %d to irq!\n", gpio);
+ }
+}
+
+static void dw_mci_of_free_cd_gpio_irq(struct device *dev, u32 gpio,
+ struct mmc_host *mmc)
+{
+ if (!gpio_is_valid(gpio))
+ return;
+
+ if (gpio_to_irq(gpio) >= 0) {
+ devm_free_irq(&mmc->class_dev, gpio_to_irq(gpio), mmc);
+ devm_gpio_free(&mmc->class_dev, gpio);
+ }
+}
#else /* CONFIG_OF */
static int dw_mci_of_get_slot_quirks(struct device *dev, u8 slot)
{
mmc->f_min = DW_MCI_FREQ_MIN;
mmc->f_max = DW_MCI_FREQ_MAX;
- printk("%d..%s: fmin=%d, fmax=%d [%s]\n", __LINE__,__FUNCTION__,
- mmc->f_min, mmc->f_max, mmc_hostname(mmc));
+ printk("%d..%s: fmin=%d, fmax=%d [%s]\n", __LINE__, __FUNCTION__,
+ mmc->f_min, mmc->f_max, mmc_hostname(mmc));
} else {
mmc->f_min = freq[0];
mmc->f_max = freq[1];
- printk("%d..%s: fmin=%d, fmax=%d [%s]\n", __LINE__,__FUNCTION__,
- mmc->f_min, mmc->f_max, mmc_hostname(mmc));
+ printk("%d..%s: fmin=%d, fmax=%d [%s]\n", __LINE__, __FUNCTION__,
+ mmc->f_min, mmc->f_max, mmc_hostname(mmc));
}
-
- if(strstr("mmc0",mmc_hostname(mmc)))
- printk("Line%d..%s: The rk_sdmmc %s",__LINE__, __FUNCTION__,RK_SDMMC_DRIVER_VERSION);
+
+ printk("%s : Rockchip specific MHSC: %s\n", mmc_hostname(mmc), RK_SDMMC_DRIVER_VERSION);
if (of_find_property(host->dev->of_node, "supports-sd", NULL))
mmc->restrict_caps |= RESTRICT_CARD_TYPE_SD;
mmc->restrict_caps |= RESTRICT_CARD_TYPE_SDIO;
if (of_find_property(host->dev->of_node, "supports-emmc", NULL))
mmc->restrict_caps |= RESTRICT_CARD_TYPE_EMMC;
+ /* Fixup for tSD */
+ if (of_find_property(host->dev->of_node, "supports-tSD", NULL))
+ mmc->restrict_caps |= RESTRICT_CARD_TYPE_TSD;
+
+
+ /* We assume only low-level chip use gpio_cd */
+ if (cpu_is_rk312x() &&
+ soc_is_rk3126() &&
+ (host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SD)) {
+ slot->cd_gpio = of_get_named_gpio(host->dev->of_node, "cd-gpios", 0);
+ if (gpio_is_valid(slot->cd_gpio)) {
+ /* Request gpio int for card detection */
+ dw_mci_of_set_cd_gpio_irq(host->dev, slot->cd_gpio,host->mmc);
+ } else {
+ slot->cd_gpio = -ENODEV;
+ dev_err(host->dev, "failed to get your cd-gpios!\n");
+ }
+ }
if (host->pdata->get_ocr)
mmc->ocr_avail = host->pdata->get_ocr(id);
mmc->max_blk_count = host->ring_size;
mmc->max_seg_size = 0x1000;
mmc->max_req_size = mmc->max_seg_size * mmc->max_blk_count;
- if(cpu_is_rk3036()){
+ if(cpu_is_rk3036() || cpu_is_rk312x()){
/* fixup for external dmac setting */
mmc->max_segs = 64;
mmc->max_blk_size = 65536; /* BLKSIZ is 16 bits */
- mmc->max_blk_count = 512;
+ 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;
}
return 0;
err_setup_bus:
+ if (gpio_is_valid(slot->cd_gpio))
+ dw_mci_of_free_cd_gpio_irq(host->dev, slot->cd_gpio,host->mmc);
mmc_free_host(mmc);
return -EINVAL;
}
/* Determine which DMA interface to use */
#if defined(CONFIG_MMC_DW_IDMAC)
- if(cpu_is_rk3036()){
+ if(cpu_is_rk3036() || cpu_is_rk312x()){
host->dma_ops = &dw_mci_edmac_ops;
dev_info(host->dev, "Using external DMA controller.\n");
}else{
/* NO requirement to reclaim slave chn using external dmac */
#ifdef CONFIG_MMC_DW_IDMAC
- if(!cpu_is_rk3036())
+ if(!(cpu_is_rk3036() || cpu_is_rk312x()))
if (host->use_dma && host->dma_ops->init)
host->dma_ops->init(host);
#endif
void dw_mci_remove(struct dw_mci *host)
{
+ struct mmc_host *mmc = host->mmc;
+ struct dw_mci_slot *slot = mmc_priv(mmc);
int i;
+
del_timer_sync(&host->dto_timer);
mci_writel(host, RINTSTS, 0xFFFFFFFF);
if(host->use_dma && host->dma_ops->exit)
host->dma_ops->exit(host);
+ if (gpio_is_valid(slot->cd_gpio))
+ dw_mci_of_free_cd_gpio_irq(host->dev, slot->cd_gpio, host->mmc);
+
if(host->vmmc){
regulator_disable(host->vmmc);
regulator_put(host->vmmc);
host->dma_ops->exit(host);
/*only for sdmmc controller*/
- if(host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SD){
+ if (host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SD) {
host->mmc->rescan_disable = 1;
- if(cancel_delayed_work_sync(&host->mmc->detect))
+ if (cancel_delayed_work_sync(&host->mmc->detect))
wake_unlock(&host->mmc->detect_wake_lock);
disable_irq(host->irq);
- if(pinctrl_select_state(host->pinctrl, host->pins_idle) < 0)
+ if (pinctrl_select_state(host->pinctrl, host->pins_idle) < 0)
MMC_DBG_ERR_FUNC(host->mmc, "Idle pinctrl setting failed! [%s]",
mmc_hostname(host->mmc));
- dw_mci_of_get_cd_gpio(host->dev,0,host->mmc);
+
mci_writel(host, RINTSTS, 0xFFFFFFFF);
mci_writel(host, INTMASK, 0x00);
mci_writel(host, CTRL, 0x00);
- enable_irq_wake(host->mmc->slot.cd_irq);
+
+ /* Soc rk3126 already in gpio_cd mode */
+ if (!(cpu_is_rk312x() && soc_is_rk3126())) {
+ dw_mci_of_get_cd_gpio(host->dev, 0, host->mmc);
+ enable_irq_wake(host->mmc->slot.cd_irq);
+ }
}
return 0;
}
}
/*only for sdmmc controller*/
if(host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SD) {
- disable_irq_wake(host->mmc->slot.cd_irq);
- mmc_gpio_free_cd(host->mmc);
+ /* Soc rk3126 already in gpio_cd mode */
+ if (!(cpu_is_rk312x() && soc_is_rk3126())) {
+ disable_irq_wake(host->mmc->slot.cd_irq);
+ mmc_gpio_free_cd(host->mmc);
+ }
if(pinctrl_select_state(host->pinctrl, host->pins_default) < 0)
MMC_DBG_ERR_FUNC(host->mmc, "Default pinctrl setting failed! [%s]",
mmc_hostname(host->mmc));
/* Disable jtag*/
if(cpu_is_rk3288())
grf_writel(((1 << 12) << 16) | (0 << 12), RK3288_GRF_SOC_CON0);
- /*
else if(cpu_is_rk3036())
grf_writel(((1 << 11) << 16) | (0 << 11), RK3036_GRF_SOC_CON0);
- else if(cpu_is_rk3126())
- TODO;
- else if audi-b
- TODO;
- */
+ else if(cpu_is_rk312x())
+ /* RK3036_GRF_SOC_CON0 is compatible with rk312x, tmp setting */
+ grf_writel(((1 << 8) << 16) | (0 << 8), RK3036_GRF_SOC_CON0);
}
if(host->vmmc){
ret = regulator_enable(host->vmmc);