From patchwork Fri Jul 22 10:15:17 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Zang Roy-R61911 X-Patchwork-Id: 998502 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter2.kernel.org (8.14.4/8.14.4) with ESMTP id p6M9bHZ3026912 for ; Fri, 22 Jul 2011 09:37:18 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753381Ab1GVJhQ (ORCPT ); Fri, 22 Jul 2011 05:37:16 -0400 Received: from ch1ehsobe006.messaging.microsoft.com ([216.32.181.186]:41601 "EHLO ch1outboundpool.messaging.microsoft.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752993Ab1GVJhP (ORCPT ); Fri, 22 Jul 2011 05:37:15 -0400 Received: from mail144-ch1-R.bigfish.com (216.32.181.172) by CH1EHSOBE006.bigfish.com (10.43.70.56) with Microsoft SMTP Server id 14.1.225.22; Fri, 22 Jul 2011 09:37:14 +0000 Received: from mail144-ch1 (localhost.localdomain [127.0.0.1]) by mail144-ch1-R.bigfish.com (Postfix) with ESMTP id 918CC10A83B1; Fri, 22 Jul 2011 09:37:14 +0000 (UTC) X-SpamScore: 0 X-BigFish: VS0(zzzz1202hzz8275bh8275dhz2dh2a8h668h839h62h) X-Spam-TCS-SCL: 1:0 X-Forefront-Antispam-Report: CIP:70.37.183.190; KIP:(null); UIP:(null); IPVD:NLI; H:mail.freescale.net; RD:none; EFVD:NLI Received: from mail144-ch1 (localhost.localdomain [127.0.0.1]) by mail144-ch1 (MessageSwitch) id 1311327404549461_30118; Fri, 22 Jul 2011 09:36:44 +0000 (UTC) Received: from CH1EHSMHS028.bigfish.com (snatpool1.int.messaging.microsoft.com [10.43.68.241]) by mail144-ch1.bigfish.com (Postfix) with ESMTP id C94C41C18135; Fri, 22 Jul 2011 09:35:58 +0000 (UTC) Received: from mail.freescale.net (70.37.183.190) by CH1EHSMHS028.bigfish.com (10.43.70.28) with Microsoft SMTP Server (TLS) id 14.1.225.22; Fri, 22 Jul 2011 09:35:58 +0000 Received: from az33smr01.freescale.net (10.64.34.199) by 039-SN1MMR1-001.039d.mgd.msft.net (10.84.1.13) with Microsoft SMTP Server id 14.1.289.8; Fri, 22 Jul 2011 04:35:57 -0500 Received: from localhost.localdomain (udp144289uds.ap.freescale.net [10.193.20.43]) by az33smr01.freescale.net (8.13.1/8.13.0) with ESMTP id p6M9ZoOf024558; Fri, 22 Jul 2011 04:35:54 -0500 (CDT) From: Roy Zang To: CC: , , , Xu lei , Roy Zang , Kumar Gala Subject: [PATCH 2/2 v2] eSDHC: Fix errors when booting kernel with fsl esdhc Date: Fri, 22 Jul 2011 18:15:17 +0800 Message-ID: <1311329717-13954-2-git-send-email-tie-fei.zang@freescale.com> X-Mailer: git-send-email 1.6.0.6 In-Reply-To: <1311329717-13954-1-git-send-email-tie-fei.zang@freescale.com> References: <1311329717-13954-1-git-send-email-tie-fei.zang@freescale.com> MIME-Version: 1.0 X-OriginatorOrg: freescale.com Sender: linux-mmc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-mmc@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter2.kernel.org [140.211.167.43]); Fri, 22 Jul 2011 09:37:18 +0000 (UTC) From: Xu lei When esdhc module was enabled in p5020, there were following errors: mmc0: Timeout waiting for hardware interrupt. mmc0: error -110 whilst initialising SD card mmc0: Unexpected interrupt 0x02000000. mmc0: Timeout waiting for hardware interrupt. mmc0: error -110 whilst initialising SD card mmc0: Unexpected interrupt 0x02000000. It is because ESDHC controller has different bit setting for PROCTL register, when kernel sets Power Control Register by method for standard SD Host Specification, it would overwritten FSL ESDHC PROCTL[DMAS]; when it set Host Control Registers[DMAS], it sets PROCTL[EMODE] and PROCTL[D3CD]. These operations will set bad bits for PROCTL Register on FSL ESDHC Controller and cause errors, so this patch will make esdhc driver access FSL PROCTL Register according to block guide instead of standard SD Host Specification. For some FSL chips, such as MPC8536/P2020, PROCTL[VOLT_SEL] and PROCTL[DMAS] bits are reserved and even if they are set to wrong bits there is no error. But considering that all FSL ESDHC Controller register map is not fully compliant to standard SD Host Specification, we put the patch to all of FSL ESDHC Controllers. Signed-off-by: Lei Xu Signed-off-by: Roy Zang Signed-off-by: Kumar Gala --- v2:v1 some minor code style fix according to Venkatraman's comment. drivers/mmc/host/sdhci-of-core.c | 3 ++ drivers/mmc/host/sdhci.c | 64 ++++++++++++++++++++++++++++++------- include/linux/mmc/sdhci.h | 6 ++- 3 files changed, 59 insertions(+), 14 deletions(-) diff --git a/drivers/mmc/host/sdhci-of-core.c b/drivers/mmc/host/sdhci-of-core.c index 60e4186..fede43d 100644 --- a/drivers/mmc/host/sdhci-of-core.c +++ b/drivers/mmc/host/sdhci-of-core.c @@ -179,6 +179,9 @@ static int __devinit sdhci_of_probe(struct platform_device *ofdev) if (sdhci_of_wp_inverted(np)) host->quirks |= SDHCI_QUIRK_INVERTED_WRITE_PROTECT; + if (of_device_is_compatible(np, "fsl,esdhc")) + host->quirks |= SDHCI_QUIRK_QORIQ_PROCTL_WEIRD; + clk = of_get_property(np, "clock-frequency", &size); if (clk && size == sizeof(*clk) && *clk) of_host->clock = be32_to_cpup(clk); diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 58d5436..855fbe8 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -674,7 +674,7 @@ static void sdhci_set_transfer_irqs(struct sdhci_host *host) static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) { u8 count; - u8 ctrl; + u32 ctrl; struct mmc_data *data = cmd->data; int ret; @@ -807,14 +807,28 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) * is ADMA. */ if (host->version >= SDHCI_SPEC_200) { - ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); - ctrl &= ~SDHCI_CTRL_DMA_MASK; - if ((host->flags & SDHCI_REQ_USE_DMA) && - (host->flags & SDHCI_USE_ADMA)) - ctrl |= SDHCI_CTRL_ADMA32; - else - ctrl |= SDHCI_CTRL_SDMA; - sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); + if (host->quirks & SDHCI_QUIRK_QORIQ_PROCTL_WEIRD) { +#define ESDHCI_PROCTL_DMAS_MASK 0x00000300 +#define ESDHCI_PROCTL_ADMA32 0x00000200 +#define ESDHCI_PROCTL_SDMA 0x00000000 + ctrl = sdhci_readl(host, SDHCI_HOST_CONTROL); + ctrl &= ~ESDHCI_PROCTL_DMAS_MASK; + if ((host->flags & SDHCI_REQ_USE_DMA) && + (host->flags & SDHCI_USE_ADMA)) + ctrl |= ESDHCI_PROCTL_ADMA32; + else + ctrl |= ESDHCI_PROCTL_SDMA; + sdhci_writel(host, ctrl, SDHCI_HOST_CONTROL); + } else { + ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); + ctrl &= ~SDHCI_CTRL_DMA_MASK; + if ((host->flags & SDHCI_REQ_USE_DMA) && + (host->flags & SDHCI_USE_ADMA)) + ctrl |= SDHCI_CTRL_ADMA32; + else + ctrl |= SDHCI_CTRL_SDMA; + sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); + } } if (!(host->flags & SDHCI_REQ_USE_DMA)) { @@ -1138,19 +1152,32 @@ out: static void sdhci_set_power(struct sdhci_host *host, unsigned short power) { u8 pwr = 0; + u8 volt = 0; if (power != (unsigned short)-1) { switch (1 << power) { +#define ESDHCI_FSL_POWER_MASK 0x40 +#define ESDHCI_FSL_POWER_180 0x00 +#define ESDHCI_FSL_POWER_300 0x40 case MMC_VDD_165_195: - pwr = SDHCI_POWER_180; + if (host->quirks & SDHCI_QUIRK_QORIQ_PROCTL_WEIRD) + pwr = ESDHCI_FSL_POWER_180; + else + pwr = SDHCI_POWER_180; break; case MMC_VDD_29_30: case MMC_VDD_30_31: - pwr = SDHCI_POWER_300; + if (host->quirks & SDHCI_QUIRK_QORIQ_PROCTL_WEIRD) + pwr = ESDHCI_FSL_POWER_300; + else + pwr = SDHCI_POWER_300; break; case MMC_VDD_32_33: case MMC_VDD_33_34: - pwr = SDHCI_POWER_330; + if (host->quirks & SDHCI_QUIRK_QORIQ_PROCTL_WEIRD) + pwr = ESDHCI_FSL_POWER_300; + else + pwr = SDHCI_POWER_330; break; default: BUG(); @@ -1162,6 +1189,19 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power) host->pwr = pwr; + /* + * FSL ESDHC Controller has no Bus Power bit, + * and PROCTL[21] bit is for voltage selection. + */ + if (host->quirks & SDHCI_QUIRK_QORIQ_PROCTL_WEIRD) { + volt = sdhci_readb(host, SDHCI_POWER_CONTROL); + volt &= ~ESDHCI_FSL_POWER_MASK; + volt |= pwr; + sdhci_writeb(host, volt, SDHCI_POWER_CONTROL); + + return; + } + if (pwr == 0) { sdhci_writeb(host, 0, SDHCI_POWER_CONTROL); return; diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h index 6a68c4e..d87abc7 100644 --- a/include/linux/mmc/sdhci.h +++ b/include/linux/mmc/sdhci.h @@ -21,7 +21,7 @@ struct sdhci_host { /* Data set by hardware interface driver */ const char *hw_name; /* Hardware bus name */ - unsigned int quirks; /* Deviations from spec. */ + u64 quirks; /* Deviations from spec. */ /* Controller doesn't honor resets unless we touch the clock register */ #define SDHCI_QUIRK_CLOCK_BEFORE_RESET (1<<0) @@ -86,7 +86,9 @@ struct sdhci_host { /* Controller treats ADMA descriptors with length 0000h incorrectly */ #define SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC (1<<30) /* The read-only detection via SDHCI_PRESENT_STATE register is unstable */ -#define SDHCI_QUIRK_UNSTABLE_RO_DETECT (1<<31) +#define SDHCI_QUIRK_UNSTABLE_RO_DETECT (1U<<31) +/* Controller has weird bit setting for Protocol Control Register */ +#define SDHCI_QUIRK_QORIQ_PROCTL_WEIRD (0x100000000U) int irq; /* Device IRQ */ void __iomem *ioaddr; /* Mapped address */