mmc: sdhci-pci-gli: Set SDR104's clock to 205MHz and enable SSC for GL9767
authorVictor Shih <victor.shih@genesyslogic.com.tw>
Fri, 9 Jun 2023 07:14:39 +0000 (15:14 +0800)
committerUlf Hansson <ulf.hansson@linaro.org>
Mon, 12 Jun 2023 13:20:08 +0000 (15:20 +0200)
Set GL9767 SDR104's clock to 205MHz and enable SSC feature
depend on register 0x888 BIT(1).

Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
Link: https://lore.kernel.org/r/20230609071441.451464-3-victorshihgli@gmail.com
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
drivers/mmc/host/sdhci-pci-gli.c

index 3ed207b..7a5ebd0 100644 (file)
 #define   GLI_9767_VHS_REV_M     0x1
 #define   GLI_9767_VHS_REV_W     0x2
 
+#define PCIE_GLI_9767_COM_MAILBOX              0x888
+#define   PCIE_GLI_9767_COM_MAILBOX_SSC_EN       BIT(1)
+
+#define PCIE_GLI_9767_CFG              0x8A0
+#define   PCIE_GLI_9767_CFG_LOW_PWR_OFF          BIT(12)
+
 #define PCIE_GLI_9767_PWR_MACRO_CTL                                    0x8D0
 #define   PCIE_GLI_9767_PWR_MACRO_CTL_LOW_VOLTAGE                        GENMASK(3, 0)
 #define   PCIE_GLI_9767_PWR_MACRO_CTL_LD0_LOW_OUTPUT_VOLTAGE             GENMASK(15, 12)
 #define   PCIE_GLI_9767_SCR_CORE_PWR_D3_OFF              BIT(21)
 #define   PCIE_GLI_9767_SCR_CFG_RST_DATA_LINK_DOWN       BIT(30)
 
+#define PCIE_GLI_9767_SD_PLL_CTL                       0x938
+#define   PCIE_GLI_9767_SD_PLL_CTL_PLL_LDIV              GENMASK(9, 0)
+#define   PCIE_GLI_9767_SD_PLL_CTL_PLL_PDIV              GENMASK(15, 12)
+#define   PCIE_GLI_9767_SD_PLL_CTL_PLL_DIR_EN            BIT(16)
+#define   PCIE_GLI_9767_SD_PLL_CTL_SSC_EN                BIT(19)
+#define   PCIE_GLI_9767_SD_PLL_CTL_SSC_STEP_SETTING      GENMASK(28, 24)
+
+#define PCIE_GLI_9767_SD_PLL_CTL2              0x93C
+#define   PCIE_GLI_9767_SD_PLL_CTL2_PLLSSC_PPM   GENMASK(31, 16)
+
 #define GLI_MAX_TUNING_LOOP 40
 
 /* Genesys Logic chipset */
@@ -753,6 +769,123 @@ static inline void gl9767_vhs_write(struct pci_dev *pdev)
        pci_write_config_dword(pdev, PCIE_GLI_9767_VHS, vhs_value);
 }
 
+static bool gl9767_ssc_enable(struct pci_dev *pdev)
+{
+       u32 value;
+       u8 enable;
+
+       gl9767_vhs_write(pdev);
+
+       pci_read_config_dword(pdev, PCIE_GLI_9767_COM_MAILBOX, &value);
+       enable = FIELD_GET(PCIE_GLI_9767_COM_MAILBOX_SSC_EN, value);
+
+       gl9767_vhs_read(pdev);
+
+       return enable;
+}
+
+static void gl9767_set_ssc(struct pci_dev *pdev, u8 enable, u8 step, u16 ppm)
+{
+       u32 pll;
+       u32 ssc;
+
+       gl9767_vhs_write(pdev);
+
+       pci_read_config_dword(pdev, PCIE_GLI_9767_SD_PLL_CTL, &pll);
+       pci_read_config_dword(pdev, PCIE_GLI_9767_SD_PLL_CTL2, &ssc);
+       pll &= ~(PCIE_GLI_9767_SD_PLL_CTL_SSC_STEP_SETTING |
+                PCIE_GLI_9767_SD_PLL_CTL_SSC_EN);
+       ssc &= ~PCIE_GLI_9767_SD_PLL_CTL2_PLLSSC_PPM;
+       pll |= FIELD_PREP(PCIE_GLI_9767_SD_PLL_CTL_SSC_STEP_SETTING, step) |
+              FIELD_PREP(PCIE_GLI_9767_SD_PLL_CTL_SSC_EN, enable);
+       ssc |= FIELD_PREP(PCIE_GLI_9767_SD_PLL_CTL2_PLLSSC_PPM, ppm);
+       pci_write_config_dword(pdev, PCIE_GLI_9767_SD_PLL_CTL2, ssc);
+       pci_write_config_dword(pdev, PCIE_GLI_9767_SD_PLL_CTL, pll);
+
+       gl9767_vhs_read(pdev);
+}
+
+static void gl9767_set_pll(struct pci_dev *pdev, u8 dir, u16 ldiv, u8 pdiv)
+{
+       u32 pll;
+
+       gl9767_vhs_write(pdev);
+
+       pci_read_config_dword(pdev, PCIE_GLI_9767_SD_PLL_CTL, &pll);
+       pll &= ~(PCIE_GLI_9767_SD_PLL_CTL_PLL_LDIV |
+                PCIE_GLI_9767_SD_PLL_CTL_PLL_PDIV |
+                PCIE_GLI_9767_SD_PLL_CTL_PLL_DIR_EN);
+       pll |= FIELD_PREP(PCIE_GLI_9767_SD_PLL_CTL_PLL_LDIV, ldiv) |
+              FIELD_PREP(PCIE_GLI_9767_SD_PLL_CTL_PLL_PDIV, pdiv) |
+              FIELD_PREP(PCIE_GLI_9767_SD_PLL_CTL_PLL_DIR_EN, dir);
+       pci_write_config_dword(pdev, PCIE_GLI_9767_SD_PLL_CTL, pll);
+
+       gl9767_vhs_read(pdev);
+
+       /* wait for pll stable */
+       usleep_range(1000, 1100);
+}
+
+static void gl9767_set_ssc_pll_205mhz(struct pci_dev *pdev)
+{
+       bool enable = gl9767_ssc_enable(pdev);
+
+       /* set pll to 205MHz and ssc */
+       gl9767_set_ssc(pdev, enable, 0x1F, 0xF5C3);
+       gl9767_set_pll(pdev, 0x1, 0x246, 0x0);
+}
+
+static void gl9767_disable_ssc_pll(struct pci_dev *pdev)
+{
+       u32 pll;
+
+       gl9767_vhs_write(pdev);
+
+       pci_read_config_dword(pdev, PCIE_GLI_9767_SD_PLL_CTL, &pll);
+       pll &= ~(PCIE_GLI_9767_SD_PLL_CTL_PLL_DIR_EN | PCIE_GLI_9767_SD_PLL_CTL_SSC_EN);
+       pci_write_config_dword(pdev, PCIE_GLI_9767_SD_PLL_CTL, pll);
+
+       gl9767_vhs_read(pdev);
+}
+
+static void sdhci_gl9767_set_clock(struct sdhci_host *host, unsigned int clock)
+{
+       struct sdhci_pci_slot *slot = sdhci_priv(host);
+       struct mmc_ios *ios = &host->mmc->ios;
+       struct pci_dev *pdev;
+       u32 value;
+       u16 clk;
+
+       pdev = slot->chip->pdev;
+       host->mmc->actual_clock = 0;
+
+       gl9767_vhs_write(pdev);
+
+       pci_read_config_dword(pdev, PCIE_GLI_9767_CFG, &value);
+       value |= PCIE_GLI_9767_CFG_LOW_PWR_OFF;
+       pci_write_config_dword(pdev, PCIE_GLI_9767_CFG, value);
+
+       gl9767_disable_ssc_pll(pdev);
+       sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
+
+       if (clock == 0)
+               return;
+
+       clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock);
+       if (clock == 200000000 && ios->timing == MMC_TIMING_UHS_SDR104) {
+               host->mmc->actual_clock = 205000000;
+               gl9767_set_ssc_pll_205mhz(pdev);
+       }
+
+       sdhci_enable_clk(host, clk);
+
+       pci_read_config_dword(pdev, PCIE_GLI_9767_CFG, &value);
+       value &= ~PCIE_GLI_9767_CFG_LOW_PWR_OFF;
+       pci_write_config_dword(pdev, PCIE_GLI_9767_CFG, value);
+
+       gl9767_vhs_read(pdev);
+}
+
 static void gli_set_9767(struct sdhci_host *host)
 {
        u32 value;
@@ -1293,7 +1426,7 @@ const struct sdhci_pci_fixes sdhci_gl9763e = {
 };
 
 static const struct sdhci_ops sdhci_gl9767_ops = {
-       .set_clock               = sdhci_set_clock,
+       .set_clock               = sdhci_gl9767_set_clock,
        .enable_dma              = sdhci_pci_enable_dma,
        .set_bus_width           = sdhci_set_bus_width,
        .reset                   = sdhci_gl9767_reset,