1e51df6ceSBen Chuang // SPDX-License-Identifier: GPL-2.0+ 2e51df6ceSBen Chuang /* 3e51df6ceSBen Chuang * Copyright (C) 2019 Genesys Logic, Inc. 4e51df6ceSBen Chuang * 5e51df6ceSBen Chuang * Authors: Ben Chuang <ben.chuang@genesyslogic.com.tw> 6e51df6ceSBen Chuang * 7e51df6ceSBen Chuang * Version: v0.9.0 (2019-08-08) 8e51df6ceSBen Chuang */ 9e51df6ceSBen Chuang 10e51df6ceSBen Chuang #include <linux/bitfield.h> 11e51df6ceSBen Chuang #include <linux/bits.h> 12e51df6ceSBen Chuang #include <linux/pci.h> 13e51df6ceSBen Chuang #include <linux/mmc/mmc.h> 14e51df6ceSBen Chuang #include <linux/delay.h> 15189f1d9bSHector Martin #include <linux/of.h> 16d607667bSBen Chuang #include <linux/iopoll.h> 17e51df6ceSBen Chuang #include "sdhci.h" 1808b863bbSBrian Norris #include "sdhci-cqhci.h" 19e51df6ceSBen Chuang #include "sdhci-pci.h" 20347f6be1SBen Chuang #include "cqhci.h" 21e51df6ceSBen Chuang 22e51df6ceSBen Chuang /* Genesys Logic extra registers */ 23e51df6ceSBen Chuang #define SDHCI_GLI_9750_WT 0x800 24e51df6ceSBen Chuang #define SDHCI_GLI_9750_WT_EN BIT(0) 25e51df6ceSBen Chuang #define GLI_9750_WT_EN_ON 0x1 26e51df6ceSBen Chuang #define GLI_9750_WT_EN_OFF 0x0 27e51df6ceSBen Chuang 289751baccSBen Chuang #define SDHCI_GLI_9750_CFG2 0x848 299751baccSBen Chuang #define SDHCI_GLI_9750_CFG2_L1DLY GENMASK(28, 24) 309751baccSBen Chuang #define GLI_9750_CFG2_L1DLY_VALUE 0x1F 319751baccSBen Chuang 32e51df6ceSBen Chuang #define SDHCI_GLI_9750_DRIVING 0x860 33e51df6ceSBen Chuang #define SDHCI_GLI_9750_DRIVING_1 GENMASK(11, 0) 34e51df6ceSBen Chuang #define SDHCI_GLI_9750_DRIVING_2 GENMASK(27, 26) 35e51df6ceSBen Chuang #define GLI_9750_DRIVING_1_VALUE 0xFFF 36e51df6ceSBen Chuang #define GLI_9750_DRIVING_2_VALUE 0x3 37b56ff195SBen Chuang #define SDHCI_GLI_9750_SEL_1 BIT(29) 38b56ff195SBen Chuang #define SDHCI_GLI_9750_SEL_2 BIT(31) 39b56ff195SBen Chuang #define SDHCI_GLI_9750_ALL_RST (BIT(24)|BIT(25)|BIT(28)|BIT(30)) 40e51df6ceSBen Chuang 41e51df6ceSBen Chuang #define SDHCI_GLI_9750_PLL 0x864 42786d33c8SBen Chuang #define SDHCI_GLI_9750_PLL_LDIV GENMASK(9, 0) 43786d33c8SBen Chuang #define SDHCI_GLI_9750_PLL_PDIV GENMASK(14, 12) 44786d33c8SBen Chuang #define SDHCI_GLI_9750_PLL_DIR BIT(15) 45e51df6ceSBen Chuang #define SDHCI_GLI_9750_PLL_TX2_INV BIT(23) 46e51df6ceSBen Chuang #define SDHCI_GLI_9750_PLL_TX2_DLY GENMASK(22, 20) 47e51df6ceSBen Chuang #define GLI_9750_PLL_TX2_INV_VALUE 0x1 48e51df6ceSBen Chuang #define GLI_9750_PLL_TX2_DLY_VALUE 0x0 49786d33c8SBen Chuang #define SDHCI_GLI_9750_PLLSSC_STEP GENMASK(28, 24) 50786d33c8SBen Chuang #define SDHCI_GLI_9750_PLLSSC_EN BIT(31) 51786d33c8SBen Chuang 52786d33c8SBen Chuang #define SDHCI_GLI_9750_PLLSSC 0x86C 53786d33c8SBen Chuang #define SDHCI_GLI_9750_PLLSSC_PPM GENMASK(31, 16) 54e51df6ceSBen Chuang 55e51df6ceSBen Chuang #define SDHCI_GLI_9750_SW_CTRL 0x874 56e51df6ceSBen Chuang #define SDHCI_GLI_9750_SW_CTRL_4 GENMASK(7, 6) 57e51df6ceSBen Chuang #define GLI_9750_SW_CTRL_4_VALUE 0x3 58e51df6ceSBen Chuang 59e51df6ceSBen Chuang #define SDHCI_GLI_9750_MISC 0x878 60e51df6ceSBen Chuang #define SDHCI_GLI_9750_MISC_TX1_INV BIT(2) 61e51df6ceSBen Chuang #define SDHCI_GLI_9750_MISC_RX_INV BIT(3) 62e51df6ceSBen Chuang #define SDHCI_GLI_9750_MISC_TX1_DLY GENMASK(6, 4) 63e51df6ceSBen Chuang #define GLI_9750_MISC_TX1_INV_VALUE 0x0 64e51df6ceSBen Chuang #define GLI_9750_MISC_RX_INV_ON 0x1 65e51df6ceSBen Chuang #define GLI_9750_MISC_RX_INV_OFF 0x0 66e51df6ceSBen Chuang #define GLI_9750_MISC_RX_INV_VALUE GLI_9750_MISC_RX_INV_OFF 67e51df6ceSBen Chuang #define GLI_9750_MISC_TX1_DLY_VALUE 0x5 6808df1a50SBen Chuang #define SDHCI_GLI_9750_MISC_SSC_OFF BIT(26) 69e51df6ceSBen Chuang 70e51df6ceSBen Chuang #define SDHCI_GLI_9750_TUNING_CONTROL 0x540 71e51df6ceSBen Chuang #define SDHCI_GLI_9750_TUNING_CONTROL_EN BIT(4) 72e51df6ceSBen Chuang #define GLI_9750_TUNING_CONTROL_EN_ON 0x1 73e51df6ceSBen Chuang #define GLI_9750_TUNING_CONTROL_EN_OFF 0x0 74e51df6ceSBen Chuang #define SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_1 BIT(16) 75e51df6ceSBen Chuang #define SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_2 GENMASK(20, 19) 76e51df6ceSBen Chuang #define GLI_9750_TUNING_CONTROL_GLITCH_1_VALUE 0x1 77e51df6ceSBen Chuang #define GLI_9750_TUNING_CONTROL_GLITCH_2_VALUE 0x2 78e51df6ceSBen Chuang 79e51df6ceSBen Chuang #define SDHCI_GLI_9750_TUNING_PARAMETERS 0x544 80e51df6ceSBen Chuang #define SDHCI_GLI_9750_TUNING_PARAMETERS_RX_DLY GENMASK(2, 0) 81e51df6ceSBen Chuang #define GLI_9750_TUNING_PARAMETERS_RX_DLY_VALUE 0x1 82e51df6ceSBen Chuang 831ae1d2d6SBen Chuang #define SDHCI_GLI_9763E_CTRL_HS400 0x7 841ae1d2d6SBen Chuang 851ae1d2d6SBen Chuang #define SDHCI_GLI_9763E_HS400_ES_REG 0x52C 861ae1d2d6SBen Chuang #define SDHCI_GLI_9763E_HS400_ES_BIT BIT(8) 871ae1d2d6SBen Chuang 881ae1d2d6SBen Chuang #define PCIE_GLI_9763E_VHS 0x884 891ae1d2d6SBen Chuang #define GLI_9763E_VHS_REV GENMASK(19, 16) 901ae1d2d6SBen Chuang #define GLI_9763E_VHS_REV_R 0x0 911ae1d2d6SBen Chuang #define GLI_9763E_VHS_REV_M 0x1 921ae1d2d6SBen Chuang #define GLI_9763E_VHS_REV_W 0x2 93347f6be1SBen Chuang #define PCIE_GLI_9763E_MB 0x888 94347f6be1SBen Chuang #define GLI_9763E_MB_CMDQ_OFF BIT(19) 9515f908faSRenius Chen #define GLI_9763E_MB_ERP_ON BIT(7) 961ae1d2d6SBen Chuang #define PCIE_GLI_9763E_SCR 0x8E0 971ae1d2d6SBen Chuang #define GLI_9763E_SCR_AXI_REQ BIT(9) 981ae1d2d6SBen Chuang 99f9e5b339SJason Lai #define PCIE_GLI_9763E_CFG 0x8A0 100f9e5b339SJason Lai #define GLI_9763E_CFG_LPSN_DIS BIT(12) 101f9e5b339SJason Lai 102edee82f7SRenius Chen #define PCIE_GLI_9763E_CFG2 0x8A4 103edee82f7SRenius Chen #define GLI_9763E_CFG2_L1DLY GENMASK(28, 19) 10434dd3cccSBen Chuang #define GLI_9763E_CFG2_L1DLY_MID 0x54 105edee82f7SRenius Chen 10698991b18SBen Chuang #define PCIE_GLI_9763E_MMC_CTRL 0x960 10798991b18SBen Chuang #define GLI_9763E_HS400_SLOW BIT(3) 10898991b18SBen Chuang 109c58c5950SRenius Chen #define PCIE_GLI_9763E_CLKRXDLY 0x934 110c58c5950SRenius Chen #define GLI_9763E_HS400_RXDLY GENMASK(31, 28) 111c58c5950SRenius Chen #define GLI_9763E_HS400_RXDLY_5 0x5 112c58c5950SRenius Chen 113347f6be1SBen Chuang #define SDHCI_GLI_9763E_CQE_BASE_ADDR 0x200 114347f6be1SBen Chuang #define GLI_9763E_CQE_TRNS_MODE (SDHCI_TRNS_MULTI | \ 115347f6be1SBen Chuang SDHCI_TRNS_BLK_CNT_EN | \ 116347f6be1SBen Chuang SDHCI_TRNS_DMA) 117347f6be1SBen Chuang 118786d33c8SBen Chuang #define PCI_GLI_9755_WT 0x800 119786d33c8SBen Chuang #define PCI_GLI_9755_WT_EN BIT(0) 120786d33c8SBen Chuang #define GLI_9755_WT_EN_ON 0x1 121786d33c8SBen Chuang #define GLI_9755_WT_EN_OFF 0x0 122786d33c8SBen Chuang 1230f1d9961SBen Chuang #define PCI_GLI_9755_PECONF 0x44 1240f1d9961SBen Chuang #define PCI_GLI_9755_LFCLK GENMASK(14, 12) 1250f1d9961SBen Chuang #define PCI_GLI_9755_DMACLK BIT(29) 126189f1d9bSHector Martin #define PCI_GLI_9755_INVERT_CD BIT(30) 127189f1d9bSHector Martin #define PCI_GLI_9755_INVERT_WP BIT(31) 1280f1d9961SBen Chuang 1299751baccSBen Chuang #define PCI_GLI_9755_CFG2 0x48 1309751baccSBen Chuang #define PCI_GLI_9755_CFG2_L1DLY GENMASK(28, 24) 1319751baccSBen Chuang #define GLI_9755_CFG2_L1DLY_VALUE 0x1F 1329751baccSBen Chuang 133786d33c8SBen Chuang #define PCI_GLI_9755_PLL 0x64 134786d33c8SBen Chuang #define PCI_GLI_9755_PLL_LDIV GENMASK(9, 0) 135786d33c8SBen Chuang #define PCI_GLI_9755_PLL_PDIV GENMASK(14, 12) 136786d33c8SBen Chuang #define PCI_GLI_9755_PLL_DIR BIT(15) 137786d33c8SBen Chuang #define PCI_GLI_9755_PLLSSC_STEP GENMASK(28, 24) 138786d33c8SBen Chuang #define PCI_GLI_9755_PLLSSC_EN BIT(31) 139786d33c8SBen Chuang 140786d33c8SBen Chuang #define PCI_GLI_9755_PLLSSC 0x68 141786d33c8SBen Chuang #define PCI_GLI_9755_PLLSSC_PPM GENMASK(15, 0) 142786d33c8SBen Chuang 143f46b54ccSRenius Chen #define PCI_GLI_9755_SerDes 0x70 144f46b54ccSRenius Chen #define PCI_GLI_9755_SCP_DIS BIT(19) 145f46b54ccSRenius Chen 14608df1a50SBen Chuang #define PCI_GLI_9755_MISC 0x78 14708df1a50SBen Chuang #define PCI_GLI_9755_MISC_SSC_OFF BIT(26) 14808df1a50SBen Chuang 14936ed2fd3SBen Chuang #define PCI_GLI_9755_PM_CTRL 0xFC 15036ed2fd3SBen Chuang #define PCI_GLI_9755_PM_STATE GENMASK(1, 0) 15136ed2fd3SBen Chuang 152*f3a5b56cSVictor Shih #define SDHCI_GLI_9767_GM_BURST_SIZE 0x510 153*f3a5b56cSVictor Shih #define SDHCI_GLI_9767_GM_BURST_SIZE_AXI_ALWAYS_SET BIT(8) 154*f3a5b56cSVictor Shih 155*f3a5b56cSVictor Shih #define PCIE_GLI_9767_VHS 0x884 156*f3a5b56cSVictor Shih #define GLI_9767_VHS_REV GENMASK(19, 16) 157*f3a5b56cSVictor Shih #define GLI_9767_VHS_REV_R 0x0 158*f3a5b56cSVictor Shih #define GLI_9767_VHS_REV_M 0x1 159*f3a5b56cSVictor Shih #define GLI_9767_VHS_REV_W 0x2 160*f3a5b56cSVictor Shih 161*f3a5b56cSVictor Shih #define PCIE_GLI_9767_PWR_MACRO_CTL 0x8D0 162*f3a5b56cSVictor Shih #define PCIE_GLI_9767_PWR_MACRO_CTL_LOW_VOLTAGE GENMASK(3, 0) 163*f3a5b56cSVictor Shih #define PCIE_GLI_9767_PWR_MACRO_CTL_LD0_LOW_OUTPUT_VOLTAGE GENMASK(15, 12) 164*f3a5b56cSVictor Shih #define PCIE_GLI_9767_PWR_MACRO_CTL_LD0_LOW_OUTPUT_VOLTAGE_VALUE 0x7 165*f3a5b56cSVictor Shih #define PCIE_GLI_9767_PWR_MACRO_CTL_RCLK_AMPLITUDE_CTL GENMASK(29, 28) 166*f3a5b56cSVictor Shih #define PCIE_GLI_9767_PWR_MACRO_CTL_RCLK_AMPLITUDE_CTL_VALUE 0x3 167*f3a5b56cSVictor Shih 168*f3a5b56cSVictor Shih #define PCIE_GLI_9767_SCR 0x8E0 169*f3a5b56cSVictor Shih #define PCIE_GLI_9767_SCR_AUTO_AXI_W_BURST BIT(6) 170*f3a5b56cSVictor Shih #define PCIE_GLI_9767_SCR_AUTO_AXI_R_BURST BIT(7) 171*f3a5b56cSVictor Shih #define PCIE_GLI_9767_SCR_AXI_REQ BIT(9) 172*f3a5b56cSVictor Shih #define PCIE_GLI_9767_SCR_CARD_DET_PWR_SAVING_EN BIT(10) 173*f3a5b56cSVictor Shih #define PCIE_GLI_9767_SCR_SYSTEM_CLK_SELECT_MODE0 BIT(16) 174*f3a5b56cSVictor Shih #define PCIE_GLI_9767_SCR_SYSTEM_CLK_SELECT_MODE1 BIT(17) 175*f3a5b56cSVictor Shih #define PCIE_GLI_9767_SCR_CORE_PWR_D3_OFF BIT(21) 176*f3a5b56cSVictor Shih #define PCIE_GLI_9767_SCR_CFG_RST_DATA_LINK_DOWN BIT(30) 177*f3a5b56cSVictor Shih 178e51df6ceSBen Chuang #define GLI_MAX_TUNING_LOOP 40 179e51df6ceSBen Chuang 180e51df6ceSBen Chuang /* Genesys Logic chipset */ 181e51df6ceSBen Chuang static inline void gl9750_wt_on(struct sdhci_host *host) 182e51df6ceSBen Chuang { 183e51df6ceSBen Chuang u32 wt_value; 184e51df6ceSBen Chuang u32 wt_enable; 185e51df6ceSBen Chuang 186e51df6ceSBen Chuang wt_value = sdhci_readl(host, SDHCI_GLI_9750_WT); 187e51df6ceSBen Chuang wt_enable = FIELD_GET(SDHCI_GLI_9750_WT_EN, wt_value); 188e51df6ceSBen Chuang 189e51df6ceSBen Chuang if (wt_enable == GLI_9750_WT_EN_ON) 190e51df6ceSBen Chuang return; 191e51df6ceSBen Chuang 192e51df6ceSBen Chuang wt_value &= ~SDHCI_GLI_9750_WT_EN; 193e51df6ceSBen Chuang wt_value |= FIELD_PREP(SDHCI_GLI_9750_WT_EN, GLI_9750_WT_EN_ON); 194e51df6ceSBen Chuang 195e51df6ceSBen Chuang sdhci_writel(host, wt_value, SDHCI_GLI_9750_WT); 196e51df6ceSBen Chuang } 197e51df6ceSBen Chuang 198e51df6ceSBen Chuang static inline void gl9750_wt_off(struct sdhci_host *host) 199e51df6ceSBen Chuang { 200e51df6ceSBen Chuang u32 wt_value; 201e51df6ceSBen Chuang u32 wt_enable; 202e51df6ceSBen Chuang 203e51df6ceSBen Chuang wt_value = sdhci_readl(host, SDHCI_GLI_9750_WT); 204e51df6ceSBen Chuang wt_enable = FIELD_GET(SDHCI_GLI_9750_WT_EN, wt_value); 205e51df6ceSBen Chuang 206e51df6ceSBen Chuang if (wt_enable == GLI_9750_WT_EN_OFF) 207e51df6ceSBen Chuang return; 208e51df6ceSBen Chuang 209e51df6ceSBen Chuang wt_value &= ~SDHCI_GLI_9750_WT_EN; 210e51df6ceSBen Chuang wt_value |= FIELD_PREP(SDHCI_GLI_9750_WT_EN, GLI_9750_WT_EN_OFF); 211e51df6ceSBen Chuang 212e51df6ceSBen Chuang sdhci_writel(host, wt_value, SDHCI_GLI_9750_WT); 213e51df6ceSBen Chuang } 214e51df6ceSBen Chuang 215e51df6ceSBen Chuang static void gli_set_9750(struct sdhci_host *host) 216e51df6ceSBen Chuang { 217e51df6ceSBen Chuang u32 driving_value; 218e51df6ceSBen Chuang u32 pll_value; 219e51df6ceSBen Chuang u32 sw_ctrl_value; 220e51df6ceSBen Chuang u32 misc_value; 221e51df6ceSBen Chuang u32 parameter_value; 222e51df6ceSBen Chuang u32 control_value; 223e51df6ceSBen Chuang u16 ctrl2; 224e51df6ceSBen Chuang 225e51df6ceSBen Chuang gl9750_wt_on(host); 226e51df6ceSBen Chuang 227e51df6ceSBen Chuang driving_value = sdhci_readl(host, SDHCI_GLI_9750_DRIVING); 228e51df6ceSBen Chuang pll_value = sdhci_readl(host, SDHCI_GLI_9750_PLL); 229e51df6ceSBen Chuang sw_ctrl_value = sdhci_readl(host, SDHCI_GLI_9750_SW_CTRL); 230e51df6ceSBen Chuang misc_value = sdhci_readl(host, SDHCI_GLI_9750_MISC); 231e51df6ceSBen Chuang parameter_value = sdhci_readl(host, SDHCI_GLI_9750_TUNING_PARAMETERS); 232e51df6ceSBen Chuang control_value = sdhci_readl(host, SDHCI_GLI_9750_TUNING_CONTROL); 233e51df6ceSBen Chuang 234e51df6ceSBen Chuang driving_value &= ~(SDHCI_GLI_9750_DRIVING_1); 235e51df6ceSBen Chuang driving_value &= ~(SDHCI_GLI_9750_DRIVING_2); 236e51df6ceSBen Chuang driving_value |= FIELD_PREP(SDHCI_GLI_9750_DRIVING_1, 237e51df6ceSBen Chuang GLI_9750_DRIVING_1_VALUE); 238e51df6ceSBen Chuang driving_value |= FIELD_PREP(SDHCI_GLI_9750_DRIVING_2, 239e51df6ceSBen Chuang GLI_9750_DRIVING_2_VALUE); 240b56ff195SBen Chuang driving_value &= ~(SDHCI_GLI_9750_SEL_1|SDHCI_GLI_9750_SEL_2|SDHCI_GLI_9750_ALL_RST); 241b56ff195SBen Chuang driving_value |= SDHCI_GLI_9750_SEL_2; 242e51df6ceSBen Chuang sdhci_writel(host, driving_value, SDHCI_GLI_9750_DRIVING); 243e51df6ceSBen Chuang 244e51df6ceSBen Chuang sw_ctrl_value &= ~SDHCI_GLI_9750_SW_CTRL_4; 245e51df6ceSBen Chuang sw_ctrl_value |= FIELD_PREP(SDHCI_GLI_9750_SW_CTRL_4, 246e51df6ceSBen Chuang GLI_9750_SW_CTRL_4_VALUE); 247e51df6ceSBen Chuang sdhci_writel(host, sw_ctrl_value, SDHCI_GLI_9750_SW_CTRL); 248e51df6ceSBen Chuang 249e51df6ceSBen Chuang /* reset the tuning flow after reinit and before starting tuning */ 250e51df6ceSBen Chuang pll_value &= ~SDHCI_GLI_9750_PLL_TX2_INV; 251e51df6ceSBen Chuang pll_value &= ~SDHCI_GLI_9750_PLL_TX2_DLY; 252e51df6ceSBen Chuang pll_value |= FIELD_PREP(SDHCI_GLI_9750_PLL_TX2_INV, 253e51df6ceSBen Chuang GLI_9750_PLL_TX2_INV_VALUE); 254e51df6ceSBen Chuang pll_value |= FIELD_PREP(SDHCI_GLI_9750_PLL_TX2_DLY, 255e51df6ceSBen Chuang GLI_9750_PLL_TX2_DLY_VALUE); 256e51df6ceSBen Chuang 257e51df6ceSBen Chuang misc_value &= ~SDHCI_GLI_9750_MISC_TX1_INV; 258e51df6ceSBen Chuang misc_value &= ~SDHCI_GLI_9750_MISC_RX_INV; 259e51df6ceSBen Chuang misc_value &= ~SDHCI_GLI_9750_MISC_TX1_DLY; 260e51df6ceSBen Chuang misc_value |= FIELD_PREP(SDHCI_GLI_9750_MISC_TX1_INV, 261e51df6ceSBen Chuang GLI_9750_MISC_TX1_INV_VALUE); 262e51df6ceSBen Chuang misc_value |= FIELD_PREP(SDHCI_GLI_9750_MISC_RX_INV, 263e51df6ceSBen Chuang GLI_9750_MISC_RX_INV_VALUE); 264e51df6ceSBen Chuang misc_value |= FIELD_PREP(SDHCI_GLI_9750_MISC_TX1_DLY, 265e51df6ceSBen Chuang GLI_9750_MISC_TX1_DLY_VALUE); 266e51df6ceSBen Chuang 267e51df6ceSBen Chuang parameter_value &= ~SDHCI_GLI_9750_TUNING_PARAMETERS_RX_DLY; 268e51df6ceSBen Chuang parameter_value |= FIELD_PREP(SDHCI_GLI_9750_TUNING_PARAMETERS_RX_DLY, 269e51df6ceSBen Chuang GLI_9750_TUNING_PARAMETERS_RX_DLY_VALUE); 270e51df6ceSBen Chuang 271e51df6ceSBen Chuang control_value &= ~SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_1; 272e51df6ceSBen Chuang control_value &= ~SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_2; 273e51df6ceSBen Chuang control_value |= FIELD_PREP(SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_1, 274e51df6ceSBen Chuang GLI_9750_TUNING_CONTROL_GLITCH_1_VALUE); 275e51df6ceSBen Chuang control_value |= FIELD_PREP(SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_2, 276e51df6ceSBen Chuang GLI_9750_TUNING_CONTROL_GLITCH_2_VALUE); 277e51df6ceSBen Chuang 278e51df6ceSBen Chuang sdhci_writel(host, pll_value, SDHCI_GLI_9750_PLL); 279e51df6ceSBen Chuang sdhci_writel(host, misc_value, SDHCI_GLI_9750_MISC); 280e51df6ceSBen Chuang 281e51df6ceSBen Chuang /* disable tuned clk */ 282e51df6ceSBen Chuang ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); 283e51df6ceSBen Chuang ctrl2 &= ~SDHCI_CTRL_TUNED_CLK; 284e51df6ceSBen Chuang sdhci_writew(host, ctrl2, SDHCI_HOST_CONTROL2); 285e51df6ceSBen Chuang 286e51df6ceSBen Chuang /* enable tuning parameters control */ 287e51df6ceSBen Chuang control_value &= ~SDHCI_GLI_9750_TUNING_CONTROL_EN; 288e51df6ceSBen Chuang control_value |= FIELD_PREP(SDHCI_GLI_9750_TUNING_CONTROL_EN, 289e51df6ceSBen Chuang GLI_9750_TUNING_CONTROL_EN_ON); 290e51df6ceSBen Chuang sdhci_writel(host, control_value, SDHCI_GLI_9750_TUNING_CONTROL); 291e51df6ceSBen Chuang 292e51df6ceSBen Chuang /* write tuning parameters */ 293e51df6ceSBen Chuang sdhci_writel(host, parameter_value, SDHCI_GLI_9750_TUNING_PARAMETERS); 294e51df6ceSBen Chuang 295e51df6ceSBen Chuang /* disable tuning parameters control */ 296e51df6ceSBen Chuang control_value &= ~SDHCI_GLI_9750_TUNING_CONTROL_EN; 297e51df6ceSBen Chuang control_value |= FIELD_PREP(SDHCI_GLI_9750_TUNING_CONTROL_EN, 298e51df6ceSBen Chuang GLI_9750_TUNING_CONTROL_EN_OFF); 299e51df6ceSBen Chuang sdhci_writel(host, control_value, SDHCI_GLI_9750_TUNING_CONTROL); 300e51df6ceSBen Chuang 301e51df6ceSBen Chuang /* clear tuned clk */ 302e51df6ceSBen Chuang ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); 303e51df6ceSBen Chuang ctrl2 &= ~SDHCI_CTRL_TUNED_CLK; 304e51df6ceSBen Chuang sdhci_writew(host, ctrl2, SDHCI_HOST_CONTROL2); 305e51df6ceSBen Chuang 306e51df6ceSBen Chuang gl9750_wt_off(host); 307e51df6ceSBen Chuang } 308e51df6ceSBen Chuang 309e51df6ceSBen Chuang static void gli_set_9750_rx_inv(struct sdhci_host *host, bool b) 310e51df6ceSBen Chuang { 311e51df6ceSBen Chuang u32 misc_value; 312e51df6ceSBen Chuang 313e51df6ceSBen Chuang gl9750_wt_on(host); 314e51df6ceSBen Chuang 315e51df6ceSBen Chuang misc_value = sdhci_readl(host, SDHCI_GLI_9750_MISC); 316e51df6ceSBen Chuang misc_value &= ~SDHCI_GLI_9750_MISC_RX_INV; 317e51df6ceSBen Chuang if (b) { 318e51df6ceSBen Chuang misc_value |= FIELD_PREP(SDHCI_GLI_9750_MISC_RX_INV, 319e51df6ceSBen Chuang GLI_9750_MISC_RX_INV_ON); 320e51df6ceSBen Chuang } else { 321e51df6ceSBen Chuang misc_value |= FIELD_PREP(SDHCI_GLI_9750_MISC_RX_INV, 322e51df6ceSBen Chuang GLI_9750_MISC_RX_INV_OFF); 323e51df6ceSBen Chuang } 324e51df6ceSBen Chuang sdhci_writel(host, misc_value, SDHCI_GLI_9750_MISC); 325e51df6ceSBen Chuang 326e51df6ceSBen Chuang gl9750_wt_off(host); 327e51df6ceSBen Chuang } 328e51df6ceSBen Chuang 329e51df6ceSBen Chuang static int __sdhci_execute_tuning_9750(struct sdhci_host *host, u32 opcode) 330e51df6ceSBen Chuang { 331e51df6ceSBen Chuang int i; 332e51df6ceSBen Chuang int rx_inv; 333e51df6ceSBen Chuang 334e51df6ceSBen Chuang for (rx_inv = 0; rx_inv < 2; rx_inv++) { 335e51df6ceSBen Chuang gli_set_9750_rx_inv(host, !!rx_inv); 336e51df6ceSBen Chuang sdhci_start_tuning(host); 337e51df6ceSBen Chuang 338e51df6ceSBen Chuang for (i = 0; i < GLI_MAX_TUNING_LOOP; i++) { 339e51df6ceSBen Chuang u16 ctrl; 340e51df6ceSBen Chuang 341e51df6ceSBen Chuang sdhci_send_tuning(host, opcode); 342e51df6ceSBen Chuang 343e51df6ceSBen Chuang if (!host->tuning_done) { 344e51df6ceSBen Chuang sdhci_abort_tuning(host, opcode); 345e51df6ceSBen Chuang break; 346e51df6ceSBen Chuang } 347e51df6ceSBen Chuang 348e51df6ceSBen Chuang ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); 349e51df6ceSBen Chuang if (!(ctrl & SDHCI_CTRL_EXEC_TUNING)) { 350e51df6ceSBen Chuang if (ctrl & SDHCI_CTRL_TUNED_CLK) 351e51df6ceSBen Chuang return 0; /* Success! */ 352e51df6ceSBen Chuang break; 353e51df6ceSBen Chuang } 354e51df6ceSBen Chuang } 355e51df6ceSBen Chuang } 356e51df6ceSBen Chuang if (!host->tuning_done) { 357e51df6ceSBen Chuang pr_info("%s: Tuning timeout, falling back to fixed sampling clock\n", 358e51df6ceSBen Chuang mmc_hostname(host->mmc)); 359e51df6ceSBen Chuang return -ETIMEDOUT; 360e51df6ceSBen Chuang } 361e51df6ceSBen Chuang 362e51df6ceSBen Chuang pr_info("%s: Tuning failed, falling back to fixed sampling clock\n", 363e51df6ceSBen Chuang mmc_hostname(host->mmc)); 364e51df6ceSBen Chuang sdhci_reset_tuning(host); 365e51df6ceSBen Chuang 366e51df6ceSBen Chuang return -EAGAIN; 367e51df6ceSBen Chuang } 368e51df6ceSBen Chuang 369e51df6ceSBen Chuang static int gl9750_execute_tuning(struct sdhci_host *host, u32 opcode) 370e51df6ceSBen Chuang { 371e51df6ceSBen Chuang host->mmc->retune_period = 0; 372e51df6ceSBen Chuang if (host->tuning_mode == SDHCI_TUNING_MODE_1) 373e51df6ceSBen Chuang host->mmc->retune_period = host->tuning_count; 374e51df6ceSBen Chuang 375e51df6ceSBen Chuang gli_set_9750(host); 376e51df6ceSBen Chuang host->tuning_err = __sdhci_execute_tuning_9750(host, opcode); 377e51df6ceSBen Chuang sdhci_end_tuning(host); 378e51df6ceSBen Chuang 379e51df6ceSBen Chuang return 0; 380e51df6ceSBen Chuang } 381e51df6ceSBen Chuang 382786d33c8SBen Chuang static void gl9750_disable_ssc_pll(struct sdhci_host *host) 383786d33c8SBen Chuang { 384786d33c8SBen Chuang u32 pll; 385786d33c8SBen Chuang 386786d33c8SBen Chuang gl9750_wt_on(host); 387786d33c8SBen Chuang pll = sdhci_readl(host, SDHCI_GLI_9750_PLL); 388786d33c8SBen Chuang pll &= ~(SDHCI_GLI_9750_PLL_DIR | SDHCI_GLI_9750_PLLSSC_EN); 389786d33c8SBen Chuang sdhci_writel(host, pll, SDHCI_GLI_9750_PLL); 390786d33c8SBen Chuang gl9750_wt_off(host); 391786d33c8SBen Chuang } 392786d33c8SBen Chuang 393786d33c8SBen Chuang static void gl9750_set_pll(struct sdhci_host *host, u8 dir, u16 ldiv, u8 pdiv) 394786d33c8SBen Chuang { 395786d33c8SBen Chuang u32 pll; 396786d33c8SBen Chuang 397786d33c8SBen Chuang gl9750_wt_on(host); 398786d33c8SBen Chuang pll = sdhci_readl(host, SDHCI_GLI_9750_PLL); 399786d33c8SBen Chuang pll &= ~(SDHCI_GLI_9750_PLL_LDIV | 400786d33c8SBen Chuang SDHCI_GLI_9750_PLL_PDIV | 401786d33c8SBen Chuang SDHCI_GLI_9750_PLL_DIR); 402786d33c8SBen Chuang pll |= FIELD_PREP(SDHCI_GLI_9750_PLL_LDIV, ldiv) | 403786d33c8SBen Chuang FIELD_PREP(SDHCI_GLI_9750_PLL_PDIV, pdiv) | 404786d33c8SBen Chuang FIELD_PREP(SDHCI_GLI_9750_PLL_DIR, dir); 405786d33c8SBen Chuang sdhci_writel(host, pll, SDHCI_GLI_9750_PLL); 406786d33c8SBen Chuang gl9750_wt_off(host); 407786d33c8SBen Chuang 408786d33c8SBen Chuang /* wait for pll stable */ 409786d33c8SBen Chuang mdelay(1); 410786d33c8SBen Chuang } 411786d33c8SBen Chuang 41208df1a50SBen Chuang static bool gl9750_ssc_enable(struct sdhci_host *host) 41308df1a50SBen Chuang { 41408df1a50SBen Chuang u32 misc; 41508df1a50SBen Chuang u8 off; 41608df1a50SBen Chuang 41708df1a50SBen Chuang gl9750_wt_on(host); 41808df1a50SBen Chuang misc = sdhci_readl(host, SDHCI_GLI_9750_MISC); 41908df1a50SBen Chuang off = FIELD_GET(SDHCI_GLI_9750_MISC_SSC_OFF, misc); 42008df1a50SBen Chuang gl9750_wt_off(host); 42108df1a50SBen Chuang 42208df1a50SBen Chuang return !off; 42308df1a50SBen Chuang } 42408df1a50SBen Chuang 425786d33c8SBen Chuang static void gl9750_set_ssc(struct sdhci_host *host, u8 enable, u8 step, u16 ppm) 426786d33c8SBen Chuang { 427786d33c8SBen Chuang u32 pll; 428786d33c8SBen Chuang u32 ssc; 429786d33c8SBen Chuang 430786d33c8SBen Chuang gl9750_wt_on(host); 431786d33c8SBen Chuang pll = sdhci_readl(host, SDHCI_GLI_9750_PLL); 432786d33c8SBen Chuang ssc = sdhci_readl(host, SDHCI_GLI_9750_PLLSSC); 433786d33c8SBen Chuang pll &= ~(SDHCI_GLI_9750_PLLSSC_STEP | 434786d33c8SBen Chuang SDHCI_GLI_9750_PLLSSC_EN); 435786d33c8SBen Chuang ssc &= ~SDHCI_GLI_9750_PLLSSC_PPM; 436786d33c8SBen Chuang pll |= FIELD_PREP(SDHCI_GLI_9750_PLLSSC_STEP, step) | 437786d33c8SBen Chuang FIELD_PREP(SDHCI_GLI_9750_PLLSSC_EN, enable); 438786d33c8SBen Chuang ssc |= FIELD_PREP(SDHCI_GLI_9750_PLLSSC_PPM, ppm); 439786d33c8SBen Chuang sdhci_writel(host, ssc, SDHCI_GLI_9750_PLLSSC); 440786d33c8SBen Chuang sdhci_writel(host, pll, SDHCI_GLI_9750_PLL); 441786d33c8SBen Chuang gl9750_wt_off(host); 442786d33c8SBen Chuang } 443786d33c8SBen Chuang 444786d33c8SBen Chuang static void gl9750_set_ssc_pll_205mhz(struct sdhci_host *host) 445786d33c8SBen Chuang { 44608df1a50SBen Chuang bool enable = gl9750_ssc_enable(host); 44708df1a50SBen Chuang 44808df1a50SBen Chuang /* set pll to 205MHz and ssc */ 44908df1a50SBen Chuang gl9750_set_ssc(host, enable, 0xF, 0x5A1D); 450786d33c8SBen Chuang gl9750_set_pll(host, 0x1, 0x246, 0x0); 451786d33c8SBen Chuang } 452786d33c8SBen Chuang 453d3c6bdb6SBen Chuang static void gl9750_set_ssc_pll_100mhz(struct sdhci_host *host) 454d3c6bdb6SBen Chuang { 45508df1a50SBen Chuang bool enable = gl9750_ssc_enable(host); 45608df1a50SBen Chuang 45708df1a50SBen Chuang /* set pll to 100MHz and ssc */ 45808df1a50SBen Chuang gl9750_set_ssc(host, enable, 0xE, 0x51EC); 459d3c6bdb6SBen Chuang gl9750_set_pll(host, 0x1, 0x244, 0x1); 460d3c6bdb6SBen Chuang } 461d3c6bdb6SBen Chuang 462d3c6bdb6SBen Chuang static void gl9750_set_ssc_pll_50mhz(struct sdhci_host *host) 463d3c6bdb6SBen Chuang { 46408df1a50SBen Chuang bool enable = gl9750_ssc_enable(host); 46508df1a50SBen Chuang 46608df1a50SBen Chuang /* set pll to 50MHz and ssc */ 46708df1a50SBen Chuang gl9750_set_ssc(host, enable, 0xE, 0x51EC); 468d3c6bdb6SBen Chuang gl9750_set_pll(host, 0x1, 0x244, 0x3); 469d3c6bdb6SBen Chuang } 470d3c6bdb6SBen Chuang 471786d33c8SBen Chuang static void sdhci_gl9750_set_clock(struct sdhci_host *host, unsigned int clock) 472786d33c8SBen Chuang { 473786d33c8SBen Chuang struct mmc_ios *ios = &host->mmc->ios; 474786d33c8SBen Chuang u16 clk; 475786d33c8SBen Chuang 476786d33c8SBen Chuang host->mmc->actual_clock = 0; 477786d33c8SBen Chuang 478786d33c8SBen Chuang gl9750_disable_ssc_pll(host); 479786d33c8SBen Chuang sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); 480786d33c8SBen Chuang 481786d33c8SBen Chuang if (clock == 0) 482786d33c8SBen Chuang return; 483786d33c8SBen Chuang 484786d33c8SBen Chuang clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock); 485786d33c8SBen Chuang if (clock == 200000000 && ios->timing == MMC_TIMING_UHS_SDR104) { 486786d33c8SBen Chuang host->mmc->actual_clock = 205000000; 487786d33c8SBen Chuang gl9750_set_ssc_pll_205mhz(host); 488d3c6bdb6SBen Chuang } else if (clock == 100000000) { 489d3c6bdb6SBen Chuang gl9750_set_ssc_pll_100mhz(host); 490d3c6bdb6SBen Chuang } else if (clock == 50000000) { 491d3c6bdb6SBen Chuang gl9750_set_ssc_pll_50mhz(host); 492786d33c8SBen Chuang } 493786d33c8SBen Chuang 494786d33c8SBen Chuang sdhci_enable_clk(host, clk); 495786d33c8SBen Chuang } 496786d33c8SBen Chuang 4979751baccSBen Chuang static void gl9750_hw_setting(struct sdhci_host *host) 4989751baccSBen Chuang { 4999751baccSBen Chuang u32 value; 5009751baccSBen Chuang 5019751baccSBen Chuang gl9750_wt_on(host); 5029751baccSBen Chuang 5039751baccSBen Chuang value = sdhci_readl(host, SDHCI_GLI_9750_CFG2); 5049751baccSBen Chuang value &= ~SDHCI_GLI_9750_CFG2_L1DLY; 5059751baccSBen Chuang /* set ASPM L1 entry delay to 7.9us */ 5069751baccSBen Chuang value |= FIELD_PREP(SDHCI_GLI_9750_CFG2_L1DLY, 5079751baccSBen Chuang GLI_9750_CFG2_L1DLY_VALUE); 5089751baccSBen Chuang sdhci_writel(host, value, SDHCI_GLI_9750_CFG2); 5099751baccSBen Chuang 5109751baccSBen Chuang gl9750_wt_off(host); 5119751baccSBen Chuang } 5129751baccSBen Chuang 51331e43f31SBen Chuang static void gli_pcie_enable_msi(struct sdhci_pci_slot *slot) 51431e43f31SBen Chuang { 51531e43f31SBen Chuang int ret; 51631e43f31SBen Chuang 51731e43f31SBen Chuang ret = pci_alloc_irq_vectors(slot->chip->pdev, 1, 1, 51831e43f31SBen Chuang PCI_IRQ_MSI | PCI_IRQ_MSIX); 51931e43f31SBen Chuang if (ret < 0) { 52031e43f31SBen Chuang pr_warn("%s: enable PCI MSI failed, error=%d\n", 52131e43f31SBen Chuang mmc_hostname(slot->host->mmc), ret); 52231e43f31SBen Chuang return; 52331e43f31SBen Chuang } 52431e43f31SBen Chuang 52531e43f31SBen Chuang slot->host->irq = pci_irq_vector(slot->chip->pdev, 0); 52631e43f31SBen Chuang } 52731e43f31SBen Chuang 528786d33c8SBen Chuang static inline void gl9755_wt_on(struct pci_dev *pdev) 529786d33c8SBen Chuang { 530786d33c8SBen Chuang u32 wt_value; 531786d33c8SBen Chuang u32 wt_enable; 532786d33c8SBen Chuang 533786d33c8SBen Chuang pci_read_config_dword(pdev, PCI_GLI_9755_WT, &wt_value); 534786d33c8SBen Chuang wt_enable = FIELD_GET(PCI_GLI_9755_WT_EN, wt_value); 535786d33c8SBen Chuang 536786d33c8SBen Chuang if (wt_enable == GLI_9755_WT_EN_ON) 537786d33c8SBen Chuang return; 538786d33c8SBen Chuang 539786d33c8SBen Chuang wt_value &= ~PCI_GLI_9755_WT_EN; 540786d33c8SBen Chuang wt_value |= FIELD_PREP(PCI_GLI_9755_WT_EN, GLI_9755_WT_EN_ON); 541786d33c8SBen Chuang 542786d33c8SBen Chuang pci_write_config_dword(pdev, PCI_GLI_9755_WT, wt_value); 543786d33c8SBen Chuang } 544786d33c8SBen Chuang 545786d33c8SBen Chuang static inline void gl9755_wt_off(struct pci_dev *pdev) 546786d33c8SBen Chuang { 547786d33c8SBen Chuang u32 wt_value; 548786d33c8SBen Chuang u32 wt_enable; 549786d33c8SBen Chuang 550786d33c8SBen Chuang pci_read_config_dword(pdev, PCI_GLI_9755_WT, &wt_value); 551786d33c8SBen Chuang wt_enable = FIELD_GET(PCI_GLI_9755_WT_EN, wt_value); 552786d33c8SBen Chuang 553786d33c8SBen Chuang if (wt_enable == GLI_9755_WT_EN_OFF) 554786d33c8SBen Chuang return; 555786d33c8SBen Chuang 556786d33c8SBen Chuang wt_value &= ~PCI_GLI_9755_WT_EN; 557786d33c8SBen Chuang wt_value |= FIELD_PREP(PCI_GLI_9755_WT_EN, GLI_9755_WT_EN_OFF); 558786d33c8SBen Chuang 559786d33c8SBen Chuang pci_write_config_dword(pdev, PCI_GLI_9755_WT, wt_value); 560786d33c8SBen Chuang } 561786d33c8SBen Chuang 562786d33c8SBen Chuang static void gl9755_disable_ssc_pll(struct pci_dev *pdev) 563786d33c8SBen Chuang { 564786d33c8SBen Chuang u32 pll; 565786d33c8SBen Chuang 566786d33c8SBen Chuang gl9755_wt_on(pdev); 567786d33c8SBen Chuang pci_read_config_dword(pdev, PCI_GLI_9755_PLL, &pll); 568786d33c8SBen Chuang pll &= ~(PCI_GLI_9755_PLL_DIR | PCI_GLI_9755_PLLSSC_EN); 569786d33c8SBen Chuang pci_write_config_dword(pdev, PCI_GLI_9755_PLL, pll); 570786d33c8SBen Chuang gl9755_wt_off(pdev); 571786d33c8SBen Chuang } 572786d33c8SBen Chuang 573786d33c8SBen Chuang static void gl9755_set_pll(struct pci_dev *pdev, u8 dir, u16 ldiv, u8 pdiv) 574786d33c8SBen Chuang { 575786d33c8SBen Chuang u32 pll; 576786d33c8SBen Chuang 577786d33c8SBen Chuang gl9755_wt_on(pdev); 578786d33c8SBen Chuang pci_read_config_dword(pdev, PCI_GLI_9755_PLL, &pll); 579786d33c8SBen Chuang pll &= ~(PCI_GLI_9755_PLL_LDIV | 580786d33c8SBen Chuang PCI_GLI_9755_PLL_PDIV | 581786d33c8SBen Chuang PCI_GLI_9755_PLL_DIR); 582786d33c8SBen Chuang pll |= FIELD_PREP(PCI_GLI_9755_PLL_LDIV, ldiv) | 583786d33c8SBen Chuang FIELD_PREP(PCI_GLI_9755_PLL_PDIV, pdiv) | 584786d33c8SBen Chuang FIELD_PREP(PCI_GLI_9755_PLL_DIR, dir); 585786d33c8SBen Chuang pci_write_config_dword(pdev, PCI_GLI_9755_PLL, pll); 586786d33c8SBen Chuang gl9755_wt_off(pdev); 587786d33c8SBen Chuang 588786d33c8SBen Chuang /* wait for pll stable */ 589786d33c8SBen Chuang mdelay(1); 590786d33c8SBen Chuang } 591786d33c8SBen Chuang 59208df1a50SBen Chuang static bool gl9755_ssc_enable(struct pci_dev *pdev) 59308df1a50SBen Chuang { 59408df1a50SBen Chuang u32 misc; 59508df1a50SBen Chuang u8 off; 59608df1a50SBen Chuang 59708df1a50SBen Chuang gl9755_wt_on(pdev); 59808df1a50SBen Chuang pci_read_config_dword(pdev, PCI_GLI_9755_MISC, &misc); 59908df1a50SBen Chuang off = FIELD_GET(PCI_GLI_9755_MISC_SSC_OFF, misc); 60008df1a50SBen Chuang gl9755_wt_off(pdev); 60108df1a50SBen Chuang 60208df1a50SBen Chuang return !off; 60308df1a50SBen Chuang } 60408df1a50SBen Chuang 605786d33c8SBen Chuang static void gl9755_set_ssc(struct pci_dev *pdev, u8 enable, u8 step, u16 ppm) 606786d33c8SBen Chuang { 607786d33c8SBen Chuang u32 pll; 608786d33c8SBen Chuang u32 ssc; 609786d33c8SBen Chuang 610786d33c8SBen Chuang gl9755_wt_on(pdev); 611786d33c8SBen Chuang pci_read_config_dword(pdev, PCI_GLI_9755_PLL, &pll); 612786d33c8SBen Chuang pci_read_config_dword(pdev, PCI_GLI_9755_PLLSSC, &ssc); 613786d33c8SBen Chuang pll &= ~(PCI_GLI_9755_PLLSSC_STEP | 614786d33c8SBen Chuang PCI_GLI_9755_PLLSSC_EN); 615786d33c8SBen Chuang ssc &= ~PCI_GLI_9755_PLLSSC_PPM; 616786d33c8SBen Chuang pll |= FIELD_PREP(PCI_GLI_9755_PLLSSC_STEP, step) | 617786d33c8SBen Chuang FIELD_PREP(PCI_GLI_9755_PLLSSC_EN, enable); 618786d33c8SBen Chuang ssc |= FIELD_PREP(PCI_GLI_9755_PLLSSC_PPM, ppm); 619786d33c8SBen Chuang pci_write_config_dword(pdev, PCI_GLI_9755_PLLSSC, ssc); 620786d33c8SBen Chuang pci_write_config_dword(pdev, PCI_GLI_9755_PLL, pll); 621786d33c8SBen Chuang gl9755_wt_off(pdev); 622786d33c8SBen Chuang } 623786d33c8SBen Chuang 624786d33c8SBen Chuang static void gl9755_set_ssc_pll_205mhz(struct pci_dev *pdev) 625786d33c8SBen Chuang { 62608df1a50SBen Chuang bool enable = gl9755_ssc_enable(pdev); 62708df1a50SBen Chuang 62808df1a50SBen Chuang /* set pll to 205MHz and ssc */ 62908df1a50SBen Chuang gl9755_set_ssc(pdev, enable, 0xF, 0x5A1D); 630786d33c8SBen Chuang gl9755_set_pll(pdev, 0x1, 0x246, 0x0); 631786d33c8SBen Chuang } 632786d33c8SBen Chuang 633d3c6bdb6SBen Chuang static void gl9755_set_ssc_pll_100mhz(struct pci_dev *pdev) 634d3c6bdb6SBen Chuang { 63508df1a50SBen Chuang bool enable = gl9755_ssc_enable(pdev); 63608df1a50SBen Chuang 63708df1a50SBen Chuang /* set pll to 100MHz and ssc */ 63808df1a50SBen Chuang gl9755_set_ssc(pdev, enable, 0xE, 0x51EC); 639d3c6bdb6SBen Chuang gl9755_set_pll(pdev, 0x1, 0x244, 0x1); 640d3c6bdb6SBen Chuang } 641d3c6bdb6SBen Chuang 642d3c6bdb6SBen Chuang static void gl9755_set_ssc_pll_50mhz(struct pci_dev *pdev) 643d3c6bdb6SBen Chuang { 64408df1a50SBen Chuang bool enable = gl9755_ssc_enable(pdev); 64508df1a50SBen Chuang 64608df1a50SBen Chuang /* set pll to 50MHz and ssc */ 64708df1a50SBen Chuang gl9755_set_ssc(pdev, enable, 0xE, 0x51EC); 648d3c6bdb6SBen Chuang gl9755_set_pll(pdev, 0x1, 0x244, 0x3); 649d3c6bdb6SBen Chuang } 650d3c6bdb6SBen Chuang 651786d33c8SBen Chuang static void sdhci_gl9755_set_clock(struct sdhci_host *host, unsigned int clock) 652786d33c8SBen Chuang { 653786d33c8SBen Chuang struct sdhci_pci_slot *slot = sdhci_priv(host); 654786d33c8SBen Chuang struct mmc_ios *ios = &host->mmc->ios; 655786d33c8SBen Chuang struct pci_dev *pdev; 656786d33c8SBen Chuang u16 clk; 657786d33c8SBen Chuang 658786d33c8SBen Chuang pdev = slot->chip->pdev; 659786d33c8SBen Chuang host->mmc->actual_clock = 0; 660786d33c8SBen Chuang 661786d33c8SBen Chuang gl9755_disable_ssc_pll(pdev); 662786d33c8SBen Chuang sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); 663786d33c8SBen Chuang 664786d33c8SBen Chuang if (clock == 0) 665786d33c8SBen Chuang return; 666786d33c8SBen Chuang 667786d33c8SBen Chuang clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock); 668786d33c8SBen Chuang if (clock == 200000000 && ios->timing == MMC_TIMING_UHS_SDR104) { 669786d33c8SBen Chuang host->mmc->actual_clock = 205000000; 670786d33c8SBen Chuang gl9755_set_ssc_pll_205mhz(pdev); 671d3c6bdb6SBen Chuang } else if (clock == 100000000) { 672d3c6bdb6SBen Chuang gl9755_set_ssc_pll_100mhz(pdev); 673d3c6bdb6SBen Chuang } else if (clock == 50000000) { 674d3c6bdb6SBen Chuang gl9755_set_ssc_pll_50mhz(pdev); 675786d33c8SBen Chuang } 676786d33c8SBen Chuang 677786d33c8SBen Chuang sdhci_enable_clk(host, clk); 678786d33c8SBen Chuang } 679786d33c8SBen Chuang 6800f1d9961SBen Chuang static void gl9755_hw_setting(struct sdhci_pci_slot *slot) 6810f1d9961SBen Chuang { 6820f1d9961SBen Chuang struct pci_dev *pdev = slot->chip->pdev; 6830f1d9961SBen Chuang u32 value; 6840f1d9961SBen Chuang 6850f1d9961SBen Chuang gl9755_wt_on(pdev); 6860f1d9961SBen Chuang 6870f1d9961SBen Chuang pci_read_config_dword(pdev, PCI_GLI_9755_PECONF, &value); 688189f1d9bSHector Martin /* 689189f1d9bSHector Martin * Apple ARM64 platforms using these chips may have 690189f1d9bSHector Martin * inverted CD/WP detection. 691189f1d9bSHector Martin */ 692189f1d9bSHector Martin if (of_property_read_bool(pdev->dev.of_node, "cd-inverted")) 693189f1d9bSHector Martin value |= PCI_GLI_9755_INVERT_CD; 694189f1d9bSHector Martin if (of_property_read_bool(pdev->dev.of_node, "wp-inverted")) 695189f1d9bSHector Martin value |= PCI_GLI_9755_INVERT_WP; 6960f1d9961SBen Chuang value &= ~PCI_GLI_9755_LFCLK; 6970f1d9961SBen Chuang value &= ~PCI_GLI_9755_DMACLK; 6980f1d9961SBen Chuang pci_write_config_dword(pdev, PCI_GLI_9755_PECONF, value); 6990f1d9961SBen Chuang 700f46b54ccSRenius Chen /* enable short circuit protection */ 701f46b54ccSRenius Chen pci_read_config_dword(pdev, PCI_GLI_9755_SerDes, &value); 702f46b54ccSRenius Chen value &= ~PCI_GLI_9755_SCP_DIS; 703f46b54ccSRenius Chen pci_write_config_dword(pdev, PCI_GLI_9755_SerDes, value); 704f46b54ccSRenius Chen 7059751baccSBen Chuang pci_read_config_dword(pdev, PCI_GLI_9755_CFG2, &value); 7069751baccSBen Chuang value &= ~PCI_GLI_9755_CFG2_L1DLY; 7079751baccSBen Chuang /* set ASPM L1 entry delay to 7.9us */ 7089751baccSBen Chuang value |= FIELD_PREP(PCI_GLI_9755_CFG2_L1DLY, 7099751baccSBen Chuang GLI_9755_CFG2_L1DLY_VALUE); 7109751baccSBen Chuang pci_write_config_dword(pdev, PCI_GLI_9755_CFG2, value); 7119751baccSBen Chuang 71236ed2fd3SBen Chuang /* toggle PM state to allow GL9755 to enter ASPM L1.2 */ 71336ed2fd3SBen Chuang pci_read_config_dword(pdev, PCI_GLI_9755_PM_CTRL, &value); 71436ed2fd3SBen Chuang value |= PCI_GLI_9755_PM_STATE; 71536ed2fd3SBen Chuang pci_write_config_dword(pdev, PCI_GLI_9755_PM_CTRL, value); 71636ed2fd3SBen Chuang value &= ~PCI_GLI_9755_PM_STATE; 71736ed2fd3SBen Chuang pci_write_config_dword(pdev, PCI_GLI_9755_PM_CTRL, value); 71836ed2fd3SBen Chuang 7190f1d9961SBen Chuang gl9755_wt_off(pdev); 7200f1d9961SBen Chuang } 7210f1d9961SBen Chuang 722*f3a5b56cSVictor Shih static inline void gl9767_vhs_read(struct pci_dev *pdev) 723*f3a5b56cSVictor Shih { 724*f3a5b56cSVictor Shih u32 vhs_enable; 725*f3a5b56cSVictor Shih u32 vhs_value; 726*f3a5b56cSVictor Shih 727*f3a5b56cSVictor Shih pci_read_config_dword(pdev, PCIE_GLI_9767_VHS, &vhs_value); 728*f3a5b56cSVictor Shih vhs_enable = FIELD_GET(GLI_9767_VHS_REV, vhs_value); 729*f3a5b56cSVictor Shih 730*f3a5b56cSVictor Shih if (vhs_enable == GLI_9767_VHS_REV_R) 731*f3a5b56cSVictor Shih return; 732*f3a5b56cSVictor Shih 733*f3a5b56cSVictor Shih vhs_value &= ~GLI_9767_VHS_REV; 734*f3a5b56cSVictor Shih vhs_value |= FIELD_PREP(GLI_9767_VHS_REV, GLI_9767_VHS_REV_R); 735*f3a5b56cSVictor Shih 736*f3a5b56cSVictor Shih pci_write_config_dword(pdev, PCIE_GLI_9767_VHS, vhs_value); 737*f3a5b56cSVictor Shih } 738*f3a5b56cSVictor Shih 739*f3a5b56cSVictor Shih static inline void gl9767_vhs_write(struct pci_dev *pdev) 740*f3a5b56cSVictor Shih { 741*f3a5b56cSVictor Shih u32 vhs_enable; 742*f3a5b56cSVictor Shih u32 vhs_value; 743*f3a5b56cSVictor Shih 744*f3a5b56cSVictor Shih pci_read_config_dword(pdev, PCIE_GLI_9767_VHS, &vhs_value); 745*f3a5b56cSVictor Shih vhs_enable = FIELD_GET(GLI_9767_VHS_REV, vhs_value); 746*f3a5b56cSVictor Shih 747*f3a5b56cSVictor Shih if (vhs_enable == GLI_9767_VHS_REV_W) 748*f3a5b56cSVictor Shih return; 749*f3a5b56cSVictor Shih 750*f3a5b56cSVictor Shih vhs_value &= ~GLI_9767_VHS_REV; 751*f3a5b56cSVictor Shih vhs_value |= FIELD_PREP(GLI_9767_VHS_REV, GLI_9767_VHS_REV_W); 752*f3a5b56cSVictor Shih 753*f3a5b56cSVictor Shih pci_write_config_dword(pdev, PCIE_GLI_9767_VHS, vhs_value); 754*f3a5b56cSVictor Shih } 755*f3a5b56cSVictor Shih 756*f3a5b56cSVictor Shih static void gli_set_9767(struct sdhci_host *host) 757*f3a5b56cSVictor Shih { 758*f3a5b56cSVictor Shih u32 value; 759*f3a5b56cSVictor Shih 760*f3a5b56cSVictor Shih value = sdhci_readl(host, SDHCI_GLI_9767_GM_BURST_SIZE); 761*f3a5b56cSVictor Shih value &= ~SDHCI_GLI_9767_GM_BURST_SIZE_AXI_ALWAYS_SET; 762*f3a5b56cSVictor Shih sdhci_writel(host, value, SDHCI_GLI_9767_GM_BURST_SIZE); 763*f3a5b56cSVictor Shih } 764*f3a5b56cSVictor Shih 765*f3a5b56cSVictor Shih static void gl9767_hw_setting(struct sdhci_pci_slot *slot) 766*f3a5b56cSVictor Shih { 767*f3a5b56cSVictor Shih struct pci_dev *pdev = slot->chip->pdev; 768*f3a5b56cSVictor Shih u32 value; 769*f3a5b56cSVictor Shih 770*f3a5b56cSVictor Shih gl9767_vhs_write(pdev); 771*f3a5b56cSVictor Shih 772*f3a5b56cSVictor Shih pci_read_config_dword(pdev, PCIE_GLI_9767_PWR_MACRO_CTL, &value); 773*f3a5b56cSVictor Shih value &= ~(PCIE_GLI_9767_PWR_MACRO_CTL_LOW_VOLTAGE | 774*f3a5b56cSVictor Shih PCIE_GLI_9767_PWR_MACRO_CTL_LD0_LOW_OUTPUT_VOLTAGE | 775*f3a5b56cSVictor Shih PCIE_GLI_9767_PWR_MACRO_CTL_RCLK_AMPLITUDE_CTL); 776*f3a5b56cSVictor Shih 777*f3a5b56cSVictor Shih value |= PCIE_GLI_9767_PWR_MACRO_CTL_LOW_VOLTAGE | 778*f3a5b56cSVictor Shih FIELD_PREP(PCIE_GLI_9767_PWR_MACRO_CTL_LD0_LOW_OUTPUT_VOLTAGE, 779*f3a5b56cSVictor Shih PCIE_GLI_9767_PWR_MACRO_CTL_LD0_LOW_OUTPUT_VOLTAGE_VALUE) | 780*f3a5b56cSVictor Shih FIELD_PREP(PCIE_GLI_9767_PWR_MACRO_CTL_RCLK_AMPLITUDE_CTL, 781*f3a5b56cSVictor Shih PCIE_GLI_9767_PWR_MACRO_CTL_RCLK_AMPLITUDE_CTL_VALUE); 782*f3a5b56cSVictor Shih pci_write_config_dword(pdev, PCIE_GLI_9767_PWR_MACRO_CTL, value); 783*f3a5b56cSVictor Shih 784*f3a5b56cSVictor Shih pci_read_config_dword(pdev, PCIE_GLI_9767_SCR, &value); 785*f3a5b56cSVictor Shih value &= ~(PCIE_GLI_9767_SCR_SYSTEM_CLK_SELECT_MODE0 | 786*f3a5b56cSVictor Shih PCIE_GLI_9767_SCR_SYSTEM_CLK_SELECT_MODE1 | 787*f3a5b56cSVictor Shih PCIE_GLI_9767_SCR_CFG_RST_DATA_LINK_DOWN); 788*f3a5b56cSVictor Shih 789*f3a5b56cSVictor Shih value |= PCIE_GLI_9767_SCR_AUTO_AXI_W_BURST | 790*f3a5b56cSVictor Shih PCIE_GLI_9767_SCR_AUTO_AXI_R_BURST | 791*f3a5b56cSVictor Shih PCIE_GLI_9767_SCR_AXI_REQ | 792*f3a5b56cSVictor Shih PCIE_GLI_9767_SCR_CARD_DET_PWR_SAVING_EN | 793*f3a5b56cSVictor Shih PCIE_GLI_9767_SCR_CORE_PWR_D3_OFF; 794*f3a5b56cSVictor Shih pci_write_config_dword(pdev, PCIE_GLI_9767_SCR, value); 795*f3a5b56cSVictor Shih 796*f3a5b56cSVictor Shih gl9767_vhs_read(pdev); 797*f3a5b56cSVictor Shih } 798*f3a5b56cSVictor Shih 799*f3a5b56cSVictor Shih static void sdhci_gl9767_reset(struct sdhci_host *host, u8 mask) 800*f3a5b56cSVictor Shih { 801*f3a5b56cSVictor Shih sdhci_reset(host, mask); 802*f3a5b56cSVictor Shih gli_set_9767(host); 803*f3a5b56cSVictor Shih } 804*f3a5b56cSVictor Shih 805e51df6ceSBen Chuang static int gli_probe_slot_gl9750(struct sdhci_pci_slot *slot) 806e51df6ceSBen Chuang { 807e51df6ceSBen Chuang struct sdhci_host *host = slot->host; 808e51df6ceSBen Chuang 8099751baccSBen Chuang gl9750_hw_setting(host); 81031e43f31SBen Chuang gli_pcie_enable_msi(slot); 811e51df6ceSBen Chuang slot->host->mmc->caps2 |= MMC_CAP2_NO_SDIO; 812e51df6ceSBen Chuang sdhci_enable_v4_mode(host); 813e51df6ceSBen Chuang 814e51df6ceSBen Chuang return 0; 815e51df6ceSBen Chuang } 816e51df6ceSBen Chuang 817e51df6ceSBen Chuang static int gli_probe_slot_gl9755(struct sdhci_pci_slot *slot) 818e51df6ceSBen Chuang { 819e51df6ceSBen Chuang struct sdhci_host *host = slot->host; 820e51df6ceSBen Chuang 8210f1d9961SBen Chuang gl9755_hw_setting(slot); 82231e43f31SBen Chuang gli_pcie_enable_msi(slot); 823e51df6ceSBen Chuang slot->host->mmc->caps2 |= MMC_CAP2_NO_SDIO; 824e51df6ceSBen Chuang sdhci_enable_v4_mode(host); 825e51df6ceSBen Chuang 826e51df6ceSBen Chuang return 0; 827e51df6ceSBen Chuang } 828e51df6ceSBen Chuang 829*f3a5b56cSVictor Shih static int gli_probe_slot_gl9767(struct sdhci_pci_slot *slot) 830*f3a5b56cSVictor Shih { 831*f3a5b56cSVictor Shih struct sdhci_host *host = slot->host; 832*f3a5b56cSVictor Shih 833*f3a5b56cSVictor Shih gli_set_9767(host); 834*f3a5b56cSVictor Shih gl9767_hw_setting(slot); 835*f3a5b56cSVictor Shih gli_pcie_enable_msi(slot); 836*f3a5b56cSVictor Shih slot->host->mmc->caps2 |= MMC_CAP2_NO_SDIO; 837*f3a5b56cSVictor Shih sdhci_enable_v4_mode(host); 838*f3a5b56cSVictor Shih 839*f3a5b56cSVictor Shih return 0; 840*f3a5b56cSVictor Shih } 841*f3a5b56cSVictor Shih 842e51df6ceSBen Chuang static void sdhci_gli_voltage_switch(struct sdhci_host *host) 843e51df6ceSBen Chuang { 844e51df6ceSBen Chuang /* 845e51df6ceSBen Chuang * According to Section 3.6.1 signal voltage switch procedure in 846e51df6ceSBen Chuang * SD Host Controller Simplified Spec. 4.20, steps 6~8 are as 847e51df6ceSBen Chuang * follows: 848e51df6ceSBen Chuang * (6) Set 1.8V Signal Enable in the Host Control 2 register. 849e51df6ceSBen Chuang * (7) Wait 5ms. 1.8V voltage regulator shall be stable within this 850e51df6ceSBen Chuang * period. 851e51df6ceSBen Chuang * (8) If 1.8V Signal Enable is cleared by Host Controller, go to 852e51df6ceSBen Chuang * step (12). 853e51df6ceSBen Chuang * 854e51df6ceSBen Chuang * Wait 5ms after set 1.8V signal enable in Host Control 2 register 855e51df6ceSBen Chuang * to ensure 1.8V signal enable bit is set by GL9750/GL9755. 856a1149a6cSDaniel Beer * 857a1149a6cSDaniel Beer * ...however, the controller in the NUC10i3FNK4 (a 9755) requires 858a1149a6cSDaniel Beer * slightly longer than 5ms before the control register reports that 859a1149a6cSDaniel Beer * 1.8V is ready, and far longer still before the card will actually 860a1149a6cSDaniel Beer * work reliably. 861e51df6ceSBen Chuang */ 862a1149a6cSDaniel Beer usleep_range(100000, 110000); 863e51df6ceSBen Chuang } 864e51df6ceSBen Chuang 865*f3a5b56cSVictor Shih static void sdhci_gl9767_voltage_switch(struct sdhci_host *host) 866*f3a5b56cSVictor Shih { 867*f3a5b56cSVictor Shih /* 868*f3a5b56cSVictor Shih * According to Section 3.6.1 signal voltage switch procedure in 869*f3a5b56cSVictor Shih * SD Host Controller Simplified Spec. 4.20, steps 6~8 are as 870*f3a5b56cSVictor Shih * follows: 871*f3a5b56cSVictor Shih * (6) Set 1.8V Signal Enable in the Host Control 2 register. 872*f3a5b56cSVictor Shih * (7) Wait 5ms. 1.8V voltage regulator shall be stable within this 873*f3a5b56cSVictor Shih * period. 874*f3a5b56cSVictor Shih * (8) If 1.8V Signal Enable is cleared by Host Controller, go to 875*f3a5b56cSVictor Shih * step (12). 876*f3a5b56cSVictor Shih * 877*f3a5b56cSVictor Shih * Wait 5ms after set 1.8V signal enable in Host Control 2 register 878*f3a5b56cSVictor Shih * to ensure 1.8V signal enable bit is set by GL9767. 879*f3a5b56cSVictor Shih * 880*f3a5b56cSVictor Shih */ 881*f3a5b56cSVictor Shih usleep_range(5000, 5500); 882*f3a5b56cSVictor Shih } 883*f3a5b56cSVictor Shih 884e51df6ceSBen Chuang static void sdhci_gl9750_reset(struct sdhci_host *host, u8 mask) 885e51df6ceSBen Chuang { 886e51df6ceSBen Chuang sdhci_reset(host, mask); 887e51df6ceSBen Chuang gli_set_9750(host); 888e51df6ceSBen Chuang } 889e51df6ceSBen Chuang 890e51df6ceSBen Chuang static u32 sdhci_gl9750_readl(struct sdhci_host *host, int reg) 891e51df6ceSBen Chuang { 892e51df6ceSBen Chuang u32 value; 893e51df6ceSBen Chuang 894e51df6ceSBen Chuang value = readl(host->ioaddr + reg); 895e51df6ceSBen Chuang if (unlikely(reg == SDHCI_MAX_CURRENT && !(value & 0xff))) 896e51df6ceSBen Chuang value |= 0xc8; 897e51df6ceSBen Chuang 898e51df6ceSBen Chuang return value; 899e51df6ceSBen Chuang } 900e51df6ceSBen Chuang 901282ede76SBen Chuang #ifdef CONFIG_PM_SLEEP 902282ede76SBen Chuang static int sdhci_pci_gli_resume(struct sdhci_pci_chip *chip) 903282ede76SBen Chuang { 904282ede76SBen Chuang struct sdhci_pci_slot *slot = chip->slots[0]; 905282ede76SBen Chuang 906282ede76SBen Chuang pci_free_irq_vectors(slot->chip->pdev); 907282ede76SBen Chuang gli_pcie_enable_msi(slot); 908282ede76SBen Chuang 909282ede76SBen Chuang return sdhci_pci_resume_host(chip); 910282ede76SBen Chuang } 911347f6be1SBen Chuang 912347f6be1SBen Chuang static int sdhci_cqhci_gli_resume(struct sdhci_pci_chip *chip) 913347f6be1SBen Chuang { 914347f6be1SBen Chuang struct sdhci_pci_slot *slot = chip->slots[0]; 915347f6be1SBen Chuang int ret; 916347f6be1SBen Chuang 917347f6be1SBen Chuang ret = sdhci_pci_gli_resume(chip); 918347f6be1SBen Chuang if (ret) 919347f6be1SBen Chuang return ret; 920347f6be1SBen Chuang 921347f6be1SBen Chuang return cqhci_resume(slot->host->mmc); 922347f6be1SBen Chuang } 923347f6be1SBen Chuang 924347f6be1SBen Chuang static int sdhci_cqhci_gli_suspend(struct sdhci_pci_chip *chip) 925347f6be1SBen Chuang { 926347f6be1SBen Chuang struct sdhci_pci_slot *slot = chip->slots[0]; 927347f6be1SBen Chuang int ret; 928347f6be1SBen Chuang 929347f6be1SBen Chuang ret = cqhci_suspend(slot->host->mmc); 930347f6be1SBen Chuang if (ret) 931347f6be1SBen Chuang return ret; 932347f6be1SBen Chuang 933347f6be1SBen Chuang return sdhci_suspend_host(slot->host); 934347f6be1SBen Chuang } 935282ede76SBen Chuang #endif 936282ede76SBen Chuang 9371ae1d2d6SBen Chuang static void gl9763e_hs400_enhanced_strobe(struct mmc_host *mmc, 9381ae1d2d6SBen Chuang struct mmc_ios *ios) 9391ae1d2d6SBen Chuang { 9401ae1d2d6SBen Chuang struct sdhci_host *host = mmc_priv(mmc); 9411ae1d2d6SBen Chuang u32 val; 9421ae1d2d6SBen Chuang 9431ae1d2d6SBen Chuang val = sdhci_readl(host, SDHCI_GLI_9763E_HS400_ES_REG); 9441ae1d2d6SBen Chuang if (ios->enhanced_strobe) 9451ae1d2d6SBen Chuang val |= SDHCI_GLI_9763E_HS400_ES_BIT; 9461ae1d2d6SBen Chuang else 9471ae1d2d6SBen Chuang val &= ~SDHCI_GLI_9763E_HS400_ES_BIT; 9481ae1d2d6SBen Chuang 9491ae1d2d6SBen Chuang sdhci_writel(host, val, SDHCI_GLI_9763E_HS400_ES_REG); 9501ae1d2d6SBen Chuang } 9511ae1d2d6SBen Chuang 9521ae1d2d6SBen Chuang static void sdhci_set_gl9763e_signaling(struct sdhci_host *host, 9531ae1d2d6SBen Chuang unsigned int timing) 9541ae1d2d6SBen Chuang { 9551ae1d2d6SBen Chuang u16 ctrl_2; 9561ae1d2d6SBen Chuang 9571ae1d2d6SBen Chuang ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); 9581ae1d2d6SBen Chuang ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; 9591ae1d2d6SBen Chuang if (timing == MMC_TIMING_MMC_HS200) 9601ae1d2d6SBen Chuang ctrl_2 |= SDHCI_CTRL_UHS_SDR104; 9611ae1d2d6SBen Chuang else if (timing == MMC_TIMING_MMC_HS) 9621ae1d2d6SBen Chuang ctrl_2 |= SDHCI_CTRL_UHS_SDR25; 9631ae1d2d6SBen Chuang else if (timing == MMC_TIMING_MMC_DDR52) 9641ae1d2d6SBen Chuang ctrl_2 |= SDHCI_CTRL_UHS_DDR50; 9651ae1d2d6SBen Chuang else if (timing == MMC_TIMING_MMC_HS400) 9661ae1d2d6SBen Chuang ctrl_2 |= SDHCI_GLI_9763E_CTRL_HS400; 9671ae1d2d6SBen Chuang 9681ae1d2d6SBen Chuang sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); 9691ae1d2d6SBen Chuang } 9701ae1d2d6SBen Chuang 971347f6be1SBen Chuang static void sdhci_gl9763e_dumpregs(struct mmc_host *mmc) 972347f6be1SBen Chuang { 973347f6be1SBen Chuang sdhci_dumpregs(mmc_priv(mmc)); 974347f6be1SBen Chuang } 975347f6be1SBen Chuang 976347f6be1SBen Chuang static void sdhci_gl9763e_cqe_pre_enable(struct mmc_host *mmc) 977347f6be1SBen Chuang { 978347f6be1SBen Chuang struct cqhci_host *cq_host = mmc->cqe_private; 979347f6be1SBen Chuang u32 value; 980347f6be1SBen Chuang 981347f6be1SBen Chuang value = cqhci_readl(cq_host, CQHCI_CFG); 982347f6be1SBen Chuang value |= CQHCI_ENABLE; 983347f6be1SBen Chuang cqhci_writel(cq_host, value, CQHCI_CFG); 984347f6be1SBen Chuang } 985347f6be1SBen Chuang 986347f6be1SBen Chuang static void sdhci_gl9763e_cqe_enable(struct mmc_host *mmc) 987347f6be1SBen Chuang { 988347f6be1SBen Chuang struct sdhci_host *host = mmc_priv(mmc); 989347f6be1SBen Chuang 990347f6be1SBen Chuang sdhci_writew(host, GLI_9763E_CQE_TRNS_MODE, SDHCI_TRANSFER_MODE); 991347f6be1SBen Chuang sdhci_cqe_enable(mmc); 992347f6be1SBen Chuang } 993347f6be1SBen Chuang 994347f6be1SBen Chuang static u32 sdhci_gl9763e_cqhci_irq(struct sdhci_host *host, u32 intmask) 995347f6be1SBen Chuang { 996347f6be1SBen Chuang int cmd_error = 0; 997347f6be1SBen Chuang int data_error = 0; 998347f6be1SBen Chuang 999347f6be1SBen Chuang if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error)) 1000347f6be1SBen Chuang return intmask; 1001347f6be1SBen Chuang 1002347f6be1SBen Chuang cqhci_irq(host->mmc, intmask, cmd_error, data_error); 1003347f6be1SBen Chuang 1004347f6be1SBen Chuang return 0; 1005347f6be1SBen Chuang } 1006347f6be1SBen Chuang 1007347f6be1SBen Chuang static void sdhci_gl9763e_cqe_post_disable(struct mmc_host *mmc) 1008347f6be1SBen Chuang { 1009347f6be1SBen Chuang struct sdhci_host *host = mmc_priv(mmc); 1010347f6be1SBen Chuang struct cqhci_host *cq_host = mmc->cqe_private; 1011347f6be1SBen Chuang u32 value; 1012347f6be1SBen Chuang 1013347f6be1SBen Chuang value = cqhci_readl(cq_host, CQHCI_CFG); 1014347f6be1SBen Chuang value &= ~CQHCI_ENABLE; 1015347f6be1SBen Chuang cqhci_writel(cq_host, value, CQHCI_CFG); 1016347f6be1SBen Chuang sdhci_writew(host, 0x0, SDHCI_TRANSFER_MODE); 1017347f6be1SBen Chuang } 1018347f6be1SBen Chuang 1019347f6be1SBen Chuang static const struct cqhci_host_ops sdhci_gl9763e_cqhci_ops = { 1020347f6be1SBen Chuang .enable = sdhci_gl9763e_cqe_enable, 1021347f6be1SBen Chuang .disable = sdhci_cqe_disable, 1022347f6be1SBen Chuang .dumpregs = sdhci_gl9763e_dumpregs, 1023347f6be1SBen Chuang .pre_enable = sdhci_gl9763e_cqe_pre_enable, 1024347f6be1SBen Chuang .post_disable = sdhci_gl9763e_cqe_post_disable, 1025347f6be1SBen Chuang }; 1026347f6be1SBen Chuang 1027347f6be1SBen Chuang static int gl9763e_add_host(struct sdhci_pci_slot *slot) 1028347f6be1SBen Chuang { 1029347f6be1SBen Chuang struct device *dev = &slot->chip->pdev->dev; 1030347f6be1SBen Chuang struct sdhci_host *host = slot->host; 1031347f6be1SBen Chuang struct cqhci_host *cq_host; 1032347f6be1SBen Chuang bool dma64; 1033347f6be1SBen Chuang int ret; 1034347f6be1SBen Chuang 1035347f6be1SBen Chuang ret = sdhci_setup_host(host); 1036347f6be1SBen Chuang if (ret) 1037347f6be1SBen Chuang return ret; 1038347f6be1SBen Chuang 1039347f6be1SBen Chuang cq_host = devm_kzalloc(dev, sizeof(*cq_host), GFP_KERNEL); 1040347f6be1SBen Chuang if (!cq_host) { 1041347f6be1SBen Chuang ret = -ENOMEM; 1042347f6be1SBen Chuang goto cleanup; 1043347f6be1SBen Chuang } 1044347f6be1SBen Chuang 1045347f6be1SBen Chuang cq_host->mmio = host->ioaddr + SDHCI_GLI_9763E_CQE_BASE_ADDR; 1046347f6be1SBen Chuang cq_host->ops = &sdhci_gl9763e_cqhci_ops; 1047347f6be1SBen Chuang 1048347f6be1SBen Chuang dma64 = host->flags & SDHCI_USE_64_BIT_DMA; 1049347f6be1SBen Chuang if (dma64) 1050347f6be1SBen Chuang cq_host->caps |= CQHCI_TASK_DESC_SZ_128; 1051347f6be1SBen Chuang 1052347f6be1SBen Chuang ret = cqhci_init(cq_host, host->mmc, dma64); 1053347f6be1SBen Chuang if (ret) 1054347f6be1SBen Chuang goto cleanup; 1055347f6be1SBen Chuang 1056347f6be1SBen Chuang ret = __sdhci_add_host(host); 1057347f6be1SBen Chuang if (ret) 1058347f6be1SBen Chuang goto cleanup; 1059347f6be1SBen Chuang 1060347f6be1SBen Chuang return 0; 1061347f6be1SBen Chuang 1062347f6be1SBen Chuang cleanup: 1063347f6be1SBen Chuang sdhci_cleanup_host(host); 1064347f6be1SBen Chuang return ret; 1065347f6be1SBen Chuang } 1066347f6be1SBen Chuang 10671ae1d2d6SBen Chuang static void gli_set_gl9763e(struct sdhci_pci_slot *slot) 10681ae1d2d6SBen Chuang { 10691ae1d2d6SBen Chuang struct pci_dev *pdev = slot->chip->pdev; 10701ae1d2d6SBen Chuang u32 value; 10711ae1d2d6SBen Chuang 10721ae1d2d6SBen Chuang pci_read_config_dword(pdev, PCIE_GLI_9763E_VHS, &value); 10731ae1d2d6SBen Chuang value &= ~GLI_9763E_VHS_REV; 10741ae1d2d6SBen Chuang value |= FIELD_PREP(GLI_9763E_VHS_REV, GLI_9763E_VHS_REV_W); 10751ae1d2d6SBen Chuang pci_write_config_dword(pdev, PCIE_GLI_9763E_VHS, value); 10761ae1d2d6SBen Chuang 10771ae1d2d6SBen Chuang pci_read_config_dword(pdev, PCIE_GLI_9763E_SCR, &value); 10781ae1d2d6SBen Chuang value |= GLI_9763E_SCR_AXI_REQ; 10791ae1d2d6SBen Chuang pci_write_config_dword(pdev, PCIE_GLI_9763E_SCR, value); 10801ae1d2d6SBen Chuang 108198991b18SBen Chuang pci_read_config_dword(pdev, PCIE_GLI_9763E_MMC_CTRL, &value); 108298991b18SBen Chuang value &= ~GLI_9763E_HS400_SLOW; 108398991b18SBen Chuang pci_write_config_dword(pdev, PCIE_GLI_9763E_MMC_CTRL, value); 108498991b18SBen Chuang 1085edee82f7SRenius Chen pci_read_config_dword(pdev, PCIE_GLI_9763E_CFG2, &value); 1086edee82f7SRenius Chen value &= ~GLI_9763E_CFG2_L1DLY; 108734dd3cccSBen Chuang /* set ASPM L1 entry delay to 21us */ 1088baaaf55dSBen Chuang value |= FIELD_PREP(GLI_9763E_CFG2_L1DLY, GLI_9763E_CFG2_L1DLY_MID); 1089edee82f7SRenius Chen pci_write_config_dword(pdev, PCIE_GLI_9763E_CFG2, value); 1090edee82f7SRenius Chen 1091c58c5950SRenius Chen pci_read_config_dword(pdev, PCIE_GLI_9763E_CLKRXDLY, &value); 1092c58c5950SRenius Chen value &= ~GLI_9763E_HS400_RXDLY; 1093c58c5950SRenius Chen value |= FIELD_PREP(GLI_9763E_HS400_RXDLY, GLI_9763E_HS400_RXDLY_5); 1094c58c5950SRenius Chen pci_write_config_dword(pdev, PCIE_GLI_9763E_CLKRXDLY, value); 1095c58c5950SRenius Chen 10961ae1d2d6SBen Chuang pci_read_config_dword(pdev, PCIE_GLI_9763E_VHS, &value); 10971ae1d2d6SBen Chuang value &= ~GLI_9763E_VHS_REV; 10981ae1d2d6SBen Chuang value |= FIELD_PREP(GLI_9763E_VHS_REV, GLI_9763E_VHS_REV_R); 10991ae1d2d6SBen Chuang pci_write_config_dword(pdev, PCIE_GLI_9763E_VHS, value); 11001ae1d2d6SBen Chuang } 11011ae1d2d6SBen Chuang 1102d607667bSBen Chuang #ifdef CONFIG_PM 11031c5fd973SRen Zhijie static void gl9763e_set_low_power_negotiation(struct sdhci_pci_slot *slot, bool enable) 11041c5fd973SRen Zhijie { 11051c5fd973SRen Zhijie struct pci_dev *pdev = slot->chip->pdev; 11061c5fd973SRen Zhijie u32 value; 11071c5fd973SRen Zhijie 11081c5fd973SRen Zhijie pci_read_config_dword(pdev, PCIE_GLI_9763E_VHS, &value); 11091c5fd973SRen Zhijie value &= ~GLI_9763E_VHS_REV; 11101c5fd973SRen Zhijie value |= FIELD_PREP(GLI_9763E_VHS_REV, GLI_9763E_VHS_REV_W); 11111c5fd973SRen Zhijie pci_write_config_dword(pdev, PCIE_GLI_9763E_VHS, value); 11121c5fd973SRen Zhijie 11131c5fd973SRen Zhijie pci_read_config_dword(pdev, PCIE_GLI_9763E_CFG, &value); 11141c5fd973SRen Zhijie 11151c5fd973SRen Zhijie if (enable) 11161c5fd973SRen Zhijie value &= ~GLI_9763E_CFG_LPSN_DIS; 11171c5fd973SRen Zhijie else 11181c5fd973SRen Zhijie value |= GLI_9763E_CFG_LPSN_DIS; 11191c5fd973SRen Zhijie 11201c5fd973SRen Zhijie pci_write_config_dword(pdev, PCIE_GLI_9763E_CFG, value); 11211c5fd973SRen Zhijie 11221c5fd973SRen Zhijie pci_read_config_dword(pdev, PCIE_GLI_9763E_VHS, &value); 11231c5fd973SRen Zhijie value &= ~GLI_9763E_VHS_REV; 11241c5fd973SRen Zhijie value |= FIELD_PREP(GLI_9763E_VHS_REV, GLI_9763E_VHS_REV_R); 11251c5fd973SRen Zhijie pci_write_config_dword(pdev, PCIE_GLI_9763E_VHS, value); 11261c5fd973SRen Zhijie } 11271c5fd973SRen Zhijie 1128d607667bSBen Chuang static int gl9763e_runtime_suspend(struct sdhci_pci_chip *chip) 1129d607667bSBen Chuang { 1130d607667bSBen Chuang struct sdhci_pci_slot *slot = chip->slots[0]; 1131d607667bSBen Chuang struct sdhci_host *host = slot->host; 1132d607667bSBen Chuang u16 clock; 1133d607667bSBen Chuang 1134f9e5b339SJason Lai /* Enable LPM negotiation to allow entering L1 state */ 1135f9e5b339SJason Lai gl9763e_set_low_power_negotiation(slot, true); 1136f9e5b339SJason Lai 1137d607667bSBen Chuang clock = sdhci_readw(host, SDHCI_CLOCK_CONTROL); 1138d607667bSBen Chuang clock &= ~(SDHCI_CLOCK_PLL_EN | SDHCI_CLOCK_CARD_EN); 1139d607667bSBen Chuang sdhci_writew(host, clock, SDHCI_CLOCK_CONTROL); 1140d607667bSBen Chuang 1141d607667bSBen Chuang return 0; 1142d607667bSBen Chuang } 1143d607667bSBen Chuang 1144d607667bSBen Chuang static int gl9763e_runtime_resume(struct sdhci_pci_chip *chip) 1145d607667bSBen Chuang { 1146d607667bSBen Chuang struct sdhci_pci_slot *slot = chip->slots[0]; 1147d607667bSBen Chuang struct sdhci_host *host = slot->host; 1148d607667bSBen Chuang u16 clock; 1149d607667bSBen Chuang 1150291e7d52SBen Chuang if (host->mmc->ios.power_mode != MMC_POWER_ON) 1151291e7d52SBen Chuang return 0; 1152291e7d52SBen Chuang 1153d607667bSBen Chuang clock = sdhci_readw(host, SDHCI_CLOCK_CONTROL); 1154d607667bSBen Chuang 1155d607667bSBen Chuang clock |= SDHCI_CLOCK_PLL_EN; 1156d607667bSBen Chuang clock &= ~SDHCI_CLOCK_INT_STABLE; 1157d607667bSBen Chuang sdhci_writew(host, clock, SDHCI_CLOCK_CONTROL); 1158d607667bSBen Chuang 1159d607667bSBen Chuang /* Wait max 150 ms */ 1160d607667bSBen Chuang if (read_poll_timeout(sdhci_readw, clock, (clock & SDHCI_CLOCK_INT_STABLE), 1161d607667bSBen Chuang 1000, 150000, false, host, SDHCI_CLOCK_CONTROL)) { 1162d607667bSBen Chuang pr_err("%s: PLL clock never stabilised.\n", 1163d607667bSBen Chuang mmc_hostname(host->mmc)); 1164d607667bSBen Chuang sdhci_dumpregs(host); 1165d607667bSBen Chuang } 1166d607667bSBen Chuang 1167d607667bSBen Chuang clock |= SDHCI_CLOCK_CARD_EN; 1168d607667bSBen Chuang sdhci_writew(host, clock, SDHCI_CLOCK_CONTROL); 1169d607667bSBen Chuang 1170f9e5b339SJason Lai /* Disable LPM negotiation to avoid entering L1 state. */ 1171f9e5b339SJason Lai gl9763e_set_low_power_negotiation(slot, false); 1172f9e5b339SJason Lai 1173d607667bSBen Chuang return 0; 1174d607667bSBen Chuang } 1175d607667bSBen Chuang #endif 1176d607667bSBen Chuang 11771ae1d2d6SBen Chuang static int gli_probe_slot_gl9763e(struct sdhci_pci_slot *slot) 11781ae1d2d6SBen Chuang { 1179347f6be1SBen Chuang struct pci_dev *pdev = slot->chip->pdev; 11801ae1d2d6SBen Chuang struct sdhci_host *host = slot->host; 1181347f6be1SBen Chuang u32 value; 11821ae1d2d6SBen Chuang 11831ae1d2d6SBen Chuang host->mmc->caps |= MMC_CAP_8_BIT_DATA | 11841ae1d2d6SBen Chuang MMC_CAP_1_8V_DDR | 11851ae1d2d6SBen Chuang MMC_CAP_NONREMOVABLE; 11861ae1d2d6SBen Chuang host->mmc->caps2 |= MMC_CAP2_HS200_1_8V_SDR | 11871ae1d2d6SBen Chuang MMC_CAP2_HS400_1_8V | 11881ae1d2d6SBen Chuang MMC_CAP2_HS400_ES | 11891ae1d2d6SBen Chuang MMC_CAP2_NO_SDIO | 11901ae1d2d6SBen Chuang MMC_CAP2_NO_SD; 1191347f6be1SBen Chuang 1192347f6be1SBen Chuang pci_read_config_dword(pdev, PCIE_GLI_9763E_MB, &value); 1193347f6be1SBen Chuang if (!(value & GLI_9763E_MB_CMDQ_OFF)) 119415f908faSRenius Chen if (value & GLI_9763E_MB_ERP_ON) 1195347f6be1SBen Chuang host->mmc->caps2 |= MMC_CAP2_CQE | MMC_CAP2_CQE_DCMD; 1196347f6be1SBen Chuang 11971ae1d2d6SBen Chuang gli_pcie_enable_msi(slot); 11981ae1d2d6SBen Chuang host->mmc_host_ops.hs400_enhanced_strobe = 11991ae1d2d6SBen Chuang gl9763e_hs400_enhanced_strobe; 12001ae1d2d6SBen Chuang gli_set_gl9763e(slot); 12011ae1d2d6SBen Chuang sdhci_enable_v4_mode(host); 12021ae1d2d6SBen Chuang 12031ae1d2d6SBen Chuang return 0; 12041ae1d2d6SBen Chuang } 12051ae1d2d6SBen Chuang 1206c064bb5cSHector Martin #define REG_OFFSET_IN_BITS(reg) ((reg) << 3 & 0x18) 1207c064bb5cSHector Martin 1208c064bb5cSHector Martin static u16 sdhci_gli_readw(struct sdhci_host *host, int reg) 1209c064bb5cSHector Martin { 1210c064bb5cSHector Martin u32 val = readl(host->ioaddr + (reg & ~3)); 1211c064bb5cSHector Martin u16 word; 1212c064bb5cSHector Martin 1213c064bb5cSHector Martin word = (val >> REG_OFFSET_IN_BITS(reg)) & 0xffff; 1214c064bb5cSHector Martin return word; 1215c064bb5cSHector Martin } 1216c064bb5cSHector Martin 1217c064bb5cSHector Martin static u8 sdhci_gli_readb(struct sdhci_host *host, int reg) 1218c064bb5cSHector Martin { 1219c064bb5cSHector Martin u32 val = readl(host->ioaddr + (reg & ~3)); 1220c064bb5cSHector Martin u8 byte = (val >> REG_OFFSET_IN_BITS(reg)) & 0xff; 1221c064bb5cSHector Martin 1222c064bb5cSHector Martin return byte; 1223c064bb5cSHector Martin } 1224c064bb5cSHector Martin 1225e51df6ceSBen Chuang static const struct sdhci_ops sdhci_gl9755_ops = { 1226c064bb5cSHector Martin .read_w = sdhci_gli_readw, 1227c064bb5cSHector Martin .read_b = sdhci_gli_readb, 1228786d33c8SBen Chuang .set_clock = sdhci_gl9755_set_clock, 1229e51df6ceSBen Chuang .enable_dma = sdhci_pci_enable_dma, 1230e51df6ceSBen Chuang .set_bus_width = sdhci_set_bus_width, 1231e51df6ceSBen Chuang .reset = sdhci_reset, 1232e51df6ceSBen Chuang .set_uhs_signaling = sdhci_set_uhs_signaling, 1233e51df6ceSBen Chuang .voltage_switch = sdhci_gli_voltage_switch, 1234e51df6ceSBen Chuang }; 1235e51df6ceSBen Chuang 1236e51df6ceSBen Chuang const struct sdhci_pci_fixes sdhci_gl9755 = { 1237e51df6ceSBen Chuang .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, 1238e51df6ceSBen Chuang .quirks2 = SDHCI_QUIRK2_BROKEN_DDR50, 1239e51df6ceSBen Chuang .probe_slot = gli_probe_slot_gl9755, 1240e51df6ceSBen Chuang .ops = &sdhci_gl9755_ops, 1241282ede76SBen Chuang #ifdef CONFIG_PM_SLEEP 1242282ede76SBen Chuang .resume = sdhci_pci_gli_resume, 1243282ede76SBen Chuang #endif 1244e51df6ceSBen Chuang }; 1245e51df6ceSBen Chuang 1246e51df6ceSBen Chuang static const struct sdhci_ops sdhci_gl9750_ops = { 1247c064bb5cSHector Martin .read_w = sdhci_gli_readw, 1248c064bb5cSHector Martin .read_b = sdhci_gli_readb, 1249e51df6ceSBen Chuang .read_l = sdhci_gl9750_readl, 1250786d33c8SBen Chuang .set_clock = sdhci_gl9750_set_clock, 1251e51df6ceSBen Chuang .enable_dma = sdhci_pci_enable_dma, 1252e51df6ceSBen Chuang .set_bus_width = sdhci_set_bus_width, 1253e51df6ceSBen Chuang .reset = sdhci_gl9750_reset, 1254e51df6ceSBen Chuang .set_uhs_signaling = sdhci_set_uhs_signaling, 1255e51df6ceSBen Chuang .voltage_switch = sdhci_gli_voltage_switch, 1256e51df6ceSBen Chuang .platform_execute_tuning = gl9750_execute_tuning, 1257e51df6ceSBen Chuang }; 1258e51df6ceSBen Chuang 1259e51df6ceSBen Chuang const struct sdhci_pci_fixes sdhci_gl9750 = { 1260e51df6ceSBen Chuang .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, 1261e51df6ceSBen Chuang .quirks2 = SDHCI_QUIRK2_BROKEN_DDR50, 1262e51df6ceSBen Chuang .probe_slot = gli_probe_slot_gl9750, 1263e51df6ceSBen Chuang .ops = &sdhci_gl9750_ops, 1264282ede76SBen Chuang #ifdef CONFIG_PM_SLEEP 1265282ede76SBen Chuang .resume = sdhci_pci_gli_resume, 1266282ede76SBen Chuang #endif 1267e51df6ceSBen Chuang }; 12681ae1d2d6SBen Chuang 12691ae1d2d6SBen Chuang static const struct sdhci_ops sdhci_gl9763e_ops = { 12701ae1d2d6SBen Chuang .set_clock = sdhci_set_clock, 12711ae1d2d6SBen Chuang .enable_dma = sdhci_pci_enable_dma, 12721ae1d2d6SBen Chuang .set_bus_width = sdhci_set_bus_width, 127308b863bbSBrian Norris .reset = sdhci_and_cqhci_reset, 12741ae1d2d6SBen Chuang .set_uhs_signaling = sdhci_set_gl9763e_signaling, 12751ae1d2d6SBen Chuang .voltage_switch = sdhci_gli_voltage_switch, 1276347f6be1SBen Chuang .irq = sdhci_gl9763e_cqhci_irq, 12771ae1d2d6SBen Chuang }; 12781ae1d2d6SBen Chuang 12791ae1d2d6SBen Chuang const struct sdhci_pci_fixes sdhci_gl9763e = { 12801ae1d2d6SBen Chuang .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, 12811ae1d2d6SBen Chuang .probe_slot = gli_probe_slot_gl9763e, 12821ae1d2d6SBen Chuang .ops = &sdhci_gl9763e_ops, 12831ae1d2d6SBen Chuang #ifdef CONFIG_PM_SLEEP 1284347f6be1SBen Chuang .resume = sdhci_cqhci_gli_resume, 1285347f6be1SBen Chuang .suspend = sdhci_cqhci_gli_suspend, 12861ae1d2d6SBen Chuang #endif 1287d607667bSBen Chuang #ifdef CONFIG_PM 1288d607667bSBen Chuang .runtime_suspend = gl9763e_runtime_suspend, 1289d607667bSBen Chuang .runtime_resume = gl9763e_runtime_resume, 1290d607667bSBen Chuang .allow_runtime_pm = true, 1291d607667bSBen Chuang #endif 1292347f6be1SBen Chuang .add_host = gl9763e_add_host, 12931ae1d2d6SBen Chuang }; 1294*f3a5b56cSVictor Shih 1295*f3a5b56cSVictor Shih static const struct sdhci_ops sdhci_gl9767_ops = { 1296*f3a5b56cSVictor Shih .set_clock = sdhci_set_clock, 1297*f3a5b56cSVictor Shih .enable_dma = sdhci_pci_enable_dma, 1298*f3a5b56cSVictor Shih .set_bus_width = sdhci_set_bus_width, 1299*f3a5b56cSVictor Shih .reset = sdhci_gl9767_reset, 1300*f3a5b56cSVictor Shih .set_uhs_signaling = sdhci_set_uhs_signaling, 1301*f3a5b56cSVictor Shih .voltage_switch = sdhci_gl9767_voltage_switch, 1302*f3a5b56cSVictor Shih }; 1303*f3a5b56cSVictor Shih 1304*f3a5b56cSVictor Shih const struct sdhci_pci_fixes sdhci_gl9767 = { 1305*f3a5b56cSVictor Shih .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, 1306*f3a5b56cSVictor Shih .quirks2 = SDHCI_QUIRK2_BROKEN_DDR50, 1307*f3a5b56cSVictor Shih .probe_slot = gli_probe_slot_gl9767, 1308*f3a5b56cSVictor Shih .ops = &sdhci_gl9767_ops, 1309*f3a5b56cSVictor Shih #ifdef CONFIG_PM_SLEEP 1310*f3a5b56cSVictor Shih .resume = sdhci_pci_gli_resume, 1311*f3a5b56cSVictor Shih #endif 1312*f3a5b56cSVictor Shih }; 1313