imxmmc: use readl/writel
Use readl/writel instead of direct pointer deref. Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
This commit is contained in:
parent
2507b0a333
commit
df25f9da9f
2 changed files with 135 additions and 94 deletions
|
@ -43,6 +43,7 @@ struct imxmci_host {
|
||||||
struct mmc_host *mmc;
|
struct mmc_host *mmc;
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
|
void __iomem *base;
|
||||||
int irq;
|
int irq;
|
||||||
imx_dmach_t dma;
|
imx_dmach_t dma;
|
||||||
volatile unsigned int imask;
|
volatile unsigned int imask;
|
||||||
|
@ -98,14 +99,22 @@ struct imxmci_host {
|
||||||
static void imxmci_stop_clock(struct imxmci_host *host)
|
static void imxmci_stop_clock(struct imxmci_host *host)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
MMC_STR_STP_CLK &= ~STR_STP_CLK_START_CLK;
|
u16 reg;
|
||||||
while (i < 0x1000) {
|
|
||||||
if (!(i & 0x7f))
|
|
||||||
MMC_STR_STP_CLK |= STR_STP_CLK_STOP_CLK;
|
|
||||||
|
|
||||||
if (!(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN)) {
|
reg = readw(host->base + MMC_REG_STR_STP_CLK);
|
||||||
|
writew(reg & ~STR_STP_CLK_START_CLK, host->base + MMC_REG_STR_STP_CLK);
|
||||||
|
while (i < 0x1000) {
|
||||||
|
if (!(i & 0x7f)) {
|
||||||
|
reg = readw(host->base + MMC_REG_STR_STP_CLK);
|
||||||
|
writew(reg | STR_STP_CLK_STOP_CLK,
|
||||||
|
host->base + MMC_REG_STR_STP_CLK);
|
||||||
|
}
|
||||||
|
|
||||||
|
reg = readw(host->base + MMC_REG_STATUS);
|
||||||
|
if (!(reg & STATUS_CARD_BUS_CLK_RUN)) {
|
||||||
/* Check twice before cut */
|
/* Check twice before cut */
|
||||||
if (!(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN))
|
reg = readw(host->base + MMC_REG_STATUS);
|
||||||
|
if (!(reg & STATUS_CARD_BUS_CLK_RUN))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,8 +128,10 @@ static int imxmci_start_clock(struct imxmci_host *host)
|
||||||
unsigned int trials = 0;
|
unsigned int trials = 0;
|
||||||
unsigned int delay_limit = 128;
|
unsigned int delay_limit = 128;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
u16 reg;
|
||||||
|
|
||||||
MMC_STR_STP_CLK &= ~STR_STP_CLK_STOP_CLK;
|
reg = readw(host->base + MMC_REG_STR_STP_CLK);
|
||||||
|
writew(reg & ~STR_STP_CLK_STOP_CLK, host->base + MMC_REG_STR_STP_CLK);
|
||||||
|
|
||||||
clear_bit(IMXMCI_PEND_STARTED_b, &host->pending_events);
|
clear_bit(IMXMCI_PEND_STARTED_b, &host->pending_events);
|
||||||
|
|
||||||
|
@ -129,15 +140,18 @@ static int imxmci_start_clock(struct imxmci_host *host)
|
||||||
* then 6 delay loops, but during card detection (low clockrate)
|
* then 6 delay loops, but during card detection (low clockrate)
|
||||||
* it takes up to 5000 delay loops and sometimes fails for the first time
|
* it takes up to 5000 delay loops and sometimes fails for the first time
|
||||||
*/
|
*/
|
||||||
MMC_STR_STP_CLK |= STR_STP_CLK_START_CLK;
|
reg = readw(host->base + MMC_REG_STR_STP_CLK);
|
||||||
|
writew(reg | STR_STP_CLK_START_CLK, host->base + MMC_REG_STR_STP_CLK);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
unsigned int delay = delay_limit;
|
unsigned int delay = delay_limit;
|
||||||
|
|
||||||
while (delay--) {
|
while (delay--) {
|
||||||
if (MMC_STATUS & STATUS_CARD_BUS_CLK_RUN)
|
reg = readw(host->base + MMC_REG_STATUS);
|
||||||
|
if (reg & STATUS_CARD_BUS_CLK_RUN)
|
||||||
/* Check twice before cut */
|
/* Check twice before cut */
|
||||||
if (MMC_STATUS & STATUS_CARD_BUS_CLK_RUN)
|
reg = readw(host->base + MMC_REG_STATUS);
|
||||||
|
if (reg & STATUS_CARD_BUS_CLK_RUN)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (test_bit(IMXMCI_PEND_STARTED_b, &host->pending_events))
|
if (test_bit(IMXMCI_PEND_STARTED_b, &host->pending_events))
|
||||||
|
@ -151,8 +165,11 @@ static int imxmci_start_clock(struct imxmci_host *host)
|
||||||
* IRQ or schedule delays this function execution and the clocks has
|
* IRQ or schedule delays this function execution and the clocks has
|
||||||
* been already stopped by other means (response processing, SDHC HW)
|
* been already stopped by other means (response processing, SDHC HW)
|
||||||
*/
|
*/
|
||||||
if (!test_bit(IMXMCI_PEND_STARTED_b, &host->pending_events))
|
if (!test_bit(IMXMCI_PEND_STARTED_b, &host->pending_events)) {
|
||||||
MMC_STR_STP_CLK |= STR_STP_CLK_START_CLK;
|
reg = readw(host->base + MMC_REG_STR_STP_CLK);
|
||||||
|
writew(reg | STR_STP_CLK_START_CLK,
|
||||||
|
host->base + MMC_REG_STR_STP_CLK);
|
||||||
|
}
|
||||||
local_irq_restore(flags);
|
local_irq_restore(flags);
|
||||||
|
|
||||||
} while (++trials < 256);
|
} while (++trials < 256);
|
||||||
|
@ -162,23 +179,20 @@ static int imxmci_start_clock(struct imxmci_host *host)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void imxmci_softreset(void)
|
static void imxmci_softreset(struct imxmci_host *host)
|
||||||
{
|
{
|
||||||
/* reset sequence */
|
int i;
|
||||||
MMC_STR_STP_CLK = 0x8;
|
|
||||||
MMC_STR_STP_CLK = 0xD;
|
|
||||||
MMC_STR_STP_CLK = 0x5;
|
|
||||||
MMC_STR_STP_CLK = 0x5;
|
|
||||||
MMC_STR_STP_CLK = 0x5;
|
|
||||||
MMC_STR_STP_CLK = 0x5;
|
|
||||||
MMC_STR_STP_CLK = 0x5;
|
|
||||||
MMC_STR_STP_CLK = 0x5;
|
|
||||||
MMC_STR_STP_CLK = 0x5;
|
|
||||||
MMC_STR_STP_CLK = 0x5;
|
|
||||||
|
|
||||||
MMC_RES_TO = 0xff;
|
/* reset sequence */
|
||||||
MMC_BLK_LEN = 512;
|
writew(0x08, host->base + MMC_REG_STR_STP_CLK);
|
||||||
MMC_NOB = 1;
|
writew(0x0D, host->base + MMC_REG_STR_STP_CLK);
|
||||||
|
|
||||||
|
for (i = 0; i < 8; i++)
|
||||||
|
writew(0x05, host->base + MMC_REG_STR_STP_CLK);
|
||||||
|
|
||||||
|
writew(0xff, host->base + MMC_REG_RES_TO);
|
||||||
|
writew(512, host->base + MMC_REG_BLK_LEN);
|
||||||
|
writew(1, host->base + MMC_REG_NOB);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int imxmci_busy_wait_for_status(struct imxmci_host *host,
|
static int imxmci_busy_wait_for_status(struct imxmci_host *host,
|
||||||
|
@ -195,7 +209,7 @@ static int imxmci_busy_wait_for_status(struct imxmci_host *host,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
udelay(2);
|
udelay(2);
|
||||||
*pstat |= MMC_STATUS;
|
*pstat |= readw(host->base + MMC_REG_STATUS);
|
||||||
}
|
}
|
||||||
if (!loops)
|
if (!loops)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -220,8 +234,8 @@ static void imxmci_setup_data(struct imxmci_host *host, struct mmc_data *data)
|
||||||
host->data = data;
|
host->data = data;
|
||||||
data->bytes_xfered = 0;
|
data->bytes_xfered = 0;
|
||||||
|
|
||||||
MMC_NOB = nob;
|
writew(nob, host->base + MMC_REG_NOB);
|
||||||
MMC_BLK_LEN = blksz;
|
writew(blksz, host->base + MMC_REG_BLK_LEN);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DMA cannot be used for small block sizes, we have to use CPU driven transfers otherwise.
|
* DMA cannot be used for small block sizes, we have to use CPU driven transfers otherwise.
|
||||||
|
@ -237,8 +251,8 @@ static void imxmci_setup_data(struct imxmci_host *host, struct mmc_data *data)
|
||||||
host->dma_dir = DMA_FROM_DEVICE;
|
host->dma_dir = DMA_FROM_DEVICE;
|
||||||
|
|
||||||
/* Hack to enable read SCR */
|
/* Hack to enable read SCR */
|
||||||
MMC_NOB = 1;
|
writew(1, host->base + MMC_REG_NOB);
|
||||||
MMC_BLK_LEN = 512;
|
writew(512, host->base + MMC_REG_BLK_LEN);
|
||||||
} else {
|
} else {
|
||||||
host->dma_dir = DMA_TO_DEVICE;
|
host->dma_dir = DMA_TO_DEVICE;
|
||||||
}
|
}
|
||||||
|
@ -259,7 +273,8 @@ static void imxmci_setup_data(struct imxmci_host *host, struct mmc_data *data)
|
||||||
data->sg_len, host->dma_dir);
|
data->sg_len, host->dma_dir);
|
||||||
|
|
||||||
imx_dma_setup_sg(host->dma, data->sg, data->sg_len, datasz,
|
imx_dma_setup_sg(host->dma, data->sg, data->sg_len, datasz,
|
||||||
host->res->start + MMC_BUFFER_ACCESS_OFS, DMA_MODE_READ);
|
host->res->start + MMC_REG_BUFFER_ACCESS,
|
||||||
|
DMA_MODE_READ);
|
||||||
|
|
||||||
/*imx_dma_setup_mem2dev_ccr(host->dma, DMA_MODE_READ, IMX_DMA_WIDTH_16, CCR_REN);*/
|
/*imx_dma_setup_mem2dev_ccr(host->dma, DMA_MODE_READ, IMX_DMA_WIDTH_16, CCR_REN);*/
|
||||||
CCR(host->dma) = CCR_DMOD_LINEAR | CCR_DSIZ_32 | CCR_SMOD_FIFO | CCR_SSIZ_16 | CCR_REN;
|
CCR(host->dma) = CCR_DMOD_LINEAR | CCR_DSIZ_32 | CCR_SMOD_FIFO | CCR_SSIZ_16 | CCR_REN;
|
||||||
|
@ -270,7 +285,8 @@ static void imxmci_setup_data(struct imxmci_host *host, struct mmc_data *data)
|
||||||
data->sg_len, host->dma_dir);
|
data->sg_len, host->dma_dir);
|
||||||
|
|
||||||
imx_dma_setup_sg(host->dma, data->sg, data->sg_len, datasz,
|
imx_dma_setup_sg(host->dma, data->sg, data->sg_len, datasz,
|
||||||
host->res->start + MMC_BUFFER_ACCESS_OFS, DMA_MODE_WRITE);
|
host->res->start + MMC_REG_BUFFER_ACCESS,
|
||||||
|
DMA_MODE_WRITE);
|
||||||
|
|
||||||
/*imx_dma_setup_mem2dev_ccr(host->dma, DMA_MODE_WRITE, IMX_DMA_WIDTH_16, CCR_REN);*/
|
/*imx_dma_setup_mem2dev_ccr(host->dma, DMA_MODE_WRITE, IMX_DMA_WIDTH_16, CCR_REN);*/
|
||||||
CCR(host->dma) = CCR_SMOD_LINEAR | CCR_SSIZ_32 | CCR_DMOD_FIFO | CCR_DSIZ_16 | CCR_REN;
|
CCR(host->dma) = CCR_SMOD_LINEAR | CCR_SSIZ_32 | CCR_DMOD_FIFO | CCR_DSIZ_16 | CCR_REN;
|
||||||
|
@ -341,10 +357,10 @@ static void imxmci_start_cmd(struct imxmci_host *host, struct mmc_command *cmd,
|
||||||
if (host->actual_bus_width == MMC_BUS_WIDTH_4)
|
if (host->actual_bus_width == MMC_BUS_WIDTH_4)
|
||||||
cmdat |= CMD_DAT_CONT_BUS_WIDTH_4;
|
cmdat |= CMD_DAT_CONT_BUS_WIDTH_4;
|
||||||
|
|
||||||
MMC_CMD = cmd->opcode;
|
writew(cmd->opcode, host->base + MMC_REG_CMD);
|
||||||
MMC_ARGH = cmd->arg >> 16;
|
writew(cmd->arg >> 16, host->base + MMC_REG_ARGH);
|
||||||
MMC_ARGL = cmd->arg & 0xffff;
|
writew(cmd->arg & 0xffff, host->base + MMC_REG_ARGL);
|
||||||
MMC_CMD_DAT_CONT = cmdat;
|
writew(cmdat, host->base + MMC_REG_CMD_DAT_CONT);
|
||||||
|
|
||||||
atomic_set(&host->stuck_timeout, 0);
|
atomic_set(&host->stuck_timeout, 0);
|
||||||
set_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events);
|
set_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events);
|
||||||
|
@ -363,7 +379,7 @@ static void imxmci_start_cmd(struct imxmci_host *host, struct mmc_command *cmd,
|
||||||
|
|
||||||
spin_lock_irqsave(&host->lock, flags);
|
spin_lock_irqsave(&host->lock, flags);
|
||||||
host->imask = imask;
|
host->imask = imask;
|
||||||
MMC_INT_MASK = host->imask;
|
writew(host->imask, host->base + MMC_REG_INT_MASK);
|
||||||
spin_unlock_irqrestore(&host->lock, flags);
|
spin_unlock_irqrestore(&host->lock, flags);
|
||||||
|
|
||||||
dev_dbg(mmc_dev(host->mmc), "CMD%02d (0x%02x) mask set to 0x%04x\n",
|
dev_dbg(mmc_dev(host->mmc), "CMD%02d (0x%02x) mask set to 0x%04x\n",
|
||||||
|
@ -382,7 +398,7 @@ static void imxmci_finish_request(struct imxmci_host *host, struct mmc_request *
|
||||||
IMXMCI_PEND_DMA_DATA_m | IMXMCI_PEND_CPU_DATA_m);
|
IMXMCI_PEND_DMA_DATA_m | IMXMCI_PEND_CPU_DATA_m);
|
||||||
|
|
||||||
host->imask = IMXMCI_INT_MASK_DEFAULT;
|
host->imask = IMXMCI_INT_MASK_DEFAULT;
|
||||||
MMC_INT_MASK = host->imask;
|
writew(host->imask, host->base + MMC_REG_INT_MASK);
|
||||||
|
|
||||||
spin_unlock_irqrestore(&host->lock, flags);
|
spin_unlock_irqrestore(&host->lock, flags);
|
||||||
|
|
||||||
|
@ -448,14 +464,14 @@ static int imxmci_cmd_done(struct imxmci_host *host, unsigned int stat)
|
||||||
if (cmd->flags & MMC_RSP_PRESENT) {
|
if (cmd->flags & MMC_RSP_PRESENT) {
|
||||||
if (cmd->flags & MMC_RSP_136) {
|
if (cmd->flags & MMC_RSP_136) {
|
||||||
for (i = 0; i < 4; i++) {
|
for (i = 0; i < 4; i++) {
|
||||||
u32 d = MMC_RES_FIFO & 0xffff;
|
a = readw(host->base + MMC_REG_RES_FIFO);
|
||||||
u32 e = MMC_RES_FIFO & 0xffff;
|
b = readw(host->base + MMC_REG_RES_FIFO);
|
||||||
cmd->resp[i] = d << 16 | e;
|
cmd->resp[i] = a << 16 | b;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
a = MMC_RES_FIFO & 0xffff;
|
a = readw(host->base + MMC_REG_RES_FIFO);
|
||||||
b = MMC_RES_FIFO & 0xffff;
|
b = readw(host->base + MMC_REG_RES_FIFO);
|
||||||
c = MMC_RES_FIFO & 0xffff;
|
c = readw(host->base + MMC_REG_RES_FIFO);
|
||||||
cmd->resp[0] = a << 24 | b << 8 | c >> 8;
|
cmd->resp[0] = a << 24 | b << 8 | c >> 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -468,7 +484,7 @@ static int imxmci_cmd_done(struct imxmci_host *host, unsigned int stat)
|
||||||
|
|
||||||
/* Wait for FIFO to be empty before starting DMA write */
|
/* Wait for FIFO to be empty before starting DMA write */
|
||||||
|
|
||||||
stat = MMC_STATUS;
|
stat = readw(host->base + MMC_REG_STATUS);
|
||||||
if (imxmci_busy_wait_for_status(host, &stat,
|
if (imxmci_busy_wait_for_status(host, &stat,
|
||||||
STATUS_APPL_BUFF_FE,
|
STATUS_APPL_BUFF_FE,
|
||||||
40, "imxmci_cmd_done DMA WR") < 0) {
|
40, "imxmci_cmd_done DMA WR") < 0) {
|
||||||
|
@ -558,7 +574,7 @@ static int imxmci_cpu_driven_data(struct imxmci_host *host, unsigned int *pstat)
|
||||||
|
|
||||||
for (i = burst_len; i >= 2 ; i -= 2) {
|
for (i = burst_len; i >= 2 ; i -= 2) {
|
||||||
u16 data;
|
u16 data;
|
||||||
data = MMC_BUFFER_ACCESS;
|
data = readw(host->base + MMC_REG_BUFFER_ACCESS);
|
||||||
udelay(10); /* required for clocks < 8MHz*/
|
udelay(10); /* required for clocks < 8MHz*/
|
||||||
if (host->data_cnt+2 <= host->dma_size) {
|
if (host->data_cnt+2 <= host->dma_size) {
|
||||||
*(host->data_ptr++) = data;
|
*(host->data_ptr++) = data;
|
||||||
|
@ -569,7 +585,7 @@ static int imxmci_cpu_driven_data(struct imxmci_host *host, unsigned int *pstat)
|
||||||
host->data_cnt += 2;
|
host->data_cnt += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
stat = MMC_STATUS;
|
stat = readw(host->base + MMC_REG_STATUS);
|
||||||
|
|
||||||
dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data read %d burst %d STATUS = 0x%x\n",
|
dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data read %d burst %d STATUS = 0x%x\n",
|
||||||
host->data_cnt, burst_len, stat);
|
host->data_cnt, burst_len, stat);
|
||||||
|
@ -603,9 +619,9 @@ static int imxmci_cpu_driven_data(struct imxmci_host *host, unsigned int *pstat)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = burst_len; i > 0 ; i -= 2)
|
for (i = burst_len; i > 0 ; i -= 2)
|
||||||
MMC_BUFFER_ACCESS = *(host->data_ptr++);
|
writew(*(host->data_ptr++), host->base + MMC_REG_BUFFER_ACCESS);
|
||||||
|
|
||||||
stat = MMC_STATUS;
|
stat = readw(host->base + MMC_REG_STATUS);
|
||||||
|
|
||||||
dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data write burst %d STATUS = 0x%x\n",
|
dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data write burst %d STATUS = 0x%x\n",
|
||||||
burst_len, stat);
|
burst_len, stat);
|
||||||
|
@ -620,7 +636,7 @@ static int imxmci_cpu_driven_data(struct imxmci_host *host, unsigned int *pstat)
|
||||||
static void imxmci_dma_irq(int dma, void *devid)
|
static void imxmci_dma_irq(int dma, void *devid)
|
||||||
{
|
{
|
||||||
struct imxmci_host *host = devid;
|
struct imxmci_host *host = devid;
|
||||||
uint32_t stat = MMC_STATUS;
|
u32 stat = readw(host->base + MMC_REG_STATUS);
|
||||||
|
|
||||||
atomic_set(&host->stuck_timeout, 0);
|
atomic_set(&host->stuck_timeout, 0);
|
||||||
host->status_reg = stat;
|
host->status_reg = stat;
|
||||||
|
@ -631,10 +647,11 @@ static void imxmci_dma_irq(int dma, void *devid)
|
||||||
static irqreturn_t imxmci_irq(int irq, void *devid)
|
static irqreturn_t imxmci_irq(int irq, void *devid)
|
||||||
{
|
{
|
||||||
struct imxmci_host *host = devid;
|
struct imxmci_host *host = devid;
|
||||||
uint32_t stat = MMC_STATUS;
|
u32 stat = readw(host->base + MMC_REG_STATUS);
|
||||||
int handled = 1;
|
int handled = 1;
|
||||||
|
|
||||||
MMC_INT_MASK = host->imask | INT_MASK_SDIO | INT_MASK_AUTO_CARD_DETECT;
|
writew(host->imask | INT_MASK_SDIO | INT_MASK_AUTO_CARD_DETECT,
|
||||||
|
host->base + MMC_REG_INT_MASK);
|
||||||
|
|
||||||
atomic_set(&host->stuck_timeout, 0);
|
atomic_set(&host->stuck_timeout, 0);
|
||||||
host->status_reg = stat;
|
host->status_reg = stat;
|
||||||
|
@ -655,7 +672,7 @@ static void imxmci_tasklet_fnc(unsigned long data)
|
||||||
if (atomic_read(&host->stuck_timeout) > 4) {
|
if (atomic_read(&host->stuck_timeout) > 4) {
|
||||||
char *what;
|
char *what;
|
||||||
timeout = 1;
|
timeout = 1;
|
||||||
stat = MMC_STATUS;
|
stat = readw(host->base + MMC_REG_STATUS);
|
||||||
host->status_reg = stat;
|
host->status_reg = stat;
|
||||||
if (test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events))
|
if (test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events))
|
||||||
if (test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events))
|
if (test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events))
|
||||||
|
@ -671,12 +688,20 @@ static void imxmci_tasklet_fnc(unsigned long data)
|
||||||
else
|
else
|
||||||
what = "???";
|
what = "???";
|
||||||
|
|
||||||
dev_err(mmc_dev(host->mmc), "%s TIMEOUT, hardware stucked STATUS = 0x%04x IMASK = 0x%04x\n",
|
dev_err(mmc_dev(host->mmc),
|
||||||
what, stat, MMC_INT_MASK);
|
"%s TIMEOUT, hardware stucked STATUS = 0x%04x IMASK = 0x%04x\n",
|
||||||
dev_err(mmc_dev(host->mmc), "CMD_DAT_CONT = 0x%04x, MMC_BLK_LEN = 0x%04x, MMC_NOB = 0x%04x, DMA_CCR = 0x%08x\n",
|
what, stat,
|
||||||
MMC_CMD_DAT_CONT, MMC_BLK_LEN, MMC_NOB, CCR(host->dma));
|
readw(host->base + MMC_REG_INT_MASK));
|
||||||
|
dev_err(mmc_dev(host->mmc),
|
||||||
|
"CMD_DAT_CONT = 0x%04x, MMC_BLK_LEN = 0x%04x, MMC_NOB = 0x%04x, DMA_CCR = 0x%08x\n",
|
||||||
|
readw(host->base + MMC_REG_CMD_DAT_CONT),
|
||||||
|
readw(host->base + MMC_REG_BLK_LEN),
|
||||||
|
readw(host->base + MMC_REG_NOB),
|
||||||
|
CCR(host->dma));
|
||||||
dev_err(mmc_dev(host->mmc), "CMD%d, prevCMD%d, bus %d-bit, dma_size = 0x%x\n",
|
dev_err(mmc_dev(host->mmc), "CMD%d, prevCMD%d, bus %d-bit, dma_size = 0x%x\n",
|
||||||
host->cmd?host->cmd->opcode:0, host->prev_cmd_code, 1 << host->actual_bus_width, host->dma_size);
|
host->cmd ? host->cmd->opcode : 0,
|
||||||
|
host->prev_cmd_code,
|
||||||
|
1 << host->actual_bus_width, host->dma_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!host->present || timeout)
|
if (!host->present || timeout)
|
||||||
|
@ -686,7 +711,7 @@ static void imxmci_tasklet_fnc(unsigned long data)
|
||||||
if (test_bit(IMXMCI_PEND_IRQ_b, &host->pending_events) || timeout) {
|
if (test_bit(IMXMCI_PEND_IRQ_b, &host->pending_events) || timeout) {
|
||||||
clear_bit(IMXMCI_PEND_IRQ_b, &host->pending_events);
|
clear_bit(IMXMCI_PEND_IRQ_b, &host->pending_events);
|
||||||
|
|
||||||
stat = MMC_STATUS;
|
stat = readw(host->base + MMC_REG_STATUS);
|
||||||
/*
|
/*
|
||||||
* This is not required in theory, but there is chance to miss some flag
|
* This is not required in theory, but there is chance to miss some flag
|
||||||
* which clears automatically by mask write, FreeScale original code keeps
|
* which clears automatically by mask write, FreeScale original code keeps
|
||||||
|
@ -711,7 +736,7 @@ static void imxmci_tasklet_fnc(unsigned long data)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (test_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events)) {
|
if (test_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events)) {
|
||||||
stat |= MMC_STATUS;
|
stat |= readw(host->base + MMC_REG_STATUS);
|
||||||
if (imxmci_cpu_driven_data(host, &stat)) {
|
if (imxmci_cpu_driven_data(host, &stat)) {
|
||||||
if (test_and_clear_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events))
|
if (test_and_clear_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events))
|
||||||
imxmci_cmd_done(host, stat);
|
imxmci_cmd_done(host, stat);
|
||||||
|
@ -725,7 +750,7 @@ static void imxmci_tasklet_fnc(unsigned long data)
|
||||||
if (test_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events) &&
|
if (test_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events) &&
|
||||||
!test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events)) {
|
!test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events)) {
|
||||||
|
|
||||||
stat = MMC_STATUS;
|
stat = readw(host->base + MMC_REG_STATUS);
|
||||||
/* Same as above */
|
/* Same as above */
|
||||||
stat |= host->status_reg;
|
stat |= host->status_reg;
|
||||||
|
|
||||||
|
@ -813,6 +838,7 @@ static void imxmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
||||||
|
|
||||||
if (ios->clock) {
|
if (ios->clock) {
|
||||||
unsigned int clk;
|
unsigned int clk;
|
||||||
|
u16 reg;
|
||||||
|
|
||||||
/* The prescaler is 5 for PERCLK2 equal to 96MHz
|
/* The prescaler is 5 for PERCLK2 equal to 96MHz
|
||||||
* then 96MHz / 5 = 19.2 MHz
|
* then 96MHz / 5 = 19.2 MHz
|
||||||
|
@ -844,17 +870,22 @@ static void imxmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
MMC_STR_STP_CLK |= STR_STP_CLK_ENABLE; /* enable controller */
|
/* enable controller */
|
||||||
|
reg = readw(host->base + MMC_REG_STR_STP_CLK);
|
||||||
|
writew(reg | STR_STP_CLK_ENABLE,
|
||||||
|
host->base + MMC_REG_STR_STP_CLK);
|
||||||
|
|
||||||
imxmci_stop_clock(host);
|
imxmci_stop_clock(host);
|
||||||
MMC_CLK_RATE = (prescaler << 3) | clk;
|
writew((prescaler << 3) | clk, host->base + MMC_REG_CLK_RATE);
|
||||||
/*
|
/*
|
||||||
* Under my understanding, clock should not be started there, because it would
|
* Under my understanding, clock should not be started there, because it would
|
||||||
* initiate SDHC sequencer and send last or random command into card
|
* initiate SDHC sequencer and send last or random command into card
|
||||||
*/
|
*/
|
||||||
/* imxmci_start_clock(host); */
|
/* imxmci_start_clock(host); */
|
||||||
|
|
||||||
dev_dbg(mmc_dev(host->mmc), "MMC_CLK_RATE: 0x%08x\n", MMC_CLK_RATE);
|
dev_dbg(mmc_dev(host->mmc),
|
||||||
|
"MMC_CLK_RATE: 0x%08x\n",
|
||||||
|
readw(host->base + MMC_REG_CLK_RATE));
|
||||||
} else {
|
} else {
|
||||||
imxmci_stop_clock(host);
|
imxmci_stop_clock(host);
|
||||||
}
|
}
|
||||||
|
@ -913,6 +944,7 @@ static int imxmci_probe(struct platform_device *pdev)
|
||||||
struct imxmci_host *host = NULL;
|
struct imxmci_host *host = NULL;
|
||||||
struct resource *r;
|
struct resource *r;
|
||||||
int ret = 0, irq;
|
int ret = 0, irq;
|
||||||
|
u16 rev_no;
|
||||||
|
|
||||||
printk(KERN_INFO "i.MX mmc driver\n");
|
printk(KERN_INFO "i.MX mmc driver\n");
|
||||||
|
|
||||||
|
@ -921,7 +953,8 @@ static int imxmci_probe(struct platform_device *pdev)
|
||||||
if (!r || irq < 0)
|
if (!r || irq < 0)
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
|
|
||||||
if (!request_mem_region(r->start, 0x100, pdev->name))
|
r = request_mem_region(r->start, resource_size(r), pdev->name);
|
||||||
|
if (!r)
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
mmc = mmc_alloc_host(sizeof(struct imxmci_host), &pdev->dev);
|
mmc = mmc_alloc_host(sizeof(struct imxmci_host), &pdev->dev);
|
||||||
|
@ -945,6 +978,12 @@ static int imxmci_probe(struct platform_device *pdev)
|
||||||
mmc->max_blk_count = 65535;
|
mmc->max_blk_count = 65535;
|
||||||
|
|
||||||
host = mmc_priv(mmc);
|
host = mmc_priv(mmc);
|
||||||
|
host->base = ioremap(r->start, resource_size(r));
|
||||||
|
if (!host->base) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
host->mmc = mmc;
|
host->mmc = mmc;
|
||||||
host->dma_allocated = 0;
|
host->dma_allocated = 0;
|
||||||
host->pdata = pdev->dev.platform_data;
|
host->pdata = pdev->dev.platform_data;
|
||||||
|
@ -972,18 +1011,20 @@ static int imxmci_probe(struct platform_device *pdev)
|
||||||
imx_gpio_mode(PB12_PF_SD_CLK);
|
imx_gpio_mode(PB12_PF_SD_CLK);
|
||||||
imx_gpio_mode(PB13_PF_SD_CMD);
|
imx_gpio_mode(PB13_PF_SD_CMD);
|
||||||
|
|
||||||
imxmci_softreset();
|
imxmci_softreset(host);
|
||||||
|
|
||||||
if (MMC_REV_NO != 0x390) {
|
rev_no = readw(host->base + MMC_REG_REV_NO);
|
||||||
|
if (rev_no != 0x390) {
|
||||||
dev_err(mmc_dev(host->mmc), "wrong rev.no. 0x%08x. aborting.\n",
|
dev_err(mmc_dev(host->mmc), "wrong rev.no. 0x%08x. aborting.\n",
|
||||||
MMC_REV_NO);
|
readw(host->base + MMC_REG_REV_NO));
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
MMC_READ_TO = 0x2db4; /* recommended in data sheet */
|
/* recommended in data sheet */
|
||||||
|
writew(0x2db4, host->base + MMC_REG_READ_TO);
|
||||||
|
|
||||||
host->imask = IMXMCI_INT_MASK_DEFAULT;
|
host->imask = IMXMCI_INT_MASK_DEFAULT;
|
||||||
MMC_INT_MASK = host->imask;
|
writew(host->imask, host->base + MMC_REG_INT_MASK);
|
||||||
|
|
||||||
host->dma = imx_dma_request_by_prio(DRIVER_NAME, DMA_PRIO_LOW);
|
host->dma = imx_dma_request_by_prio(DRIVER_NAME, DMA_PRIO_LOW);
|
||||||
if(host->dma < 0) {
|
if(host->dma < 0) {
|
||||||
|
@ -1029,10 +1070,12 @@ static int imxmci_probe(struct platform_device *pdev)
|
||||||
clk_disable(host->clk);
|
clk_disable(host->clk);
|
||||||
clk_put(host->clk);
|
clk_put(host->clk);
|
||||||
}
|
}
|
||||||
|
if (host->base)
|
||||||
|
iounmap(host->base);
|
||||||
}
|
}
|
||||||
if (mmc)
|
if (mmc)
|
||||||
mmc_free_host(mmc);
|
mmc_free_host(mmc);
|
||||||
release_mem_region(r->start, 0x100);
|
release_mem_region(r->start, resource_size(r));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1051,6 +1094,7 @@ static int imxmci_remove(struct platform_device *pdev)
|
||||||
mmc_remove_host(mmc);
|
mmc_remove_host(mmc);
|
||||||
|
|
||||||
free_irq(host->irq, host);
|
free_irq(host->irq, host);
|
||||||
|
iounmap(host->base);
|
||||||
if (host->dma_allocated) {
|
if (host->dma_allocated) {
|
||||||
imx_dma_free(host->dma);
|
imx_dma_free(host->dma);
|
||||||
host->dma_allocated = 0;
|
host->dma_allocated = 0;
|
||||||
|
@ -1061,7 +1105,7 @@ static int imxmci_remove(struct platform_device *pdev)
|
||||||
clk_disable(host->clk);
|
clk_disable(host->clk);
|
||||||
clk_put(host->clk);
|
clk_put(host->clk);
|
||||||
|
|
||||||
release_mem_region(host->res->start, 0x100);
|
release_mem_region(host->res->start, resource_size(host->res));
|
||||||
|
|
||||||
mmc_free_host(mmc);
|
mmc_free_host(mmc);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,24 +1,21 @@
|
||||||
|
#define MMC_REG_STR_STP_CLK 0x00
|
||||||
|
#define MMC_REG_STATUS 0x04
|
||||||
|
#define MMC_REG_CLK_RATE 0x08
|
||||||
|
#define MMC_REG_CMD_DAT_CONT 0x0C
|
||||||
|
#define MMC_REG_RES_TO 0x10
|
||||||
|
#define MMC_REG_READ_TO 0x14
|
||||||
|
#define MMC_REG_BLK_LEN 0x18
|
||||||
|
#define MMC_REG_NOB 0x1C
|
||||||
|
#define MMC_REG_REV_NO 0x20
|
||||||
|
#define MMC_REG_INT_MASK 0x24
|
||||||
|
#define MMC_REG_CMD 0x28
|
||||||
|
#define MMC_REG_ARGH 0x2C
|
||||||
|
#define MMC_REG_ARGL 0x30
|
||||||
|
#define MMC_REG_RES_FIFO 0x34
|
||||||
|
#define MMC_REG_BUFFER_ACCESS 0x38
|
||||||
|
|
||||||
# define __REG16(x) (*((volatile u16 *)IO_ADDRESS(x)))
|
#define STR_STP_CLK_IPG_CLK_GATE_DIS (1<<15)
|
||||||
|
#define STR_STP_CLK_IPG_PERCLK_GATE_DIS (1<<14)
|
||||||
#define MMC_STR_STP_CLK __REG16(IMX_MMC_BASE + 0x00)
|
|
||||||
#define MMC_STATUS __REG16(IMX_MMC_BASE + 0x04)
|
|
||||||
#define MMC_CLK_RATE __REG16(IMX_MMC_BASE + 0x08)
|
|
||||||
#define MMC_CMD_DAT_CONT __REG16(IMX_MMC_BASE + 0x0C)
|
|
||||||
#define MMC_RES_TO __REG16(IMX_MMC_BASE + 0x10)
|
|
||||||
#define MMC_READ_TO __REG16(IMX_MMC_BASE + 0x14)
|
|
||||||
#define MMC_BLK_LEN __REG16(IMX_MMC_BASE + 0x18)
|
|
||||||
#define MMC_NOB __REG16(IMX_MMC_BASE + 0x1C)
|
|
||||||
#define MMC_REV_NO __REG16(IMX_MMC_BASE + 0x20)
|
|
||||||
#define MMC_INT_MASK __REG16(IMX_MMC_BASE + 0x24)
|
|
||||||
#define MMC_CMD __REG16(IMX_MMC_BASE + 0x28)
|
|
||||||
#define MMC_ARGH __REG16(IMX_MMC_BASE + 0x2C)
|
|
||||||
#define MMC_ARGL __REG16(IMX_MMC_BASE + 0x30)
|
|
||||||
#define MMC_RES_FIFO __REG16(IMX_MMC_BASE + 0x34)
|
|
||||||
#define MMC_BUFFER_ACCESS __REG16(IMX_MMC_BASE + 0x38)
|
|
||||||
#define MMC_BUFFER_ACCESS_OFS 0x38
|
|
||||||
|
|
||||||
|
|
||||||
#define STR_STP_CLK_ENDIAN (1<<5)
|
#define STR_STP_CLK_ENDIAN (1<<5)
|
||||||
#define STR_STP_CLK_RESET (1<<3)
|
#define STR_STP_CLK_RESET (1<<3)
|
||||||
#define STR_STP_CLK_ENABLE (1<<2)
|
#define STR_STP_CLK_ENABLE (1<<2)
|
||||||
|
|
Loading…
Reference in a new issue