summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Jin <Jason.jin@freescale.com>2012-08-10 18:23:10 +0800
committerJustin Waters <justin.waters@timesys.com>2012-09-12 16:50:07 -0400
commite4204d37dfbfae5e176f6564242f33e7a7b59fe2 (patch)
treed92cc6ba77c1fe23003dbd3c541c734bf9a80bd7
parent8b207089bcbf20474355e29395e5631f96886c66 (diff)
ENGR00212262-3: Faraday:Enable the ADMA2 function for SDHC
This patch enable the ADMA2 function for the SDHC module used on Faraday board. Please note that the ADMA address should be 16 bytes aligned other than 4 byte in the spec. This patch also increased the SDHC module frequency to 200MHz. Signed-off-by: Jason Jin <Jason.jin@freescale.com>
-rw-r--r--arch/arm/mach-mvf/clock.c2
-rw-r--r--drivers/mmc/host/sdhci-esdhc-imx.c16
-rwxr-xr-xdrivers/mmc/host/sdhci.c47
3 files changed, 45 insertions, 20 deletions
diff --git a/arch/arm/mach-mvf/clock.c b/arch/arm/mach-mvf/clock.c
index 71c51d5230c0..29cc445fc799 100644
--- a/arch/arm/mach-mvf/clock.c
+++ b/arch/arm/mach-mvf/clock.c
@@ -1727,7 +1727,7 @@ int __init mvf_clocks_init(unsigned long ckil, unsigned long osc,
/*clk_set_parent(&enet_clk, &pll5_enet_main_clk);*/
clk_set_parent(&esdhc1_clk, &pll1_pfd3_396M);
- clk_set_rate(&esdhc1_clk, 100000000);
+ clk_set_rate(&esdhc1_clk, 200000000);
clk_set_parent(&dcu0_clk, &pll1_pfd2_452M);
clk_set_rate(&dcu0_clk, 113000000);
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 2296eb8d1c18..3dcfcb043ef0 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -134,6 +134,16 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
val |= SDHCI_CARD_PRESENT;
}
+ if (reg == SDHCI_CAPABILITIES && cpu_is_mvf())
+ {
+ if (val & SDHCI_CAN_DO_ADMA1) {
+ u32 tmp = readl(host->ioaddr + SDHCI_SLOT_INT_STATUS);
+ tmp = (tmp & SDHCI_VENDOR_VER_MASK) >> SDHCI_VENDOR_VER_SHIFT;
+ if (tmp >= 0x12)
+ val |= SDHCI_CAN_DO_ADMA2;
+ }
+ }
+
if (reg == SDHCI_INT_STATUS && cpu_is_mx6()
&& mx6q_revision() == IMX_CHIP_REVISION_1_0) {
/*
@@ -786,10 +796,16 @@ static void esdhc_pltfm_exit(struct sdhci_host *host)
}
struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
+#ifdef CONFIG_ARCH_MVF
+ .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_CARD_DETECTION
+ | SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_NO_CARD_NO_RESET
+ | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC,
+#else
.quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_ADMA
| SDHCI_QUIRK_BROKEN_CARD_DETECTION
| SDHCI_QUIRK_NO_HISPD_BIT,
/* ADMA has issues. Might be fixable */
+#endif
.ops = &sdhci_esdhc_ops,
.init = esdhc_pltfm_init,
.exit = esdhc_pltfm_exit,
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 82afe0522ecc..189dff37e84e 100755
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -2,6 +2,7 @@
* linux/drivers/mmc/host/sdhci.c - Secure Digital Host Controller Interface driver
*
* Copyright (C) 2005-2011 Pierre Ossman, All Rights Reserved.
+ * Copyright 2012 Freescale Semiconductor, Inc.
*
* 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
@@ -42,6 +43,12 @@
#define MAX_TUNING_LOOP 40
+#ifdef CONFIG_ARCH_MVF
+#define ADDR_ALIGNED 0xF
+#else
+#define ADDR_ALIGNED 0x3
+#endif
+
static unsigned int debug_quirks = 0;
static void sdhci_finish_data(struct sdhci_host *);
@@ -497,10 +504,10 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
*/
host->align_addr = dma_map_single(mmc_dev(host->mmc),
- host->align_buffer, 128 * 4, direction);
+ host->align_buffer, 128 * (ADDR_ALIGNED + 1), direction);
if (dma_mapping_error(mmc_dev(host->mmc), host->align_addr))
goto fail;
- BUG_ON(host->align_addr & 0x3);
+ BUG_ON(host->align_addr & ADDR_ALIGNED);
host->sg_count = dma_map_sg(mmc_dev(host->mmc),
data->sg, data->sg_len, direction);
@@ -523,22 +530,22 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
* the (up to three) bytes that screw up the
* alignment.
*/
- offset = (4 - (addr & 0x3)) & 0x3;
+ offset = ((ADDR_ALIGNED + 1) - (addr & ADDR_ALIGNED)) & ADDR_ALIGNED;
if (offset) {
if (data->flags & MMC_DATA_WRITE) {
buffer = sdhci_kmap_atomic(sg, &flags);
- WARN_ON(((long)buffer & PAGE_MASK) > (PAGE_SIZE - 3));
+ WARN_ON(((long)buffer & PAGE_MASK) > (PAGE_SIZE - ADDR_ALIGNED));
memcpy(align, buffer, offset);
sdhci_kunmap_atomic(buffer, &flags);
}
/* tran, valid */
- sdhci_set_adma_desc(desc, align_addr, offset, 0x21);
+ sdhci_set_adma_desc(desc, align_addr, (len - offset) ? offset : len, 0x21);
BUG_ON(offset > 65536);
- align += 4;
- align_addr += 4;
+ align += (ADDR_ALIGNED + 1);
+ align_addr += (ADDR_ALIGNED + 1);
desc += 8;
@@ -549,8 +556,10 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
BUG_ON(len > 65536);
/* tran, valid */
- sdhci_set_adma_desc(desc, addr, len, 0x21);
- desc += 8;
+ if (len > 0) {
+ sdhci_set_adma_desc(desc, addr, len, 0x21);
+ desc += 8;
+ }
/*
* If this triggers then we have a calculation bug
@@ -581,14 +590,14 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
*/
if (data->flags & MMC_DATA_WRITE) {
dma_sync_single_for_device(mmc_dev(host->mmc),
- host->align_addr, 128 * 4, direction);
+ host->align_addr, 128 * (ADDR_ALIGNED + 1), direction);
}
host->adma_addr = dma_map_single(mmc_dev(host->mmc),
host->adma_desc, (128 * 2 + 1) * 4, DMA_TO_DEVICE);
if (dma_mapping_error(mmc_dev(host->mmc), host->adma_addr))
goto unmap_entries;
- BUG_ON(host->adma_addr & 0x3);
+ BUG_ON(host->adma_addr & ADDR_ALIGNED);
return 0;
@@ -597,7 +606,7 @@ unmap_entries:
data->sg_len, direction);
unmap_align:
dma_unmap_single(mmc_dev(host->mmc), host->align_addr,
- 128 * 4, direction);
+ 128 * (ADDR_ALIGNED + 1), direction);
fail:
return -EINVAL;
}
@@ -622,7 +631,7 @@ static void sdhci_adma_table_post(struct sdhci_host *host,
(128 * 2 + 1) * 4, DMA_TO_DEVICE);
dma_unmap_single(mmc_dev(host->mmc), host->align_addr,
- 128 * 4, direction);
+ 128 * (ADDR_ALIGNED + 1), direction);
if (data->flags & MMC_DATA_READ) {
dma_sync_sg_for_cpu(mmc_dev(host->mmc), data->sg,
@@ -631,15 +640,15 @@ static void sdhci_adma_table_post(struct sdhci_host *host,
align = host->align_buffer;
for_each_sg(data->sg, sg, host->sg_count, i) {
- if (sg_dma_address(sg) & 0x3) {
- size = 4 - (sg_dma_address(sg) & 0x3);
+ if (sg_dma_address(sg) & ADDR_ALIGNED) {
+ size = (ADDR_ALIGNED + 1) - (sg_dma_address(sg) & ADDR_ALIGNED);
buffer = sdhci_kmap_atomic(sg, &flags);
- WARN_ON(((long)buffer & PAGE_MASK) > (PAGE_SIZE - 3));
- memcpy(buffer, align, size);
+ WARN_ON(((long)buffer & PAGE_MASK) > (PAGE_SIZE - ADDR_ALIGNED));
+ memcpy(buffer, align, (size - data->sg->length) ? data->sg->length : size);
sdhci_kunmap_atomic(buffer, &flags);
- align += 4;
+ align += (ADDR_ALIGNED + 1);
}
}
}
@@ -2559,7 +2568,7 @@ int sdhci_add_host(struct sdhci_host *host)
* each of those entries.
*/
host->adma_desc = kmalloc((128 * 2 + 1) * 4, GFP_KERNEL);
- host->align_buffer = kmalloc(128 * 4, GFP_KERNEL);
+ host->align_buffer = kmalloc(128 * (ADDR_ALIGNED + 1), GFP_KERNEL);
if (!host->adma_desc || !host->align_buffer) {
kfree(host->adma_desc);
kfree(host->align_buffer);