]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
sdhci: arasan: Add support for Versal Tap Delays
authorManish Narani <manish.narani@xilinx.com>
Mon, 6 Apr 2020 17:43:31 +0000 (23:13 +0530)
committerUlf Hansson <ulf.hansson@linaro.org>
Thu, 28 May 2020 09:20:56 +0000 (11:20 +0200)
Add support to set tap delays for Xilinx Versal SD controller. The tap
delay registers have moved to SD controller space in Versal. Make the
changes accordingly.

Signed-off-by: Manish Narani <manish.narani@xilinx.com>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
Link: https://lore.kernel.org/r/1586195015-128992-3-git-send-email-manish.narani@xilinx.com
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
drivers/mmc/host/sdhci-of-arasan.c

index d4905c106c0605f2dd191e9d45d48081e5567463..9e2ea3b813b3252df358f5b03d9c0658c6b7d019 100644 (file)
 #include "sdhci-pltfm.h"
 
 #define SDHCI_ARASAN_VENDOR_REGISTER   0x78
+
+#define SDHCI_ARASAN_ITAPDLY_REGISTER  0xF0F8
+#define SDHCI_ARASAN_OTAPDLY_REGISTER  0xF0FC
+
 #define SDHCI_ARASAN_CQE_BASE_ADDR     0x200
 #define VENDOR_ENHANCED_STROBE         BIT(0)
 
 #define PHY_CLK_TOO_SLOW_HZ            400000
 
+#define SDHCI_ITAPDLY_CHGWIN           0x200
+#define SDHCI_ITAPDLY_ENABLE           0x100
+#define SDHCI_OTAPDLY_ENABLE           0x40
+
 /* Default settings for ZynqMP Clock Phases */
 #define ZYNQMP_ICLK_PHASE {0, 63, 63, 0, 63,  0,   0, 183, 54,  0, 0}
 #define ZYNQMP_OCLK_PHASE {0, 72, 60, 0, 60, 72, 135, 48, 72, 135, 0}
 
+#define VERSAL_ICLK_PHASE {0, 132, 132, 0, 132, 0, 0, 162, 90, 0, 0}
+#define VERSAL_OCLK_PHASE {0,  60, 48, 0, 48, 72, 90, 36, 60, 90, 0}
+
 /*
  * On some SoCs the syscon area has a feature where the upper 16-bits of
  * each 32-bit register act as a write mask for the lower 16-bits.  This allows
@@ -555,6 +566,10 @@ static const struct of_device_id sdhci_arasan_of_match[] = {
                .compatible = "xlnx,zynqmp-8.9a",
                .data = &sdhci_arasan_zynqmp_data,
        },
+       {
+               .compatible = "xlnx,versal-8.9a",
+               .data = &sdhci_arasan_zynqmp_data,
+       },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, sdhci_arasan_of_match);
@@ -757,6 +772,152 @@ static const struct clk_ops zynqmp_sampleclk_ops = {
        .set_phase = sdhci_zynqmp_sampleclk_set_phase,
 };
 
+/**
+ * sdhci_versal_sdcardclk_set_phase - Set the SD Output Clock Tap Delays
+ *
+ * Set the SD Output Clock Tap Delays for Output path
+ *
+ * @hw:                        Pointer to the hardware clock structure.
+ * @degrees            The clock phase shift between 0 - 359.
+ * Return: 0 on success and error value on error
+ */
+static int sdhci_versal_sdcardclk_set_phase(struct clk_hw *hw, int degrees)
+{
+       struct sdhci_arasan_clk_data *clk_data =
+               container_of(hw, struct sdhci_arasan_clk_data, sdcardclk_hw);
+       struct sdhci_arasan_data *sdhci_arasan =
+               container_of(clk_data, struct sdhci_arasan_data, clk_data);
+       struct sdhci_host *host = sdhci_arasan->host;
+       u8 tap_delay, tap_max = 0;
+       int ret;
+
+       /*
+        * This is applicable for SDHCI_SPEC_300 and above
+        * Versal does not set phase for <=25MHz clock.
+        * If degrees is zero, no need to do anything.
+        */
+       if (host->version < SDHCI_SPEC_300 ||
+           host->timing == MMC_TIMING_LEGACY ||
+           host->timing == MMC_TIMING_UHS_SDR12 || !degrees)
+               return 0;
+
+       switch (host->timing) {
+       case MMC_TIMING_MMC_HS:
+       case MMC_TIMING_SD_HS:
+       case MMC_TIMING_UHS_SDR25:
+       case MMC_TIMING_UHS_DDR50:
+       case MMC_TIMING_MMC_DDR52:
+               /* For 50MHz clock, 30 Taps are available */
+               tap_max = 30;
+               break;
+       case MMC_TIMING_UHS_SDR50:
+               /* For 100MHz clock, 15 Taps are available */
+               tap_max = 15;
+               break;
+       case MMC_TIMING_UHS_SDR104:
+       case MMC_TIMING_MMC_HS200:
+               /* For 200MHz clock, 8 Taps are available */
+               tap_max = 8;
+       default:
+               break;
+       }
+
+       tap_delay = (degrees * tap_max) / 360;
+
+       /* Set the Clock Phase */
+       if (tap_delay) {
+               u32 regval;
+
+               regval = sdhci_readl(host, SDHCI_ARASAN_OTAPDLY_REGISTER);
+               regval |= SDHCI_OTAPDLY_ENABLE;
+               sdhci_writel(host, regval, SDHCI_ARASAN_OTAPDLY_REGISTER);
+               regval |= tap_delay;
+               sdhci_writel(host, regval, SDHCI_ARASAN_OTAPDLY_REGISTER);
+       }
+
+       return ret;
+}
+
+static const struct clk_ops versal_sdcardclk_ops = {
+       .recalc_rate = sdhci_arasan_sdcardclk_recalc_rate,
+       .set_phase = sdhci_versal_sdcardclk_set_phase,
+};
+
+/**
+ * sdhci_versal_sampleclk_set_phase - Set the SD Input Clock Tap Delays
+ *
+ * Set the SD Input Clock Tap Delays for Input path
+ *
+ * @hw:                        Pointer to the hardware clock structure.
+ * @degrees            The clock phase shift between 0 - 359.
+ * Return: 0 on success and error value on error
+ */
+static int sdhci_versal_sampleclk_set_phase(struct clk_hw *hw, int degrees)
+{
+       struct sdhci_arasan_clk_data *clk_data =
+               container_of(hw, struct sdhci_arasan_clk_data, sampleclk_hw);
+       struct sdhci_arasan_data *sdhci_arasan =
+               container_of(clk_data, struct sdhci_arasan_data, clk_data);
+       struct sdhci_host *host = sdhci_arasan->host;
+       u8 tap_delay, tap_max = 0;
+       int ret;
+
+       /*
+        * This is applicable for SDHCI_SPEC_300 and above
+        * Versal does not set phase for <=25MHz clock.
+        * If degrees is zero, no need to do anything.
+        */
+       if (host->version < SDHCI_SPEC_300 ||
+           host->timing == MMC_TIMING_LEGACY ||
+           host->timing == MMC_TIMING_UHS_SDR12 || !degrees)
+               return 0;
+
+       switch (host->timing) {
+       case MMC_TIMING_MMC_HS:
+       case MMC_TIMING_SD_HS:
+       case MMC_TIMING_UHS_SDR25:
+       case MMC_TIMING_UHS_DDR50:
+       case MMC_TIMING_MMC_DDR52:
+               /* For 50MHz clock, 120 Taps are available */
+               tap_max = 120;
+               break;
+       case MMC_TIMING_UHS_SDR50:
+               /* For 100MHz clock, 60 Taps are available */
+               tap_max = 60;
+               break;
+       case MMC_TIMING_UHS_SDR104:
+       case MMC_TIMING_MMC_HS200:
+               /* For 200MHz clock, 30 Taps are available */
+               tap_max = 30;
+       default:
+               break;
+       }
+
+       tap_delay = (degrees * tap_max) / 360;
+
+       /* Set the Clock Phase */
+       if (tap_delay) {
+               u32 regval;
+
+               regval = sdhci_readl(host, SDHCI_ARASAN_ITAPDLY_REGISTER);
+               regval |= SDHCI_ITAPDLY_CHGWIN;
+               sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER);
+               regval |= SDHCI_ITAPDLY_ENABLE;
+               sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER);
+               regval |= tap_delay;
+               sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER);
+               regval &= ~SDHCI_ITAPDLY_CHGWIN;
+               sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER);
+       }
+
+       return ret;
+}
+
+static const struct clk_ops versal_sampleclk_ops = {
+       .recalc_rate = sdhci_arasan_sampleclk_recalc_rate,
+       .set_phase = sdhci_versal_sampleclk_set_phase,
+};
+
 static void arasan_zynqmp_dll_reset(struct sdhci_host *host, u32 deviceid)
 {
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -954,6 +1115,16 @@ static void arasan_dt_parse_clk_phases(struct device *dev,
                }
        }
 
+       if (of_device_is_compatible(dev->of_node, "xlnx,versal-8.9a")) {
+               iclk_phase = (int [MMC_TIMING_MMC_HS400 + 1]) VERSAL_ICLK_PHASE;
+               oclk_phase = (int [MMC_TIMING_MMC_HS400 + 1]) VERSAL_OCLK_PHASE;
+
+               for (i = 0; i <= MMC_TIMING_MMC_HS400; i++) {
+                       clk_data->clk_phase_in[i] = iclk_phase[i];
+                       clk_data->clk_phase_out[i] = oclk_phase[i];
+               }
+       }
+
        arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_LEGACY,
                                 "clk-phase-legacy");
        arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_HS,
@@ -1014,6 +1185,8 @@ sdhci_arasan_register_sdcardclk(struct sdhci_arasan_data *sdhci_arasan,
        sdcardclk_init.flags = CLK_GET_RATE_NOCACHE;
        if (of_device_is_compatible(np, "xlnx,zynqmp-8.9a"))
                sdcardclk_init.ops = &zynqmp_sdcardclk_ops;
+       else if (of_device_is_compatible(np, "xlnx,versal-8.9a"))
+               sdcardclk_init.ops = &versal_sdcardclk_ops;
        else
                sdcardclk_init.ops = &arasan_sdcardclk_ops;
 
@@ -1066,6 +1239,8 @@ sdhci_arasan_register_sampleclk(struct sdhci_arasan_data *sdhci_arasan,
        sampleclk_init.flags = CLK_GET_RATE_NOCACHE;
        if (of_device_is_compatible(np, "xlnx,zynqmp-8.9a"))
                sampleclk_init.ops = &zynqmp_sampleclk_ops;
+       else if (of_device_is_compatible(np, "xlnx,versal-8.9a"))
+               sampleclk_init.ops = &versal_sampleclk_ops;
        else
                sampleclk_init.ops = &arasan_sampleclk_ops;