From patchwork Mon Jun 13 19:56:56 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Brad Larson X-Patchwork-Id: 12880086 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id A0D11C433EF for ; Mon, 13 Jun 2022 20:16:04 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:List-Subscribe:List-Help: List-Post:List-Archive:List-Unsubscribe:List-Id:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=g2LqFbJ+ZPwburZgIb30VJGn6cBrQ7K1So8tOfEjI3k=; b=PwiPUt2Ahr4FjJ BbkI3/F79aRNjRTA8r61GJzHVQOT6YepEMSa0UEBMcxPw0B5LeZnj82NZUIXXPp1D8DiSX7+QrPRB R3Rt68Dmi21+QbPHU8+ObGYxeX9V1K/riVVl3i0Xmaga/90+4NIwM1xfrm1p0hkIrtfl+XLcCDlVN yzNFlrG03RTHXQ6vOp/Y8C/gU2Rmg3auFbwm0zBKSTgbdRySyxCXQcK+Alxnm+SvUc1joR/HPq3eO cNDP2Sv3Ir9J8CEBCvSReAAmLiz8DP32QKAVQUCUBeYdYJNihzYWDr//Um7qFJFvr0Zj6fsKjsd64 QV5/FWQct/3wJTKIDcAg==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1o0qSa-005XxB-T7; Mon, 13 Jun 2022 20:14:53 +0000 Received: from desiato.infradead.org ([2001:8b0:10b:1:d65d:64ff:fe57:4e05]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1o0qSH-005Xqe-Cy for linux-arm-kernel@bombadil.infradead.org; Mon, 13 Jun 2022 20:14:33 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=desiato.20200630; h=References:In-Reply-To:Message-Id:Date :Subject:Cc:To:From:Sender:Reply-To:MIME-Version:Content-Type: Content-Transfer-Encoding:Content-ID:Content-Description; bh=NyzDSLiO0lq4BsA02jWF6/uTinB+6H1C7pCNp978chk=; b=IMBF8sKyv8iVare78W9t/HYfsA l2nnDb2/Mgs2oTJjN9KAdgp9kFKe4w26N6Vbyh0ebu7MoLvJ++K7c+0gWNQUN00Ou81L3kfhXWm3Y 312mJYGPlKqtGYd2sbOQ5Dft/LX5u2A/htwjj2XocSPt9vqSPGXJh7BRYDrq9shCKR1rNx1DNbUfB 68GxORI3FjIbOmIx71Xa6mqmFqZUSQhbx8XQ6fCIZ/naBhH4V5wUuFbTQoVA8+ip1b8U0B6AVjFlA NuukEsIMJJ0pIsFaSRwKXhpeKU+uhgxYIk6xEi5EiSI30VRTnREan+AkEMZIsCk03GaZtx/gT4kuw BzMqYDxw==; Received: from mail-pj1-x102c.google.com ([2607:f8b0:4864:20::102c]) by desiato.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1o0qC8-007euB-1w for linux-arm-kernel@lists.infradead.org; Mon, 13 Jun 2022 19:57:56 +0000 Received: by mail-pj1-x102c.google.com with SMTP id z14so1815413pjb.4 for ; Mon, 13 Jun 2022 12:57:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pensando.io; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=NyzDSLiO0lq4BsA02jWF6/uTinB+6H1C7pCNp978chk=; b=ZmIcykGkPOVNDIZYaCnElS3kYgIFKxs4S+qJ/poIE9evHsNexrAS3suynT0z0YORse KC5NqMHUfpSgKp1XO9Meg7G2JDHXqN+nT4uTTsGqKhNuA8q8TFPVXYXDgeaa49MowTXM cAqglgnT3ywDffzXS+3/Q+DlsGZCwMLANFe+y0spMlW21AvMiz6LMs9PAlAiTsgJ5F7r n7HMxdTjtajX4dGUuaM3iwNhHyRRSeWuImKjcY9e5wIaJxE70LcTokQfZTbTSjgK4nvQ 2JDDpZ91PSam7PRoWV97Dz1RySV6ZaNd95cqSjkJw6d3cT0+TU8YpkoIjw94JX+Fem06 TEYg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=NyzDSLiO0lq4BsA02jWF6/uTinB+6H1C7pCNp978chk=; b=7skx+5VJaQryQUyIoJf7cDQOo1o+twShsjhLvTbUgu4D+SQbiGBy4m2vGPmy7X08Xx jxYWVO093JfVq6WJUntwtU8zgUNISNMeVd9kgFT4bn9G0EwkLQ7/hUD8SGQ1qo6/vxAW lUgh4Yg0BdDSzaOTjMcgPQ/aaRZ6gsdGE/r2cBq1+Lj82/F07bCf0MAFc4/5G+Can5ln mnO97xbineLqnZrpT9OCARBrq5A+LOCtY9OeYr5OHZLadSqWVSiYTS5J1ExXa6XxI23u C3FSIf8bx8ABEAdfOd7hL7/5cLTy8IdiAyi9IiwzIwgoT5LqEtD9EADMRssTJyekvMTj E7BQ== X-Gm-Message-State: AJIora/k3LTugZi5qZkccQwtiYcR2jvwJ4CKVy0srGe+F1M0GePlaIaU /modDqm0g4XpHCPWGzoGIlT20f6UVOwIIw== X-Google-Smtp-Source: AGRyM1tJRB1G+7kpXPt5023UTrEaqvVR4vazG7LXSR8ND5eTFK0xKuaEvvCrSvRqmxqYaTDrCGEb+Q== X-Received: by 2002:a17:90a:fd92:b0:1e2:d731:9ad5 with SMTP id cx18-20020a17090afd9200b001e2d7319ad5mr386886pjb.199.1655150270023; Mon, 13 Jun 2022 12:57:50 -0700 (PDT) Received: from platform-dev1.pensando.io ([12.226.153.42]) by smtp.gmail.com with ESMTPSA id q21-20020a170902edd500b0016797c33b6csm5509357plk.116.2022.06.13.12.57.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 13 Jun 2022 12:57:49 -0700 (PDT) From: Brad Larson To: linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org, linux-mmc@vger.kernel.org, adrian.hunter@intel.com, alcooperx@gmail.com, andy.shevchenko@gmail.com, arnd@arndb.de, brad@pensando.io, blarson@amd.com, brijeshkumar.singh@amd.com, catalin.marinas@arm.com, gsomlo@gmail.com, gerg@linux-m68k.org, krzk@kernel.org, krzysztof.kozlowski+dt@linaro.org, lee.jones@linaro.org, broonie@kernel.org, yamada.masahiro@socionext.com, p.zabel@pengutronix.de, piotrs@cadence.com, p.yadav@ti.com, rdunlap@infradead.org, robh+dt@kernel.org, samuel@sholland.org, fancer.lancer@gmail.com, suravee.suthikulpanit@amd.com, thomas.lendacky@amd.com, ulf.hansson@linaro.org, will@kernel.org, devicetree@vger.kernel.org Subject: [PATCH v5 13/15] mmc: sdhci-cadence: Add AMD Pensando Elba SoC support Date: Mon, 13 Jun 2022 12:56:56 -0700 Message-Id: <20220613195658.5607-14-brad@pensando.io> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20220613195658.5607-1-brad@pensando.io> References: <20220613195658.5607-1-brad@pensando.io> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20220613_205752_391590_857D838F X-CRM114-Status: GOOD ( 25.49 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 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+linux-arm-kernel=archiver.kernel.org@lists.infradead.org From: Brad Larson Add support for AMD Pensando Elba SoC which explicitly controls byte-lane enables on writes. Add priv_write_l() which is used on Elba platforms for byte-lane control. Select MMC_SDHCI_IO_ACCESSORS for MMC_SDHCI_CADENCE which allows Elba SoC sdhci_elba_ops to overwrite the SDHCI IO memory accessors. Signed-off-by: Brad Larson --- drivers/mmc/host/Kconfig | 1 + drivers/mmc/host/sdhci-cadence.c | 179 ++++++++++++++++++++++++++++--- 2 files changed, 166 insertions(+), 14 deletions(-) diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index d6144978e32d..d0a66a74532e 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -243,6 +243,7 @@ config MMC_SDHCI_CADENCE tristate "SDHCI support for the Cadence SD/SDIO/eMMC controller" depends on MMC_SDHCI_PLTFM depends on OF + select MMC_SDHCI_IO_ACCESSORS help This selects the Cadence SD/SDIO/eMMC driver. diff --git a/drivers/mmc/host/sdhci-cadence.c b/drivers/mmc/host/sdhci-cadence.c index 6f2de54a5987..08253357535a 100644 --- a/drivers/mmc/host/sdhci-cadence.c +++ b/drivers/mmc/host/sdhci-cadence.c @@ -12,6 +12,7 @@ #include #include #include +#include #include "sdhci-pltfm.h" @@ -66,7 +67,12 @@ struct sdhci_cdns_phy_param { struct sdhci_cdns_priv { void __iomem *hrs_addr; + void __iomem *ctl_addr; /* write control */ + spinlock_t wrlock; /* write lock */ bool enhanced_strobe; + void (*priv_write_l)(struct sdhci_cdns_priv *priv, u32 val, + void __iomem *reg); + struct reset_control *rst_hw; unsigned int nr_phy_params; struct sdhci_cdns_phy_param phy_params[]; }; @@ -76,6 +82,11 @@ struct sdhci_cdns_phy_cfg { u8 addr; }; +struct sdhci_cdns_drv_data { + int (*init)(struct platform_device *pdev); + const struct sdhci_pltfm_data pltfm_data; +}; + static const struct sdhci_cdns_phy_cfg sdhci_cdns_phy_cfgs[] = { { "cdns,phy-input-delay-sd-highspeed", SDHCI_CDNS_PHY_DLY_SD_HS, }, { "cdns,phy-input-delay-legacy", SDHCI_CDNS_PHY_DLY_SD_DEFAULT, }, @@ -90,6 +101,15 @@ static const struct sdhci_cdns_phy_cfg sdhci_cdns_phy_cfgs[] = { { "cdns,phy-dll-delay-strobe", SDHCI_CDNS_PHY_DLY_STROBE, }, }; +static inline void sdhci_cdns_priv_writel(struct sdhci_cdns_priv *priv, + u32 val, void __iomem *reg) +{ + if (unlikely(priv->priv_write_l)) + priv->priv_write_l(priv, val, reg); + else + writel(val, reg); +} + static int sdhci_cdns_write_phy_reg(struct sdhci_cdns_priv *priv, u8 addr, u8 data) { @@ -104,17 +124,17 @@ static int sdhci_cdns_write_phy_reg(struct sdhci_cdns_priv *priv, tmp = FIELD_PREP(SDHCI_CDNS_HRS04_WDATA, data) | FIELD_PREP(SDHCI_CDNS_HRS04_ADDR, addr); - writel(tmp, reg); + sdhci_cdns_priv_writel(priv, tmp, reg); tmp |= SDHCI_CDNS_HRS04_WR; - writel(tmp, reg); + sdhci_cdns_priv_writel(priv, tmp, reg); ret = readl_poll_timeout(reg, tmp, tmp & SDHCI_CDNS_HRS04_ACK, 0, 10); if (ret) return ret; tmp &= ~SDHCI_CDNS_HRS04_WR; - writel(tmp, reg); + sdhci_cdns_priv_writel(priv, tmp, reg); ret = readl_poll_timeout(reg, tmp, !(tmp & SDHCI_CDNS_HRS04_ACK), 0, 10); @@ -191,7 +211,7 @@ static void sdhci_cdns_set_emmc_mode(struct sdhci_cdns_priv *priv, u32 mode) tmp = readl(priv->hrs_addr + SDHCI_CDNS_HRS06); tmp &= ~SDHCI_CDNS_HRS06_MODE; tmp |= FIELD_PREP(SDHCI_CDNS_HRS06_MODE, mode); - writel(tmp, priv->hrs_addr + SDHCI_CDNS_HRS06); + sdhci_cdns_priv_writel(priv, tmp, priv->hrs_addr + SDHCI_CDNS_HRS06); } static u32 sdhci_cdns_get_emmc_mode(struct sdhci_cdns_priv *priv) @@ -223,7 +243,7 @@ static int sdhci_cdns_set_tune_val(struct sdhci_host *host, unsigned int val) */ for (i = 0; i < 2; i++) { tmp |= SDHCI_CDNS_HRS06_TUNE_UP; - writel(tmp, reg); + sdhci_cdns_priv_writel(priv, tmp, reg); ret = readl_poll_timeout(reg, tmp, !(tmp & SDHCI_CDNS_HRS06_TUNE_UP), @@ -309,6 +329,89 @@ static void sdhci_cdns_set_uhs_signaling(struct sdhci_host *host, sdhci_set_uhs_signaling(host, timing); } +/* + * The Pensando Elba SoC explicitly controls byte-lane enables on writes + * which includes writes to the HRS registers. + */ +static void elba_priv_write_l(struct sdhci_cdns_priv *priv, u32 val, + void __iomem *reg) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->wrlock, flags); + writel(0x78, priv->ctl_addr); + writel(val, reg); + spin_unlock_irqrestore(&priv->wrlock, flags); +} + +static void elba_write_l(struct sdhci_host *host, u32 val, int reg) +{ + elba_priv_write_l(sdhci_cdns_priv(host), val, host->ioaddr + reg); +} + +static void elba_write_w(struct sdhci_host *host, u16 val, int reg) +{ + struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host); + unsigned long flags; + u32 m = (reg & 0x3); + u32 msk = (0x3 << (m)); + + spin_lock_irqsave(&priv->wrlock, flags); + writel(msk << 3, priv->ctl_addr); + writew(val, host->ioaddr + reg); + spin_unlock_irqrestore(&priv->wrlock, flags); +} + +static void elba_write_b(struct sdhci_host *host, u8 val, int reg) +{ + struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host); + unsigned long flags; + u32 m = (reg & 0x3); + u32 msk = (0x1 << (m)); + + spin_lock_irqsave(&priv->wrlock, flags); + writel(msk << 3, priv->ctl_addr); + writeb(val, host->ioaddr + reg); + spin_unlock_irqrestore(&priv->wrlock, flags); +} + +static const struct sdhci_ops sdhci_elba_ops = { + .write_l = elba_write_l, + .write_w = elba_write_w, + .write_b = elba_write_b, + .set_clock = sdhci_set_clock, + .get_timeout_clock = sdhci_cdns_get_timeout_clock, + .set_bus_width = sdhci_set_bus_width, + .reset = sdhci_reset, + .set_uhs_signaling = sdhci_cdns_set_uhs_signaling, +}; + +static int elba_drv_init(struct platform_device *pdev) +{ + struct sdhci_host *host = platform_get_drvdata(pdev); + struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host); + struct resource *iomem; + void __iomem *ioaddr; + + host->mmc->caps |= (MMC_CAP_1_8V_DDR | MMC_CAP_8_BIT_DATA); + + iomem = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!iomem) + return -ENOMEM; + + /* Byte-lane control register */ + ioaddr = devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(ioaddr)) + return PTR_ERR(ioaddr); + + priv->ctl_addr = ioaddr; + priv->priv_write_l = elba_priv_write_l; + spin_lock_init(&priv->wrlock); + writel(0x78, priv->ctl_addr); + + return 0; +} + static const struct sdhci_ops sdhci_cdns_ops = { .set_clock = sdhci_set_clock, .get_timeout_clock = sdhci_cdns_get_timeout_clock, @@ -318,15 +421,27 @@ static const struct sdhci_ops sdhci_cdns_ops = { .set_uhs_signaling = sdhci_cdns_set_uhs_signaling, }; -static const struct sdhci_pltfm_data sdhci_cdns_uniphier_pltfm_data = { - .ops = &sdhci_cdns_ops, - .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, +static const struct sdhci_cdns_drv_data sdhci_cdns_uniphier_drv_data = { + .pltfm_data = { + .ops = &sdhci_cdns_ops, + .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, + }, }; -static const struct sdhci_pltfm_data sdhci_cdns_pltfm_data = { - .ops = &sdhci_cdns_ops, +static const struct sdhci_cdns_drv_data sdhci_elba_drv_data = { + .init = elba_drv_init, + .pltfm_data = { + .ops = &sdhci_elba_ops, + }, }; +static const struct sdhci_cdns_drv_data sdhci_cdns_drv_data = { + .pltfm_data = { + .ops = &sdhci_cdns_ops, + }, +}; + + static void sdhci_cdns_hs400_enhanced_strobe(struct mmc_host *mmc, struct mmc_ios *ios) { @@ -347,10 +462,26 @@ static void sdhci_cdns_hs400_enhanced_strobe(struct mmc_host *mmc, SDHCI_CDNS_HRS06_MODE_MMC_HS400); } +static void sdhci_mmc_hw_reset(struct mmc_host *mmc) +{ + struct sdhci_host *host = mmc_priv(mmc); + struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host); + + dev_info(mmc_dev(host->mmc), "emmc hardware reset\n"); + + reset_control_assert(priv->rst_hw); + /* For eMMC, minimum is 1us but give it 9us for good measure */ + udelay(9); + + reset_control_deassert(priv->rst_hw); + /* For eMMC, minimum is 200us but give it 300us for good measure */ + usleep_range(300, 1000); +} + static int sdhci_cdns_probe(struct platform_device *pdev) { struct sdhci_host *host; - const struct sdhci_pltfm_data *data; + const struct sdhci_cdns_drv_data *data; struct sdhci_pltfm_host *pltfm_host; struct sdhci_cdns_priv *priv; struct clk *clk; @@ -369,10 +500,10 @@ static int sdhci_cdns_probe(struct platform_device *pdev) data = of_device_get_match_data(dev); if (!data) - data = &sdhci_cdns_pltfm_data; + data = &sdhci_cdns_drv_data; nr_phy_params = sdhci_cdns_phy_param_count(dev->of_node); - host = sdhci_pltfm_init(pdev, data, + host = sdhci_pltfm_init(pdev, &data->pltfm_data, struct_size(priv, phy_params, nr_phy_params)); if (IS_ERR(host)) { ret = PTR_ERR(host); @@ -389,6 +520,11 @@ static int sdhci_cdns_probe(struct platform_device *pdev) host->ioaddr += SDHCI_CDNS_SRS_BASE; host->mmc_host_ops.hs400_enhanced_strobe = sdhci_cdns_hs400_enhanced_strobe; + if (data->init) { + ret = data->init(pdev); + if (ret) + goto free; + } sdhci_enable_v4_mode(host); __sdhci_read_caps(host, &version, NULL, NULL); @@ -404,6 +540,17 @@ static int sdhci_cdns_probe(struct platform_device *pdev) if (ret) goto free; + if (host->mmc->caps & MMC_CAP_HW_RESET) { + priv->rst_hw = devm_reset_control_get_optional_exclusive(dev, "hw"); + if (IS_ERR(priv->rst_hw)) { + ret = PTR_ERR(priv->rst_hw); + if (ret == -ENOENT) + priv->rst_hw = NULL; + } else { + host->mmc_host_ops.card_hw_reset = sdhci_mmc_hw_reset; + } + } + ret = sdhci_add_host(host); if (ret) goto free; @@ -453,7 +600,11 @@ static const struct dev_pm_ops sdhci_cdns_pm_ops = { static const struct of_device_id sdhci_cdns_match[] = { { .compatible = "socionext,uniphier-sd4hc", - .data = &sdhci_cdns_uniphier_pltfm_data, + .data = &sdhci_cdns_uniphier_drv_data, + }, + { + .compatible = "amd,pensando-elba-sd4hc", + .data = &sdhci_elba_drv_data }, { .compatible = "cdns,sd4hc" }, { /* sentinel */ }