2011-03-23 18:42:44 +07:00
|
|
|
/*
|
|
|
|
* linux/drivers/mmc/host/tmio_mmc.h
|
|
|
|
*
|
2016-04-26 22:55:26 +07:00
|
|
|
* Copyright (C) 2016 Sang Engineering, Wolfram Sang
|
|
|
|
* Copyright (C) 2015-16 Renesas Electronics Corporation
|
2011-03-23 18:42:44 +07:00
|
|
|
* Copyright (C) 2007 Ian Molton
|
|
|
|
* Copyright (C) 2004 Ian Molton
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
|
|
* published by the Free Software Foundation.
|
|
|
|
*
|
|
|
|
* Driver for the MMC / SD / SDIO cell found in:
|
|
|
|
*
|
|
|
|
* TC6393XB TC6391XB TC6387XB T7L66XB ASIC3
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef TMIO_MMC_H
|
|
|
|
#define TMIO_MMC_H
|
|
|
|
|
2015-01-13 11:59:14 +07:00
|
|
|
#include <linux/dmaengine.h>
|
2011-03-23 18:42:44 +07:00
|
|
|
#include <linux/highmem.h>
|
2011-07-14 17:12:38 +07:00
|
|
|
#include <linux/mutex.h>
|
2011-03-23 18:42:44 +07:00
|
|
|
#include <linux/pagemap.h>
|
2011-07-27 01:50:23 +07:00
|
|
|
#include <linux/scatterlist.h>
|
2012-01-06 19:06:51 +07:00
|
|
|
#include <linux/spinlock.h>
|
2016-12-30 19:47:23 +07:00
|
|
|
#include <linux/interrupt.h>
|
2011-03-23 18:42:44 +07:00
|
|
|
|
2016-04-26 22:55:26 +07:00
|
|
|
#define CTL_SD_CMD 0x00
|
|
|
|
#define CTL_ARG_REG 0x04
|
|
|
|
#define CTL_STOP_INTERNAL_ACTION 0x08
|
|
|
|
#define CTL_XFER_BLK_COUNT 0xa
|
|
|
|
#define CTL_RESPONSE 0x0c
|
2016-04-27 23:51:27 +07:00
|
|
|
/* driver merges STATUS and following STATUS2 */
|
2016-04-26 22:55:26 +07:00
|
|
|
#define CTL_STATUS 0x1c
|
2016-04-27 23:51:27 +07:00
|
|
|
/* driver merges IRQ_MASK and following IRQ_MASK2 */
|
2016-04-26 22:55:26 +07:00
|
|
|
#define CTL_IRQ_MASK 0x20
|
|
|
|
#define CTL_SD_CARD_CLK_CTL 0x24
|
|
|
|
#define CTL_SD_XFER_LEN 0x26
|
|
|
|
#define CTL_SD_MEM_CARD_OPT 0x28
|
|
|
|
#define CTL_SD_ERROR_DETAIL_STATUS 0x2c
|
|
|
|
#define CTL_SD_DATA_PORT 0x30
|
|
|
|
#define CTL_TRANSACTION_CTL 0x34
|
|
|
|
#define CTL_SDIO_STATUS 0x36
|
|
|
|
#define CTL_SDIO_IRQ_MASK 0x38
|
|
|
|
#define CTL_DMA_ENABLE 0xd8
|
|
|
|
#define CTL_RESET_SD 0xe0
|
|
|
|
#define CTL_VERSION 0xe2
|
|
|
|
#define CTL_SDIO_REGS 0x100
|
|
|
|
#define CTL_CLK_AND_WAIT_CTL 0x138
|
|
|
|
#define CTL_RESET_SDIO 0x1e0
|
|
|
|
|
2017-03-14 17:09:16 +07:00
|
|
|
/* Definitions for values the CTL_STOP_INTERNAL_ACTION register can take */
|
|
|
|
#define TMIO_STOP_STP BIT(0)
|
|
|
|
#define TMIO_STOP_SEC BIT(8)
|
|
|
|
|
2017-03-14 17:09:17 +07:00
|
|
|
/* Definitions for values the CTL_STATUS register can take */
|
2016-04-27 23:51:24 +07:00
|
|
|
#define TMIO_STAT_CMDRESPEND BIT(0)
|
|
|
|
#define TMIO_STAT_DATAEND BIT(2)
|
|
|
|
#define TMIO_STAT_CARD_REMOVE BIT(3)
|
|
|
|
#define TMIO_STAT_CARD_INSERT BIT(4)
|
|
|
|
#define TMIO_STAT_SIGSTATE BIT(5)
|
|
|
|
#define TMIO_STAT_WRPROTECT BIT(7)
|
|
|
|
#define TMIO_STAT_CARD_REMOVE_A BIT(8)
|
|
|
|
#define TMIO_STAT_CARD_INSERT_A BIT(9)
|
|
|
|
#define TMIO_STAT_SIGSTATE_A BIT(10)
|
|
|
|
|
2017-03-14 17:09:17 +07:00
|
|
|
/* These belong technically to CTL_STATUS2, but the driver merges them */
|
2016-04-27 23:51:24 +07:00
|
|
|
#define TMIO_STAT_CMD_IDX_ERR BIT(16)
|
|
|
|
#define TMIO_STAT_CRCFAIL BIT(17)
|
|
|
|
#define TMIO_STAT_STOPBIT_ERR BIT(18)
|
|
|
|
#define TMIO_STAT_DATATIMEOUT BIT(19)
|
|
|
|
#define TMIO_STAT_RXOVERFLOW BIT(20)
|
|
|
|
#define TMIO_STAT_TXUNDERRUN BIT(21)
|
|
|
|
#define TMIO_STAT_CMDTIMEOUT BIT(22)
|
2016-04-27 23:51:25 +07:00
|
|
|
#define TMIO_STAT_DAT0 BIT(23) /* only known on R-Car so far */
|
2016-04-27 23:51:24 +07:00
|
|
|
#define TMIO_STAT_RXRDY BIT(24)
|
|
|
|
#define TMIO_STAT_TXRQ BIT(25)
|
2016-04-27 23:51:26 +07:00
|
|
|
#define TMIO_STAT_ILL_FUNC BIT(29) /* only when !TMIO_MMC_HAS_IDLE_WAIT */
|
|
|
|
#define TMIO_STAT_SCLKDIVEN BIT(29) /* only when TMIO_MMC_HAS_IDLE_WAIT */
|
2016-04-27 23:51:24 +07:00
|
|
|
#define TMIO_STAT_CMD_BUSY BIT(30)
|
|
|
|
#define TMIO_STAT_ILL_ACCESS BIT(31)
|
2016-04-26 22:55:26 +07:00
|
|
|
|
|
|
|
#define CLK_CTL_DIV_MASK 0xff
|
|
|
|
#define CLK_CTL_SCLKEN BIT(8)
|
|
|
|
|
2016-09-20 03:57:48 +07:00
|
|
|
#define CARD_OPT_WIDTH8 BIT(13)
|
|
|
|
#define CARD_OPT_WIDTH BIT(15)
|
|
|
|
|
2016-04-26 22:55:26 +07:00
|
|
|
#define TMIO_BBS 512 /* Boot block size */
|
|
|
|
|
2017-03-14 17:09:17 +07:00
|
|
|
/* Definitions for values the CTL_SDIO_STATUS register can take */
|
2011-03-24 15:48:36 +07:00
|
|
|
#define TMIO_SDIO_STAT_IOIRQ 0x0001
|
2011-03-23 18:42:44 +07:00
|
|
|
#define TMIO_SDIO_STAT_EXPUB52 0x4000
|
2011-03-24 15:48:36 +07:00
|
|
|
#define TMIO_SDIO_STAT_EXWT 0x8000
|
|
|
|
#define TMIO_SDIO_MASK_ALL 0xc007
|
2011-03-23 18:42:44 +07:00
|
|
|
|
2017-01-20 03:07:18 +07:00
|
|
|
#define TMIO_SDIO_SETBITS_MASK 0x0006
|
|
|
|
|
2011-03-23 18:42:44 +07:00
|
|
|
/* Define some IRQ masks */
|
|
|
|
/* This is the mask used at reset by the chip */
|
|
|
|
#define TMIO_MASK_ALL 0x837f031d
|
|
|
|
#define TMIO_MASK_READOP (TMIO_STAT_RXRDY | TMIO_STAT_DATAEND)
|
|
|
|
#define TMIO_MASK_WRITEOP (TMIO_STAT_TXRQ | TMIO_STAT_DATAEND)
|
|
|
|
#define TMIO_MASK_CMD (TMIO_STAT_CMDRESPEND | TMIO_STAT_CMDTIMEOUT | \
|
|
|
|
TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT)
|
|
|
|
#define TMIO_MASK_IRQ (TMIO_MASK_READOP | TMIO_MASK_WRITEOP | TMIO_MASK_CMD)
|
|
|
|
|
|
|
|
struct tmio_mmc_data;
|
2015-01-13 11:59:05 +07:00
|
|
|
struct tmio_mmc_host;
|
2011-03-23 18:42:44 +07:00
|
|
|
|
2015-01-13 11:57:33 +07:00
|
|
|
struct tmio_mmc_dma {
|
2015-01-13 11:59:14 +07:00
|
|
|
enum dma_slave_buswidth dma_buswidth;
|
2015-01-13 11:57:33 +07:00
|
|
|
bool (*filter)(struct dma_chan *chan, void *arg);
|
2015-01-13 11:59:05 +07:00
|
|
|
void (*enable)(struct tmio_mmc_host *host, bool enable);
|
2015-01-13 11:57:33 +07:00
|
|
|
};
|
|
|
|
|
2011-03-23 18:42:44 +07:00
|
|
|
struct tmio_mmc_host {
|
|
|
|
void __iomem *ctl;
|
|
|
|
struct mmc_command *cmd;
|
|
|
|
struct mmc_request *mrq;
|
|
|
|
struct mmc_data *data;
|
|
|
|
struct mmc_host *mmc;
|
|
|
|
|
|
|
|
/* Callbacks for clock / power control */
|
|
|
|
void (*set_pwr)(struct platform_device *host, int state);
|
|
|
|
void (*set_clk_div)(struct platform_device *host, int state);
|
|
|
|
|
|
|
|
/* pio related stuff */
|
|
|
|
struct scatterlist *sg_ptr;
|
|
|
|
struct scatterlist *sg_orig;
|
|
|
|
unsigned int sg_len;
|
|
|
|
unsigned int sg_off;
|
2015-01-13 11:58:20 +07:00
|
|
|
unsigned long bus_shift;
|
2011-03-23 18:42:44 +07:00
|
|
|
|
|
|
|
struct platform_device *pdev;
|
|
|
|
struct tmio_mmc_data *pdata;
|
2015-01-13 11:57:33 +07:00
|
|
|
struct tmio_mmc_dma *dma;
|
2011-03-23 18:42:44 +07:00
|
|
|
|
|
|
|
/* DMA support */
|
|
|
|
bool force_pio;
|
|
|
|
struct dma_chan *chan_rx;
|
|
|
|
struct dma_chan *chan_tx;
|
mmc: tmio: ensure end of DMA and SD access are in sync
The current code assumes that DMA is finished before SD access end is
flagged. Thus, it schedules the 'dma_complete' tasklet in the SD card
interrupt routine when DATAEND is set. The assumption is not safe,
though. Even by mounting an SD card, it can be seen that sometimes DMA
complete is first, sometimes DATAEND. It seems they are usually close
enough timewise to not cause problems. However, a customer reported that
with CMD53 sometimes things really break apart. As a result, the BSP has
a patch which introduces flags for both events and makes sure both flags
are set before scheduling the tasklet. The customer accepted the patch,
yet it doesn't seem a proper upstream solution to me.
This patch refactors the code to replace the tasklet with already
existing and more lightweight mechanisms. First of all, we set the
callback in a DMA descriptor to automatically get notified when DMA is
done. In the callback, we then use a completion to make sure the SD
access has already ended. Then, we proceed as before.
Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
2017-02-18 01:22:41 +07:00
|
|
|
struct completion dma_dataend;
|
2011-03-23 18:42:44 +07:00
|
|
|
struct tasklet_struct dma_issue;
|
|
|
|
struct scatterlist bounce_sg;
|
|
|
|
u8 *bounce_buf;
|
|
|
|
|
|
|
|
/* Track lost interrupts */
|
|
|
|
struct delayed_work delayed_reset_work;
|
2011-07-14 17:12:38 +07:00
|
|
|
struct work_struct done;
|
|
|
|
|
2013-10-30 06:16:17 +07:00
|
|
|
/* Cache */
|
2011-08-25 08:27:25 +07:00
|
|
|
u32 sdcard_irq_mask;
|
|
|
|
u32 sdio_irq_mask;
|
2013-10-30 06:16:17 +07:00
|
|
|
unsigned int clk_cache;
|
2011-08-25 08:27:25 +07:00
|
|
|
|
2011-07-14 17:12:38 +07:00
|
|
|
spinlock_t lock; /* protect host private data */
|
2011-03-23 18:42:44 +07:00
|
|
|
unsigned long last_req_ts;
|
2011-07-14 17:12:38 +07:00
|
|
|
struct mutex ios_lock; /* protect set_ios() context */
|
2012-02-10 04:57:08 +07:00
|
|
|
bool native_hotplug;
|
2013-10-24 20:58:45 +07:00
|
|
|
bool sdio_irq_enabled;
|
2016-11-03 21:16:03 +07:00
|
|
|
u32 scc_tappos;
|
2015-01-13 11:57:42 +07:00
|
|
|
|
2016-11-03 21:16:01 +07:00
|
|
|
/* Mandatory callback */
|
2016-04-01 22:44:31 +07:00
|
|
|
int (*clk_enable)(struct tmio_mmc_host *host);
|
2016-11-03 21:16:01 +07:00
|
|
|
|
|
|
|
/* Optional callbacks */
|
2016-04-01 22:44:32 +07:00
|
|
|
unsigned int (*clk_update)(struct tmio_mmc_host *host,
|
|
|
|
unsigned int new_clock);
|
2016-04-01 22:44:31 +07:00
|
|
|
void (*clk_disable)(struct tmio_mmc_host *host);
|
2015-01-13 11:58:10 +07:00
|
|
|
int (*multi_io_quirk)(struct mmc_card *card,
|
|
|
|
unsigned int direction, int blk_size);
|
2016-08-24 16:34:37 +07:00
|
|
|
int (*card_busy)(struct mmc_host *mmc);
|
2016-04-01 22:44:33 +07:00
|
|
|
int (*start_signal_voltage_switch)(struct mmc_host *mmc,
|
|
|
|
struct mmc_ios *ios);
|
2016-11-03 21:16:01 +07:00
|
|
|
int (*write16_hook)(struct tmio_mmc_host *host, int addr);
|
2016-11-03 21:16:02 +07:00
|
|
|
void (*hw_reset)(struct tmio_mmc_host *host);
|
2016-11-03 21:16:03 +07:00
|
|
|
void (*prepare_tuning)(struct tmio_mmc_host *host, unsigned long tap);
|
|
|
|
bool (*check_scc_error)(struct tmio_mmc_host *host);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Mandatory callback for tuning to occur which is optional for SDR50
|
|
|
|
* and mandatory for SDR104.
|
|
|
|
*/
|
|
|
|
unsigned int (*init_tuning)(struct tmio_mmc_host *host);
|
|
|
|
int (*select_tuning)(struct tmio_mmc_host *host);
|
|
|
|
|
|
|
|
/* Tuning values: 1 for success, 0 for failure */
|
|
|
|
DECLARE_BITMAP(taps, BITS_PER_BYTE * sizeof(long));
|
|
|
|
unsigned int tap_num;
|
2011-03-23 18:42:44 +07:00
|
|
|
};
|
|
|
|
|
2015-01-13 11:57:22 +07:00
|
|
|
struct tmio_mmc_host *tmio_mmc_host_alloc(struct platform_device *pdev);
|
|
|
|
void tmio_mmc_host_free(struct tmio_mmc_host *host);
|
|
|
|
int tmio_mmc_host_probe(struct tmio_mmc_host *host,
|
2011-03-23 18:42:44 +07:00
|
|
|
struct tmio_mmc_data *pdata);
|
|
|
|
void tmio_mmc_host_remove(struct tmio_mmc_host *host);
|
|
|
|
void tmio_mmc_do_data_irq(struct tmio_mmc_host *host);
|
|
|
|
|
|
|
|
void tmio_mmc_enable_mmc_irqs(struct tmio_mmc_host *host, u32 i);
|
|
|
|
void tmio_mmc_disable_mmc_irqs(struct tmio_mmc_host *host, u32 i);
|
2011-05-06 18:02:33 +07:00
|
|
|
irqreturn_t tmio_mmc_irq(int irq, void *devid);
|
2011-03-23 18:42:44 +07:00
|
|
|
|
|
|
|
static inline char *tmio_mmc_kmap_atomic(struct scatterlist *sg,
|
|
|
|
unsigned long *flags)
|
|
|
|
{
|
|
|
|
local_irq_save(*flags);
|
2011-11-27 12:27:00 +07:00
|
|
|
return kmap_atomic(sg_page(sg)) + sg->offset;
|
2011-03-23 18:42:44 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline void tmio_mmc_kunmap_atomic(struct scatterlist *sg,
|
|
|
|
unsigned long *flags, void *virt)
|
|
|
|
{
|
2011-11-27 12:27:00 +07:00
|
|
|
kunmap_atomic(virt - sg->offset);
|
2011-03-23 18:42:44 +07:00
|
|
|
local_irq_restore(*flags);
|
|
|
|
}
|
|
|
|
|
2011-03-14 15:52:33 +07:00
|
|
|
#if defined(CONFIG_MMC_SDHI) || defined(CONFIG_MMC_SDHI_MODULE)
|
2011-03-23 18:42:44 +07:00
|
|
|
void tmio_mmc_start_dma(struct tmio_mmc_host *host, struct mmc_data *data);
|
2011-07-14 23:39:10 +07:00
|
|
|
void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable);
|
2011-03-23 18:42:44 +07:00
|
|
|
void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdata);
|
|
|
|
void tmio_mmc_release_dma(struct tmio_mmc_host *host);
|
2012-01-06 19:06:51 +07:00
|
|
|
void tmio_mmc_abort_dma(struct tmio_mmc_host *host);
|
2011-03-23 18:42:44 +07:00
|
|
|
#else
|
|
|
|
static inline void tmio_mmc_start_dma(struct tmio_mmc_host *host,
|
|
|
|
struct mmc_data *data)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2011-07-14 23:39:10 +07:00
|
|
|
static inline void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2011-03-23 18:42:44 +07:00
|
|
|
static inline void tmio_mmc_request_dma(struct tmio_mmc_host *host,
|
|
|
|
struct tmio_mmc_data *pdata)
|
|
|
|
{
|
|
|
|
host->chan_tx = NULL;
|
|
|
|
host->chan_rx = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void tmio_mmc_release_dma(struct tmio_mmc_host *host)
|
|
|
|
{
|
|
|
|
}
|
2012-01-06 19:06:51 +07:00
|
|
|
|
|
|
|
static inline void tmio_mmc_abort_dma(struct tmio_mmc_host *host)
|
|
|
|
{
|
|
|
|
}
|
2011-03-23 18:42:44 +07:00
|
|
|
#endif
|
|
|
|
|
2014-08-25 17:03:20 +07:00
|
|
|
#ifdef CONFIG_PM
|
2011-05-11 23:51:11 +07:00
|
|
|
int tmio_mmc_host_runtime_suspend(struct device *dev);
|
|
|
|
int tmio_mmc_host_runtime_resume(struct device *dev);
|
2013-10-23 19:55:07 +07:00
|
|
|
#endif
|
2011-05-11 23:51:11 +07:00
|
|
|
|
2011-06-21 06:00:09 +07:00
|
|
|
static inline u16 sd_ctrl_read16(struct tmio_mmc_host *host, int addr)
|
|
|
|
{
|
2015-01-13 11:58:20 +07:00
|
|
|
return readw(host->ctl + (addr << host->bus_shift));
|
2011-06-21 06:00:09 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline void sd_ctrl_read16_rep(struct tmio_mmc_host *host, int addr,
|
|
|
|
u16 *buf, int count)
|
|
|
|
{
|
2015-01-13 11:58:20 +07:00
|
|
|
readsw(host->ctl + (addr << host->bus_shift), buf, count);
|
2011-06-21 06:00:09 +07:00
|
|
|
}
|
|
|
|
|
2016-04-27 23:51:23 +07:00
|
|
|
static inline u32 sd_ctrl_read16_and_16_as_32(struct tmio_mmc_host *host, int addr)
|
2011-06-21 06:00:09 +07:00
|
|
|
{
|
2015-01-13 11:58:20 +07:00
|
|
|
return readw(host->ctl + (addr << host->bus_shift)) |
|
|
|
|
readw(host->ctl + ((addr + 2) << host->bus_shift)) << 16;
|
2011-06-21 06:00:09 +07:00
|
|
|
}
|
|
|
|
|
2016-09-12 21:15:06 +07:00
|
|
|
static inline void sd_ctrl_read32_rep(struct tmio_mmc_host *host, int addr,
|
|
|
|
u32 *buf, int count)
|
|
|
|
{
|
|
|
|
readsl(host->ctl + (addr << host->bus_shift), buf, count);
|
|
|
|
}
|
|
|
|
|
2011-06-21 06:00:09 +07:00
|
|
|
static inline void sd_ctrl_write16(struct tmio_mmc_host *host, int addr, u16 val)
|
|
|
|
{
|
2011-06-21 06:00:10 +07:00
|
|
|
/* If there is a hook and it returns non-zero then there
|
|
|
|
* is an error and the write should be skipped
|
|
|
|
*/
|
2015-01-13 11:57:42 +07:00
|
|
|
if (host->write16_hook && host->write16_hook(host, addr))
|
2011-06-21 06:00:10 +07:00
|
|
|
return;
|
2015-01-13 11:58:20 +07:00
|
|
|
writew(val, host->ctl + (addr << host->bus_shift));
|
2011-06-21 06:00:09 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline void sd_ctrl_write16_rep(struct tmio_mmc_host *host, int addr,
|
|
|
|
u16 *buf, int count)
|
|
|
|
{
|
2015-01-13 11:58:20 +07:00
|
|
|
writesw(host->ctl + (addr << host->bus_shift), buf, count);
|
2011-06-21 06:00:09 +07:00
|
|
|
}
|
|
|
|
|
2016-04-27 23:51:23 +07:00
|
|
|
static inline void sd_ctrl_write32_as_16_and_16(struct tmio_mmc_host *host, int addr, u32 val)
|
2011-06-21 06:00:09 +07:00
|
|
|
{
|
2016-05-27 19:10:29 +07:00
|
|
|
writew(val & 0xffff, host->ctl + (addr << host->bus_shift));
|
2015-01-13 11:58:20 +07:00
|
|
|
writew(val >> 16, host->ctl + ((addr + 2) << host->bus_shift));
|
2011-06-21 06:00:09 +07:00
|
|
|
}
|
|
|
|
|
2016-09-12 21:15:06 +07:00
|
|
|
static inline void sd_ctrl_write32_rep(struct tmio_mmc_host *host, int addr,
|
|
|
|
const u32 *buf, int count)
|
|
|
|
{
|
|
|
|
writesl(host->ctl + (addr << host->bus_shift), buf, count);
|
|
|
|
}
|
|
|
|
|
2011-03-23 18:42:44 +07:00
|
|
|
#endif
|