mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 19:30:30 +09:00
mmc: core: rk_sdmmc: prepare for next Soc(s)
Merge branch from develop-3.10-next into develop-3.10
This commit is contained in:
@@ -533,6 +533,13 @@ config MMC_DW_IDMAC
|
||||
Designware Mobile Storage IP block. This disables the external DMA
|
||||
interface.
|
||||
|
||||
config MMC_DW_EDMAC
|
||||
bool "External DMAC interface"
|
||||
depends on MMC_DW && MMC_DW_ROCKCHIP && (!MMC_DW_IDMAC)
|
||||
help
|
||||
This selects support for the external DMAC block outside the Synopsys
|
||||
Designware Mobile Storage IP block. This disables the internal DMA
|
||||
interface.
|
||||
config MMC_DW_PLTFM
|
||||
tristate "Synopsys Designware MCI Support as platform device"
|
||||
depends on MMC_DW
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/rockchip/cpu.h>
|
||||
#include <linux/rockchip/cru.h>
|
||||
|
||||
#include "rk_sdmmc.h"
|
||||
#include "dw_mmc-pltfm.h"
|
||||
@@ -31,7 +32,10 @@
|
||||
* sdmmc,sdio0,sdio1,emmc id=0~3
|
||||
* cclk_in_drv, cclk_in_sample i=0,1
|
||||
*/
|
||||
#define CRU_SDMMC_CON(id, tuning_type) (0x200 + ((id) * 8) + ((tuning_type) * 4))
|
||||
|
||||
static u32 cru_tuning_base = 0;
|
||||
|
||||
#define CRU_SDMMC_CON(id, tuning_type) (cru_tuning_base + ((id) * 8) + ((tuning_type) * 4))
|
||||
|
||||
#define MAX_DELAY_LINE (0xff)
|
||||
#define FREQ_REF_150MHZ (150000000)
|
||||
@@ -67,6 +71,7 @@ enum{
|
||||
enum dw_mci_rockchip_type {
|
||||
DW_MCI_TYPE_RK3188,
|
||||
DW_MCI_TYPE_RK3288,
|
||||
DW_MCI_TYPE_RK3036,
|
||||
};
|
||||
|
||||
/* Rockchip implementation specific driver private data */
|
||||
@@ -88,6 +93,9 @@ static struct dw_mci_rockchip_compatible {
|
||||
},{
|
||||
.compatible = "rockchip,rk32xx-sdmmc",
|
||||
.ctrl_type = DW_MCI_TYPE_RK3288,
|
||||
},{
|
||||
.compatible = "rockchip,rk3036-sdmmc",
|
||||
.ctrl_type = DW_MCI_TYPE_RK3036,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -97,14 +105,14 @@ static int dw_mci_rockchip_priv_init(struct dw_mci *host)
|
||||
int idx;
|
||||
|
||||
priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv) {
|
||||
if(!priv){
|
||||
dev_err(host->dev, "mem alloc failed for private data\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
for (idx = 0; idx < ARRAY_SIZE(rockchip_compat); idx++) {
|
||||
if (of_device_is_compatible(host->dev->of_node,
|
||||
rockchip_compat[idx].compatible))
|
||||
for(idx = 0; idx < ARRAY_SIZE(rockchip_compat); idx++){
|
||||
if(of_device_is_compatible(host->dev->of_node,
|
||||
rockchip_compat[idx].compatible))
|
||||
priv->ctrl_type = rockchip_compat[idx].ctrl_type;
|
||||
}
|
||||
|
||||
@@ -116,7 +124,8 @@ static int dw_mci_rockchip_setup_clock(struct dw_mci *host)
|
||||
{
|
||||
struct dw_mci_rockchip_priv_data *priv = host->priv;
|
||||
|
||||
if (priv->ctrl_type == DW_MCI_TYPE_RK3288)
|
||||
if ((priv->ctrl_type == DW_MCI_TYPE_RK3288) ||
|
||||
(priv->ctrl_type == DW_MCI_TYPE_RK3036))
|
||||
host->bus_hz /= (priv->ciu_div + 1);
|
||||
|
||||
return 0;
|
||||
@@ -124,8 +133,7 @@ static int dw_mci_rockchip_setup_clock(struct dw_mci *host)
|
||||
|
||||
static void dw_mci_rockchip_prepare_command(struct dw_mci *host, u32 *cmdr)
|
||||
{
|
||||
// if (SDMMC_CLKSEL_GET_DRV_WD3(mci_readl(host, CLKSEL)))
|
||||
// *cmdr |= SDMMC_CMD_USE_HOLD_REG;
|
||||
|
||||
}
|
||||
|
||||
static void dw_mci_rockchip_set_ios(struct dw_mci *host, struct mmc_ios *ios)
|
||||
@@ -210,9 +218,16 @@ static inline u8 dw_mci_rockchip_move_next_clksmpl(struct dw_mci *host, u8 con_i
|
||||
return val;
|
||||
}
|
||||
|
||||
static void dw_mci_rockchip_load_tuning_base(void)
|
||||
{
|
||||
if(cpu_is_rk3288())
|
||||
cru_tuning_base = RK3288_CRU_SDMMC_CON0;
|
||||
|
||||
|
||||
|
||||
/* Fixme: 3036
|
||||
else if(cpu_is_rk3036())
|
||||
cru_tuning_base = RK3036_CRU_SDMMC_CON0;
|
||||
*/
|
||||
}
|
||||
|
||||
static int inline __dw_mci_rockchip_execute_tuning(struct dw_mci_slot *slot, u32 opcode,
|
||||
u8 *blk_test, unsigned int blksz)
|
||||
@@ -273,7 +288,9 @@ static int dw_mci_rockchip_execute_tuning(struct dw_mci_slot *slot, u32 opcode,
|
||||
int ref = 0;
|
||||
unsigned int blksz = tuning_data->blksz;
|
||||
|
||||
MMC_DBG_INFO_FUNC(host->mmc,"execute tuning: [%s]", mmc_hostname(host->mmc));
|
||||
MMC_DBG_INFO_FUNC(host->mmc,"execute tuning: [%s]", mmc_hostname(host->mmc));
|
||||
|
||||
dw_mci_rockchip_load_tuning_base();
|
||||
|
||||
blk_test = kmalloc(blksz, GFP_KERNEL);
|
||||
if (!blk_test)
|
||||
@@ -293,6 +310,7 @@ static int dw_mci_rockchip_execute_tuning(struct dw_mci_slot *slot, u32 opcode,
|
||||
0.9 / 60ps = 15 delayline
|
||||
*/
|
||||
if(cpu_is_rk3288()){
|
||||
/* Fixme: 3036: dose it compatitable? */
|
||||
ref = ((FREQ_REF_150MHZ + host->bus_hz - 1) / host->bus_hz);
|
||||
step = (15 * ref);
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
@@ -450,27 +451,29 @@ static void dw_mci_idmac_stop_dma(struct dw_mci *host)
|
||||
mci_writel(host, BMOD, temp);
|
||||
}
|
||||
|
||||
static void dw_mci_idmac_complete_dma(struct dw_mci *host)
|
||||
static void dw_mci_idmac_complete_dma(void *arg)
|
||||
{
|
||||
struct mmc_data *data = host->data;
|
||||
struct dw_mci *host = arg;
|
||||
struct mmc_data *data = host->data;
|
||||
|
||||
dev_vdbg(host->dev, "DMA complete\n");
|
||||
dev_vdbg(host->dev, "DMA complete\n");
|
||||
|
||||
/*
|
||||
MMC_DBG_CMD_FUNC(host->mmc," DMA complete cmd=%d(arg=0x%x), blocks=%d,blksz=%d[%s]", \
|
||||
host->mrq->cmd->opcode,host->mrq->cmd->arg,data->blocks,data->blksz,mmc_hostname(host->mmc));
|
||||
*/
|
||||
|
||||
host->dma_ops->cleanup(host);
|
||||
/*
|
||||
MMC_DBG_CMD_FUNC(host->mmc," DMA complete cmd=%d(arg=0x%x), blocks=%d,blksz=%d[%s]", \
|
||||
host->mrq->cmd->opcode,host->mrq->cmd->arg,
|
||||
data->blocks,data->blksz,mmc_hostname(host->mmc));
|
||||
*/
|
||||
|
||||
host->dma_ops->cleanup(host);
|
||||
|
||||
/*
|
||||
* If the card was removed, data will be NULL. No point in trying to
|
||||
* send the stop command or waiting for NBUSY in this case.
|
||||
*/
|
||||
if (data) {
|
||||
set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
|
||||
tasklet_schedule(&host->tasklet);
|
||||
}
|
||||
if(data){
|
||||
set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
|
||||
tasklet_schedule(&host->tasklet);
|
||||
}
|
||||
}
|
||||
|
||||
static void dw_mci_translate_sglist(struct dw_mci *host, struct mmc_data *data,
|
||||
@@ -564,6 +567,151 @@ static const struct dw_mci_dma_ops dw_mci_idmac_ops = {
|
||||
};
|
||||
#endif /* CONFIG_MMC_DW_IDMAC */
|
||||
|
||||
#ifdef CONFIG_MMC_DW_EDMAC
|
||||
static void dw_mci_edma_cleanup(struct dw_mci *host)
|
||||
{
|
||||
struct mmc_data *data = host->data;
|
||||
|
||||
if (data)
|
||||
if (!data->host_cookie)
|
||||
dma_unmap_sg(host->dev,
|
||||
data->sg, data->sg_len,
|
||||
dw_mci_get_dma_dir(data));
|
||||
}
|
||||
|
||||
static void dw_mci_edmac_stop_dma(struct dw_mci *host)
|
||||
{
|
||||
dmaengine_terminate_all(host->dms->ch);
|
||||
}
|
||||
|
||||
static void dw_mci_edmac_complete_dma(void *arg)
|
||||
{
|
||||
struct dw_mci *host = arg;
|
||||
struct mmc_data *data = host->data;
|
||||
|
||||
dev_vdbg(host->dev, "DMA complete\n");
|
||||
|
||||
if(data->flags & MMC_DATA_READ)
|
||||
{
|
||||
/* Invalidate cache after read */
|
||||
dma_sync_sg_for_cpu(host->dms->ch->device->dev, data->sg,
|
||||
data->sg_len, DMA_FROM_DEVICE);
|
||||
}
|
||||
|
||||
host->dma_ops->cleanup(host);
|
||||
|
||||
/*
|
||||
* If the card was removed, data will be NULL. No point in trying to
|
||||
* send the stop command or waiting for NBUSY in this case.
|
||||
*/
|
||||
if (data) {
|
||||
set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
|
||||
tasklet_schedule(&host->tasklet);
|
||||
}
|
||||
}
|
||||
|
||||
static void dw_mci_edmac_start_dma(struct dw_mci *host, unsigned int sg_len)
|
||||
{
|
||||
struct dma_slave_config slave_config;
|
||||
struct dma_async_tx_descriptor *desc = NULL;
|
||||
struct scatterlist *sgl = host->data->sg;
|
||||
u32 sg_elems = host->data->sg_len;
|
||||
int ret = 0;
|
||||
|
||||
/* set external dma config: burst size, burst width*/
|
||||
if(host->data->flags & MMC_DATA_WRITE){
|
||||
slave_config.direction = DMA_MEM_TO_DEV;
|
||||
slave_config.dst_addr = (dma_addr_t)(host->regs + host->data_offset);
|
||||
slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
||||
//slave_config.dst_maxburst = 16;
|
||||
slave_config.dst_maxburst = ((host->fifoth_val) >> 28) && 0x7;
|
||||
|
||||
ret = dmaengine_slave_config(host->dms->ch, &slave_config);
|
||||
if (ret) {
|
||||
dev_err(host->dev, "error in dw_mci edma configuration.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
desc = dmaengine_prep_slave_sg(host->dms->ch, sgl, sg_len,
|
||||
DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||
if (!desc) {
|
||||
dev_err(host->dev, "We cannot prepare for the dw_mci slave edma!\n");
|
||||
return;
|
||||
}
|
||||
/* set dw_mci_edmac_complete_dma as callback */
|
||||
desc->callback = dw_mci_edmac_complete_dma;
|
||||
desc->callback_param = (void *)host;
|
||||
dmaengine_submit(desc);
|
||||
|
||||
/* Flush cache before write */
|
||||
dma_sync_sg_for_device(host->dms->ch->device->dev, sgl,
|
||||
sg_elems, DMA_TO_DEVICE);
|
||||
dma_async_issue_pending(host->dms->ch);
|
||||
}else{
|
||||
/* MMC_DATA_READ*/
|
||||
slave_config.direction = DMA_DEV_TO_MEM;
|
||||
slave_config.src_addr = (dma_addr_t)(host->regs + host->data_offset);
|
||||
slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
||||
//slave_config.src_maxburst = 16;
|
||||
slave_config.dst_maxburst = ((host->fifoth_val) >> 28) && 0x7;
|
||||
|
||||
ret = dmaengine_slave_config(host->dms->ch, &slave_config);
|
||||
if (ret) {
|
||||
dev_err(host->dev, "error in dw_mci edma configuration.\n");
|
||||
return;
|
||||
}
|
||||
desc = dmaengine_prep_slave_sg(host->dms->ch, sgl, sg_len,
|
||||
DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||
if (!desc) {
|
||||
dev_err(host->dev, "We cannot prepare for the dw_mci slave edma!\n");
|
||||
return;
|
||||
}
|
||||
/* set dw_mci_edmac_complete_dma as callback */
|
||||
desc->callback = dw_mci_edmac_complete_dma;
|
||||
desc->callback_param = (void *)host;
|
||||
dmaengine_submit(desc);
|
||||
dma_async_issue_pending(host->dms->ch);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int dw_mci_edmac_init(struct dw_mci *host)
|
||||
{
|
||||
MMC_DBG_BOOT_FUNC(host->mmc,"dw_mci_edmac_init: Soc is 0x%x [%s]\n",
|
||||
(unsigned int)(rockchip_soc_id & ROCKCHIP_CPU_MASK), mmc_hostname(host->mmc));
|
||||
|
||||
/* 1) request external dma channel, SHOULD decide chn in dts */
|
||||
host->dms->ch = dma_request_slave_channel(host->dev, "dw_mci");
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
static void dw_mci_edmac_exit(struct dw_mci *host)
|
||||
{
|
||||
dma_release_channel(host->dms->ch);
|
||||
}
|
||||
|
||||
static const struct dw_mci_dma_ops dw_mci_edmac_ops = {
|
||||
.init = dw_mci_edmac_init,
|
||||
.exit = dw_mci_edmac_exit,
|
||||
.start = dw_mci_edmac_start_dma,
|
||||
.stop = dw_mci_edmac_stop_dma,
|
||||
.complete = dw_mci_edmac_complete_dma,
|
||||
.cleanup = dw_mci_edma_cleanup,
|
||||
};
|
||||
#endif
|
||||
static int dw_mci_pre_dma_transfer(struct dw_mci *host,
|
||||
struct mmc_data *data,
|
||||
bool next)
|
||||
@@ -642,7 +790,7 @@ static void dw_mci_post_req(struct mmc_host *mmc,
|
||||
|
||||
static void dw_mci_adjust_fifoth(struct dw_mci *host, struct mmc_data *data)
|
||||
{
|
||||
#ifdef CONFIG_MMC_DW_IDMAC
|
||||
#if defined(CONFIG_MMC_DW_IDMAC) || defined(CONFIG_MMC_DW_EDMAC)
|
||||
unsigned int blksz = data->blksz;
|
||||
const u32 mszs[] = {1, 4, 8, 16, 32, 64, 128, 256};
|
||||
u32 fifo_width = 1 << host->data_shift;
|
||||
@@ -2593,7 +2741,8 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
|
||||
* is configured.
|
||||
*/
|
||||
if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) {
|
||||
if (!pending &&((mci_readl(host, STATUS) >> 17) & 0x1fff))
|
||||
if (!pending &&
|
||||
((mci_readl(host, STATUS) >> 17) & 0x1fff))
|
||||
pending |= SDMMC_INT_DATA_OVER;
|
||||
}
|
||||
|
||||
@@ -2695,7 +2844,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
|
||||
if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) {
|
||||
mci_writel(host, IDSTS, SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI);
|
||||
mci_writel(host, IDSTS, SDMMC_IDMAC_INT_NI);
|
||||
host->dma_ops->complete(host);
|
||||
host->dma_ops->complete((void *)host);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -3200,9 +3349,12 @@ static void dw_mci_init_dma(struct dw_mci *host)
|
||||
}
|
||||
|
||||
/* Determine which DMA interface to use */
|
||||
#ifdef CONFIG_MMC_DW_IDMAC
|
||||
#if defined(CONFIG_MMC_DW_IDMAC)
|
||||
host->dma_ops = &dw_mci_idmac_ops;
|
||||
dev_info(host->dev, "Using internal DMA controller.\n");
|
||||
#elif defined(CONFIG_MMC_DW_EDMAC)
|
||||
host->dma_ops = &dw_mci_edmac_ops;
|
||||
dev_info(host->dev, "Using external DMA controller.\n");
|
||||
#endif
|
||||
|
||||
if (!host->dma_ops)
|
||||
@@ -3672,36 +3824,38 @@ EXPORT_SYMBOL(dw_mci_probe);
|
||||
void dw_mci_remove(struct dw_mci *host)
|
||||
{
|
||||
int i;
|
||||
del_timer_sync(&host->dto_timer);
|
||||
|
||||
del_timer_sync(&host->dto_timer);
|
||||
mci_writel(host, RINTSTS, 0xFFFFFFFF);
|
||||
mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */
|
||||
if(host->use_dma && host->dma_ops->exit)
|
||||
host->dma_ops->exit(host);
|
||||
|
||||
for (i = 0; i < host->num_slots; i++) {
|
||||
dev_dbg(host->dev, "remove slot %d\n", i);
|
||||
if (host->slot[i])
|
||||
dw_mci_cleanup_slot(host->slot[i], i);
|
||||
}
|
||||
mci_writel(host, RINTSTS, 0xFFFFFFFF);
|
||||
mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */
|
||||
|
||||
/* disable clock to CIU */
|
||||
mci_writel(host, CLKENA, 0);
|
||||
mci_writel(host, CLKSRC, 0);
|
||||
for(i = 0; i < host->num_slots; i++){
|
||||
dev_dbg(host->dev, "remove slot %d\n", i);
|
||||
if(host->slot[i])
|
||||
dw_mci_cleanup_slot(host->slot[i], i);
|
||||
}
|
||||
|
||||
destroy_workqueue(host->card_workqueue);
|
||||
/* disable clock to CIU */
|
||||
mci_writel(host, CLKENA, 0);
|
||||
mci_writel(host, CLKSRC, 0);
|
||||
|
||||
if (host->use_dma && host->dma_ops->exit)
|
||||
host->dma_ops->exit(host);
|
||||
destroy_workqueue(host->card_workqueue);
|
||||
|
||||
if (host->vmmc){
|
||||
regulator_disable(host->vmmc);
|
||||
regulator_put(host->vmmc);
|
||||
}
|
||||
|
||||
if (!IS_ERR(host->clk_mmc))
|
||||
clk_disable_unprepare(host->clk_mmc);
|
||||
if(host->use_dma && host->dma_ops->exit)
|
||||
host->dma_ops->exit(host);
|
||||
|
||||
if (!IS_ERR(host->hclk_mmc))
|
||||
clk_disable_unprepare(host->hclk_mmc);
|
||||
if(host->vmmc){
|
||||
regulator_disable(host->vmmc);
|
||||
regulator_put(host->vmmc);
|
||||
}
|
||||
if(!IS_ERR(host->clk_mmc))
|
||||
clk_disable_unprepare(host->clk_mmc);
|
||||
|
||||
if(!IS_ERR(host->hclk_mmc))
|
||||
clk_disable_unprepare(host->hclk_mmc);
|
||||
}
|
||||
EXPORT_SYMBOL(dw_mci_remove);
|
||||
|
||||
@@ -3713,26 +3867,29 @@ EXPORT_SYMBOL(dw_mci_remove);
|
||||
*/
|
||||
int dw_mci_suspend(struct dw_mci *host)
|
||||
{
|
||||
|
||||
if (host->vmmc)
|
||||
regulator_disable(host->vmmc);
|
||||
if(host->vmmc)
|
||||
regulator_disable(host->vmmc);
|
||||
|
||||
/*only for sdmmc controller*/
|
||||
if(host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SD) {
|
||||
host->mmc->rescan_disable = 1;
|
||||
if (cancel_delayed_work_sync(&host->mmc->detect)){
|
||||
if(host->use_dma && host->dma_ops->exit)
|
||||
host->dma_ops->exit(host);
|
||||
|
||||
/*only for sdmmc controller*/
|
||||
if(host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SD){
|
||||
host->mmc->rescan_disable = 1;
|
||||
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)
|
||||
printk("%s: Warning : Idle pinctrl setting failed!\n", 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);
|
||||
}
|
||||
return 0;
|
||||
|
||||
disable_irq(host->irq);
|
||||
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);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(dw_mci_suspend);
|
||||
|
||||
@@ -3753,7 +3910,8 @@ int dw_mci_resume(struct dw_mci *host)
|
||||
disable_irq_wake(host->mmc->slot.cd_irq);
|
||||
mmc_gpio_free_cd(host->mmc);
|
||||
if(pinctrl_select_state(host->pinctrl, host->pins_default) < 0)
|
||||
printk("%s: Warning : Default pinctrl setting failed!\n", mmc_hostname(host->mmc));
|
||||
MMC_DBG_ERR_FUNC(host->mmc, "Default pinctrl setting failed! [%s]",
|
||||
mmc_hostname(host->mmc));
|
||||
host->mmc->rescan_disable = 0;
|
||||
if(cpu_is_rk3288()) {
|
||||
grf_writel(((1<<12)<<16)|(0<<12), RK3288_GRF_SOC_CON0);//disable jtag
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/mmc/core.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/timer.h>
|
||||
|
||||
#define MAX_MCI_SLOTS 2
|
||||
@@ -36,6 +37,11 @@ enum {
|
||||
EVENT_DATA_ERROR,
|
||||
EVENT_XFER_ERROR
|
||||
};
|
||||
struct dw_mci_dma_slave {
|
||||
struct dma_chan *ch;
|
||||
enum dma_transfer_direction direction;
|
||||
unsigned int dmach;
|
||||
};
|
||||
|
||||
struct mmc_data;
|
||||
|
||||
@@ -148,6 +154,10 @@ struct dw_mci {
|
||||
#else
|
||||
struct dw_mci_dma_data *dma_data;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MMC_DW_EDMAC
|
||||
struct dw_mci_dma_slave *dms;
|
||||
#endif
|
||||
u32 cmd_status;
|
||||
u32 data_status;
|
||||
u32 stop_cmdr;
|
||||
@@ -176,9 +186,10 @@ struct dw_mci {
|
||||
struct dw_mci_slot *slot[MAX_MCI_SLOTS];
|
||||
struct mmc_host *mmc;
|
||||
struct mmc_command *pre_cmd;
|
||||
unsigned int hold_reg_flag;//to fix the hold_reg value
|
||||
|
||||
struct timer_list dto_timer; //the timer for INT_DTO
|
||||
/* Fix the hold_reg value */
|
||||
unsigned int hold_reg_flag;
|
||||
/* Timer for INT_DTO */
|
||||
struct timer_list dto_timer;
|
||||
/* FIFO push and pull */
|
||||
int fifo_depth;
|
||||
int data_shift;
|
||||
@@ -211,7 +222,7 @@ struct dw_mci_dma_ops {
|
||||
/* DMA Ops */
|
||||
int (*init)(struct dw_mci *host);
|
||||
void (*start)(struct dw_mci *host, unsigned int sg_len);
|
||||
void (*complete)(struct dw_mci *host);
|
||||
void (*complete)(void *host);
|
||||
void (*stop)(struct dw_mci *host);
|
||||
void (*cleanup)(struct dw_mci *host);
|
||||
void (*exit)(struct dw_mci *host);
|
||||
|
||||
Reference in New Issue
Block a user