From patchwork Tue Jun 3 21:13:04 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Loc Ho X-Patchwork-Id: 4290961 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 13D759F1D6 for ; Tue, 3 Jun 2014 21:16:12 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 17454201C0 for ; Tue, 3 Jun 2014 21:16:11 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 08942201C7 for ; Tue, 3 Jun 2014 21:16:10 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1Wrw26-00046R-DQ; Tue, 03 Jun 2014 21:14:10 +0000 Received: from exprod5og120.obsmtp.com ([64.18.0.137]) by bombadil.infradead.org with smtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1Wrw22-0003xn-U9 for linux-arm-kernel@lists.infradead.org; Tue, 03 Jun 2014 21:14:07 +0000 Received: from mail-pd0-f180.google.com ([209.85.192.180]) (using TLSv1) by exprod5ob120.postini.com ([64.18.4.12]) with SMTP ID DSNKU446io/t5TAP7w8hy93oS2ecjts6dSc7@postini.com; Tue, 03 Jun 2014 14:14:06 PDT Received: by mail-pd0-f180.google.com with SMTP id y13so5164519pdi.39 for ; Tue, 03 Jun 2014 14:13:46 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=CBH7yY3H8Grrnfpyge4o5IMf6AqLX5rUomUcg/so8Hc=; b=EW9BneQGtGAXVoM3sYhr8jSQ8rXfbzsaOEY0M4Y/ZcsnUxptxcCvr3pkWjQxAKr+UT nw9jtYibUYWR4dSQpVfgK/y8paMy1ZG+PCvxYk+pUCSzcmNxhGrLHCL1Nd36qqL55GDg UJ8sGcPnuAINJn9V2cw+NkFTTWZmv4AK37KzZa7JqRclhUDfg/n3Rm2BA1uTYkNaYFdQ xbQTRi/OaUxJDir0rPIUBfy/rGZih+Wnlajz/zpA92NWP9FmhENfSmVt8U3vm2pNLbJQ r/njUQcY5SJr1uluRfJ5H8xdaK/zxevZ0ZnvQVYCTNYwIaWECYCGxOKOFxwHkY/pCHDT 9uRA== X-Gm-Message-State: ALoCoQn1Z7VhGtimJLC9oxl+Aq1iGT5RduMcOpE+b/qYISS6vnfYVHIgykuXRbZtMiiijo12wNf9HxVFTGB1qxcQUHziQ93BDI/HR+Gd+8OtrP9Q8G+Aq19FAG+cxOaRqsQYAfT8pTucyIS85O/lkJS9EDSeqpB4rg== X-Received: by 10.69.20.10 with SMTP id gy10mr55162481pbd.162.1401830025962; Tue, 03 Jun 2014 14:13:45 -0700 (PDT) X-Received: by 10.69.20.10 with SMTP id gy10mr55162444pbd.162.1401830025694; Tue, 03 Jun 2014 14:13:45 -0700 (PDT) Received: from localhost ([198.137.200.11]) by mx.google.com with ESMTPSA id ib5sm1192235pbb.55.2014.06.03.14.13.44 for (version=TLSv1 cipher=RC4-SHA bits=128/128); Tue, 03 Jun 2014 14:13:45 -0700 (PDT) From: Loc Ho To: chris@printf.net, ulf.hansson@linaro.org, michal.simek@xilinx.com Subject: [PATCH v2 2/3] mmc: Add APM X-Gene SoC SDHC controller support to Arasan SDHCI driver Date: Tue, 3 Jun 2014 15:13:04 -0600 Message-Id: <1401829985-5212-3-git-send-email-lho@apm.com> X-Mailer: git-send-email 1.5.5 In-Reply-To: <1401829985-5212-2-git-send-email-lho@apm.com> References: <1401829985-5212-1-git-send-email-lho@apm.com> <1401829985-5212-2-git-send-email-lho@apm.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140603_141407_030365_CC76323C X-CRM114-Status: GOOD ( 21.61 ) X-Spam-Score: -2.3 (--) Cc: devicetree@vger.kernel.org, linux-mmc@vger.kernel.org, patches@apm.com, Loc Ho , jcm@redhat.com, linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-2.5 required=5.0 tests=BAYES_00,RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This patch adds support for the APM X-Gene SoC SDHC controller to Arasan SDHCI driver. Signed-off-by: Loc Ho --- drivers/mmc/host/Kconfig | 4 +- drivers/mmc/host/sdhci-of-arasan.c | 126 +++++++++++++++++++++++++++++++++--- 2 files changed, 120 insertions(+), 10 deletions(-) diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 8aaf8c1..7ec5414 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -108,9 +108,11 @@ config MMC_SDHCI_OF_ARASAN tristate "SDHCI OF support for the Arasan SDHCI controllers" depends on MMC_SDHCI_PLTFM depends on OF + select MMC_SDHCI_IO_ACCESSORS help This selects the Arasan Secure Digital Host Controller Interface - (SDHCI). This hardware is found e.g. in Xilinx' Zynq SoC. + (SDHCI). This hardware is found e.g. in Xilinx' Zynq and X-Gene + SoC. If you have a controller with this interface, say Y or M here. diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c index f7c7cf6..4f1313c 100644 --- a/drivers/mmc/host/sdhci-of-arasan.c +++ b/drivers/mmc/host/sdhci-of-arasan.c @@ -20,6 +20,8 @@ */ #include +#include +#include #include "sdhci-pltfm.h" #define SDHCI_ARASAN_CLK_CTRL_OFFSET 0x2c @@ -34,6 +36,19 @@ */ struct sdhci_arasan_data { struct clk *clk_ahb; + struct platform_device *pdev; + void __iomem *ahb_aim_csr; + const struct sdhci_arasan_ahb_ops *ahb_ops; +}; + +/** + * struct sdhci_arasan_ahb_ops + * @init_ahb Initialize translation bus + * @xlat_addr Set up an 64-bit addressing translation + */ +struct sdhci_arasan_ahb_ops { + int (*init_ahb)(struct sdhci_arasan_data *data); + void (*xlat_addr)(struct sdhci_arasan_data *data, u64 dma_addr); }; static unsigned int sdhci_arasan_get_timeout_clock(struct sdhci_host *host) @@ -51,7 +66,21 @@ static unsigned int sdhci_arasan_get_timeout_clock(struct sdhci_host *host) return freq; } +static void sdhci_arasan_writel(struct sdhci_host *host, u32 val, int reg) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_arasan_data *sdhci_arasan = pltfm_host->priv; + + if (reg == SDHCI_DMA_ADDRESS) { + if (sdhci_arasan->ahb_ops && sdhci_arasan->ahb_ops->xlat_addr) + sdhci_arasan->ahb_ops->xlat_addr(sdhci_arasan, + sg_dma_address(host->data->sg)); + } + writel(val, host->ioaddr + reg); +} + static struct sdhci_ops sdhci_arasan_ops = { + .write_l = sdhci_arasan_writel, .get_max_clock = sdhci_pltfm_clk_get_max_clock, .get_timeout_clock = sdhci_arasan_get_timeout_clock, }; @@ -121,13 +150,83 @@ static int sdhci_arasan_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(sdhci_arasan_dev_pm_ops, sdhci_arasan_suspend, sdhci_arasan_resume); +static int sdhci_arasan_xgene_init_ahb(struct sdhci_arasan_data *data) +{ + #define AIM_SIZE_CTL_OFFSET 0x00000004 + #define AIM_EN_N_WR(src) (((u32) (src) << 31) & 0x80000000) + #define ARSB_WR(src) (((u32) (src) << 24) & 0x0f000000) + #define AWSB_WR(src) (((u32) (src) << 20) & 0x00f00000) + #define AIM_MASK_N_WR(src) (((u32) (src)) & 0x000fffff) + + struct sdhci_host *host = platform_get_drvdata(data->pdev); + int ret; + + if (!data->ahb_aim_csr) + return 0; + + /* + * Setup AHB AIM windows ctrl register. The lower 32-bit is left + * at 0 while the upper bit are programmed when the buffer address + ( is set from function sdhci_arasn_writel. + */ + writel(AIM_EN_N_WR(1) | ARSB_WR(1) | AWSB_WR(1) | AIM_MASK_N_WR(0), + data->ahb_aim_csr + AIM_SIZE_CTL_OFFSET); + + /* Set DMA mask */ + ret = dma_set_mask_and_coherent(&data->pdev->dev, DMA_BIT_MASK(64)); + if (ret) { + dev_err(&data->pdev->dev, "Unable to set dma mask\n"); + return ret; + } + + /* + * This shouldn't be necessary. Just in case the FW doesn't + * configure disable ADMA support as we can't support multiple + * DMA buffer whose address is 64-bit. The AHB translation bridge + * only has 8 entry max and that is required to be shared and + * upper layer can pass more than 8 buffer pointers. + */ + host->quirks |= SDHCI_QUIRK_BROKEN_ADMA; + + return 0; +} + +static void sdhci_arasn_xgene_xlat_addr(struct sdhci_arasan_data *data, + u64 dma_addr) +{ + #define AIM_AXI_HI_OFFSET 0x0000000c + #define AIM_AXI_ADDRESS_HI_N_WR(src) \ + (((u32) (src) << 20) & 0xfff00000) + + if (!data->ahb_aim_csr) + return; + + writel(AIM_AXI_ADDRESS_HI_N_WR(dma_addr >> 32), + data->ahb_aim_csr + AIM_AXI_HI_OFFSET); +} + +static const struct sdhci_arasan_ahb_ops xgene_ahb_ops = { + .init_ahb = sdhci_arasan_xgene_init_ahb, + .xlat_addr = sdhci_arasn_xgene_xlat_addr, +}; + +static const struct of_device_id sdhci_arasan_of_match[] = { + { .compatible = "arasan,sdhci-8.9a" }, + { .compatible = "apm,arasan,sdhci-8.9a", .data = &xgene_ahb_ops }, + { } +}; +MODULE_DEVICE_TABLE(of, sdhci_arasan_of_match); + static int sdhci_arasan_probe(struct platform_device *pdev) { int ret; - struct clk *clk_xin; + struct clk *clk_xin = NULL; struct sdhci_host *host; struct sdhci_pltfm_host *pltfm_host; struct sdhci_arasan_data *sdhci_arasan; + const struct of_device_id *of_id = + of_match_device(sdhci_arasan_of_match, &pdev->dev); + struct resource *res; sdhci_arasan = devm_kzalloc(&pdev->dev, sizeof(*sdhci_arasan), GFP_KERNEL); @@ -136,8 +235,9 @@ static int sdhci_arasan_probe(struct platform_device *pdev) sdhci_arasan->clk_ahb = devm_clk_get(&pdev->dev, "clk_ahb"); if (IS_ERR(sdhci_arasan->clk_ahb)) { - dev_err(&pdev->dev, "clk_ahb clock not found.\n"); - return PTR_ERR(sdhci_arasan->clk_ahb); + /* Clock is optional */ + sdhci_arasan->clk_ahb = NULL; + goto skip_clk; } clk_xin = devm_clk_get(&pdev->dev, "clk_xin"); @@ -157,6 +257,7 @@ static int sdhci_arasan_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Unable to enable SD clock.\n"); goto clk_dis_ahb; } +skip_clk: host = sdhci_pltfm_init(pdev, &sdhci_arasan_pdata, 0); if (IS_ERR(host)) { @@ -170,6 +271,19 @@ static int sdhci_arasan_probe(struct platform_device *pdev) pltfm_host->priv = sdhci_arasan; pltfm_host->clk = clk_xin; + /* Retrieval optional AHB translation memory resource */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + sdhci_arasan->ahb_aim_csr = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + + sdhci_arasan->pdev = pdev; + sdhci_arasan->ahb_ops = of_id->data; + if (sdhci_arasan->ahb_ops && sdhci_arasan->ahb_ops->init_ahb) { + ret = sdhci_arasan->ahb_ops->init_ahb(sdhci_arasan); + if (ret) + goto err_pltfm_free; + } + ret = sdhci_add_host(host); if (ret) { dev_err(&pdev->dev, "platform register failed (%u)\n", ret); @@ -200,12 +314,6 @@ static int sdhci_arasan_remove(struct platform_device *pdev) return sdhci_pltfm_unregister(pdev); } -static const struct of_device_id sdhci_arasan_of_match[] = { - { .compatible = "arasan,sdhci-8.9a" }, - { } -}; -MODULE_DEVICE_TABLE(of, sdhci_arasan_of_match); - static struct platform_driver sdhci_arasan_driver = { .driver = { .name = "sdhci-arasan",