From patchwork Tue Feb 5 14:12:58 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Faiz Abbas X-Patchwork-Id: 1036790 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.denx.de (client-ip=81.169.180.215; helo=lists.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=quarantine dis=none) header.from=ti.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ti.com header.i=@ti.com header.b="H3jYj21Y"; dkim-atps=neutral Received: from lists.denx.de (dione.denx.de [81.169.180.215]) by ozlabs.org (Postfix) with ESMTP id 43v6BZ07Rnz9s4Z for ; Wed, 6 Feb 2019 01:18:45 +1100 (AEDT) Received: by lists.denx.de (Postfix, from userid 105) id B0FD8C21EBE; Tue, 5 Feb 2019 14:16:06 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=T_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id CEB71C21F64; Tue, 5 Feb 2019 14:10:44 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 059CCC21F94; Tue, 5 Feb 2019 14:10:41 +0000 (UTC) Received: from lelv0142.ext.ti.com (lelv0142.ext.ti.com [198.47.23.249]) by lists.denx.de (Postfix) with ESMTPS id 60120C21F6A for ; Tue, 5 Feb 2019 14:10:30 +0000 (UTC) Received: from fllv0035.itg.ti.com ([10.64.41.0]) by lelv0142.ext.ti.com (8.15.2/8.15.2) with ESMTP id x15EAOOi075033; Tue, 5 Feb 2019 08:10:24 -0600 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=ti-com-17Q1; t=1549375824; bh=NWaOw5sySmyMqUKuHUTlJcl7O58rvSP2kyHy4dKopw0=; h=From:To:CC:Subject:Date:In-Reply-To:References; b=H3jYj21YouJvKYXCs9mt6rqQ1c8ZUoWap/it8Y5r1kdP2jmV/syTmk9AzUizi+eZK E0Vand8zNQ1jksUR8e+SsmkPJiobjzwNLUsd8kYqfX1xgiAwU/uyjxb6hb9yIic4sc LTxtOb6SRhYWh/UYkxEfzopcj8BKn8aQF44tSaXs= Received: from DLEE114.ent.ti.com (dlee114.ent.ti.com [157.170.170.25]) by fllv0035.itg.ti.com (8.15.2/8.15.2) with ESMTPS id x15EAO0s076862 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL); Tue, 5 Feb 2019 08:10:24 -0600 Received: from DLEE110.ent.ti.com (157.170.170.21) by DLEE114.ent.ti.com (157.170.170.25) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.1591.10; Tue, 5 Feb 2019 08:10:24 -0600 Received: from dlep32.itg.ti.com (157.170.170.100) by DLEE110.ent.ti.com (157.170.170.21) with Microsoft SMTP Server (version=TLS1_0, cipher=TLS_RSA_WITH_AES_256_CBC_SHA) id 15.1.1591.10 via Frontend Transport; Tue, 5 Feb 2019 08:10:24 -0600 Received: from a0230074-OptiPlex-7010.india.ti.com (ileax41-snat.itg.ti.com [10.172.224.153]) by dlep32.itg.ti.com (8.14.3/8.13.8) with ESMTP id x15E9leZ013398; Tue, 5 Feb 2019 08:10:21 -0600 From: Faiz Abbas To: Date: Tue, 5 Feb 2019 19:42:58 +0530 Message-ID: <20190205141301.21250-11-faiz_abbas@ti.com> X-Mailer: git-send-email 2.19.2 In-Reply-To: <20190205141301.21250-1-faiz_abbas@ti.com> References: <20190205141301.21250-1-faiz_abbas@ti.com> MIME-Version: 1.0 X-EXCLAIMER-MD-CONFIG: e1e8a2fd-e40a-4ac6-ac9b-f7e9cc9ee180 Cc: trini@konsulko.com, sivadur@xilinx.com, michal.simek@xilinx.com Subject: [U-Boot] [PATCH v2 10/13] mmc: am654_sdhci: Add Support for PHY X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" Add support in the driver for handling phy specific registers. Signed-off-by: Faiz Abbas Reviewed-by: Tom Rini --- drivers/mmc/Kconfig | 1 + drivers/mmc/am654_sdhci.c | 224 +++++++++++++++++++++++++++++++++++++- 2 files changed, 222 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 12b9356f0c..45eb1cd09a 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -420,6 +420,7 @@ config MMC_SDHCI_AM654 depends on ARCH_K3 depends on MMC_SDHCI depends on DM_MMC && OF_CONTROL && BLK + depends on REGMAP help Support for Secure Digital Host Controller Interface (SDHCI) controllers present on TI's AM654 SOCs. diff --git a/drivers/mmc/am654_sdhci.c b/drivers/mmc/am654_sdhci.c index 69914deb0c..123f4c3e8b 100644 --- a/drivers/mmc/am654_sdhci.c +++ b/drivers/mmc/am654_sdhci.c @@ -10,16 +10,190 @@ #include #include #include +#include #include +/* CTL_CFG Registers */ +#define CTL_CFG_2 0x14 + +#define SLOTTYPE_MASK GENMASK(31, 30) +#define SLOTTYPE_EMBEDDED BIT(30) + +/* PHY Registers */ +#define PHY_CTRL1 0x100 +#define PHY_CTRL2 0x104 +#define PHY_CTRL3 0x108 +#define PHY_CTRL4 0x10C +#define PHY_CTRL5 0x110 +#define PHY_CTRL6 0x114 +#define PHY_STAT1 0x130 +#define PHY_STAT2 0x134 + +#define IOMUX_ENABLE_SHIFT 31 +#define IOMUX_ENABLE_MASK BIT(IOMUX_ENABLE_SHIFT) +#define OTAPDLYENA_SHIFT 20 +#define OTAPDLYENA_MASK BIT(OTAPDLYENA_SHIFT) +#define OTAPDLYSEL_SHIFT 12 +#define OTAPDLYSEL_MASK GENMASK(15, 12) +#define STRBSEL_SHIFT 24 +#define STRBSEL_MASK GENMASK(27, 24) +#define SEL50_SHIFT 8 +#define SEL50_MASK BIT(SEL50_SHIFT) +#define SEL100_SHIFT 9 +#define SEL100_MASK BIT(SEL100_SHIFT) +#define DLL_TRIM_ICP_SHIFT 4 +#define DLL_TRIM_ICP_MASK GENMASK(7, 4) +#define DR_TY_SHIFT 20 +#define DR_TY_MASK GENMASK(22, 20) +#define ENDLL_SHIFT 1 +#define ENDLL_MASK BIT(ENDLL_SHIFT) +#define DLLRDY_SHIFT 0 +#define DLLRDY_MASK BIT(DLLRDY_SHIFT) +#define PDB_SHIFT 0 +#define PDB_MASK BIT(PDB_SHIFT) +#define CALDONE_SHIFT 1 +#define CALDONE_MASK BIT(CALDONE_SHIFT) +#define RETRIM_SHIFT 17 +#define RETRIM_MASK BIT(RETRIM_SHIFT) + +#define DRIVER_STRENGTH_50_OHM 0x0 +#define DRIVER_STRENGTH_33_OHM 0x1 +#define DRIVER_STRENGTH_66_OHM 0x2 +#define DRIVER_STRENGTH_100_OHM 0x3 +#define DRIVER_STRENGTH_40_OHM 0x4 + #define AM654_SDHCI_MIN_FREQ 400000 struct am654_sdhci_plat { struct mmc_config cfg; struct mmc mmc; unsigned int f_max; + struct regmap *base; + bool non_removable; + u32 otap_del_sel; + u32 trm_icp; + u32 drv_strength; + bool dll_on; }; +static int am654_sdhci_set_ios_post(struct sdhci_host *host) +{ + struct udevice *dev = host->mmc->dev; + struct am654_sdhci_plat *plat = dev_get_platdata(dev); + unsigned int speed = host->mmc->clock; + int sel50, sel100; + u32 mask, val; + int ret; + + /* Reset SD Clock Enable */ + val = sdhci_readw(host, SDHCI_CLOCK_CONTROL); + val &= ~SDHCI_CLOCK_CARD_EN; + sdhci_writew(host, val, SDHCI_CLOCK_CONTROL); + + /* power off phy */ + if (plat->dll_on) { + regmap_update_bits(plat->base, PHY_CTRL1, ENDLL_MASK, 0); + + plat->dll_on = false; + } + + /* restart clock */ + sdhci_set_clock(host->mmc, speed); + + /* switch phy back on */ + if (speed > AM654_SDHCI_MIN_FREQ) { + mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK; + val = (1 << OTAPDLYENA_SHIFT) | + (plat->otap_del_sel << OTAPDLYSEL_SHIFT); + regmap_update_bits(plat->base, PHY_CTRL4, + mask, val); + switch (speed) { + case 200000000: + sel50 = 0; + sel100 = 0; + break; + case 100000000: + sel50 = 0; + sel100 = 1; + break; + default: + sel50 = 1; + sel100 = 0; + } + + /* Configure PHY DLL frequency */ + mask = SEL50_MASK | SEL100_MASK; + val = (sel50 << SEL50_SHIFT) | (sel100 << SEL100_SHIFT); + regmap_update_bits(plat->base, PHY_CTRL5, + mask, val); + /* Configure DLL TRIM */ + mask = DLL_TRIM_ICP_MASK; + val = plat->trm_icp << DLL_TRIM_ICP_SHIFT; + + /* Configure DLL driver strength */ + mask |= DR_TY_MASK; + val |= plat->drv_strength << DR_TY_SHIFT; + regmap_update_bits(plat->base, PHY_CTRL1, + mask, val); + /* Enable DLL */ + regmap_update_bits(plat->base, PHY_CTRL1, + ENDLL_MASK, 0x1 << ENDLL_SHIFT); + /* + * Poll for DLL ready. Use a one second timeout. + * Works in all experiments done so far + */ + ret = regmap_read_poll_timeout(plat->base, + PHY_STAT1, val, + val & DLLRDY_MASK, + 1000000); + if (ret) + return ret; + + plat->dll_on = true; + } + + return 0; +} + +const struct sdhci_ops am654_sdhci_ops = { + .set_ios_post = &am654_sdhci_set_ios_post, +}; + +int am654_sdhci_init(struct am654_sdhci_plat *plat) +{ + int ctl_cfg_2 = 0; + u32 mask, val; + int ret; + + /* Reset OTAP to default value */ + mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK; + regmap_update_bits(plat->base, PHY_CTRL4, mask, 0x0); + + regmap_read(plat->base, PHY_STAT1, &val); + if (~val & CALDONE_MASK) { + /* Calibrate IO lines */ + regmap_update_bits(plat->base, PHY_CTRL1, + PDB_MASK, PDB_MASK); + ret = regmap_read_poll_timeout(plat->base, PHY_STAT1, + val, val & CALDONE_MASK, + 20); + if (ret) + return ret; + } + + /* Enable pins by setting IO mux to 0 */ + regmap_update_bits(plat->base, PHY_CTRL1, IOMUX_ENABLE_MASK, 0); + + /* Set slot type based on SD or eMMC */ + if (plat->non_removable) + ctl_cfg_2 = SLOTTYPE_EMBEDDED; + + regmap_update_bits(plat->base, CTL_CFG_2, ctl_cfg_2, + SLOTTYPE_MASK); + + return 0; +} + static int am654_sdhci_probe(struct udevice *dev) { struct am654_sdhci_plat *plat = dev_get_platdata(dev); @@ -58,13 +232,18 @@ static int am654_sdhci_probe(struct udevice *dev) ret = sdhci_setup_cfg(&plat->cfg, host, plat->f_max, AM654_SDHCI_MIN_FREQ); - host->mmc = &plat->mmc; if (ret) return ret; + host->mmc = &plat->mmc; + host->ops = &am654_sdhci_ops; host->mmc->priv = host; host->mmc->dev = dev; upriv->mmc = host->mmc; + regmap_init_mem_index(dev_ofnode(dev), &plat->base, 1); + + am654_sdhci_init(plat); + return sdhci_probe(dev); } @@ -72,11 +251,50 @@ static int am654_sdhci_ofdata_to_platdata(struct udevice *dev) { struct am654_sdhci_plat *plat = dev_get_platdata(dev); struct sdhci_host *host = dev_get_priv(dev); + struct mmc_config *cfg = &plat->cfg; + u32 drv_strength; + int ret; host->name = dev->name; host->ioaddr = (void *)dev_read_addr(dev); - host->bus_width = dev_read_u32_default(dev, "bus-width", 4); - plat->f_max = dev_read_u32_default(dev, "max-frequency", 0); + plat->non_removable = !dev_read_bool(dev, "non-removable"); + + ret = dev_read_u32(dev, "ti,trm-icp", &plat->trm_icp); + if (ret) + return ret; + + ret = dev_read_u32(dev, "ti,otap-del-sel", &plat->otap_del_sel); + if (ret) + return ret; + + ret = dev_read_u32(dev, "ti,driver-strength-ohm", &drv_strength); + if (ret) + return ret; + + switch (drv_strength) { + case 50: + plat->drv_strength = DRIVER_STRENGTH_50_OHM; + break; + case 33: + plat->drv_strength = DRIVER_STRENGTH_33_OHM; + break; + case 66: + plat->drv_strength = DRIVER_STRENGTH_66_OHM; + break; + case 100: + plat->drv_strength = DRIVER_STRENGTH_100_OHM; + break; + case 40: + plat->drv_strength = DRIVER_STRENGTH_40_OHM; + break; + default: + dev_err(dev, "Invalid driver strength\n"); + return -EINVAL; + } + + ret = mmc_of_parse(dev, cfg); + if (ret) + return ret; return 0; }