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" 18e51df6ceSBen Chuang #include "sdhci-pci.h" 19347f6be1SBen Chuang #include "cqhci.h" 20e51df6ceSBen Chuang 21e51df6ceSBen Chuang /* Genesys Logic extra registers */ 22e51df6ceSBen Chuang #define SDHCI_GLI_9750_WT 0x800 23e51df6ceSBen Chuang #define SDHCI_GLI_9750_WT_EN BIT(0) 24e51df6ceSBen Chuang #define GLI_9750_WT_EN_ON 0x1 25e51df6ceSBen Chuang #define GLI_9750_WT_EN_OFF 0x0 26e51df6ceSBen Chuang 279751baccSBen Chuang #define SDHCI_GLI_9750_CFG2 0x848 289751baccSBen Chuang #define SDHCI_GLI_9750_CFG2_L1DLY GENMASK(28, 24) 299751baccSBen Chuang #define GLI_9750_CFG2_L1DLY_VALUE 0x1F 309751baccSBen Chuang 31e51df6ceSBen Chuang #define SDHCI_GLI_9750_DRIVING 0x860 32e51df6ceSBen Chuang #define SDHCI_GLI_9750_DRIVING_1 GENMASK(11, 0) 33e51df6ceSBen Chuang #define SDHCI_GLI_9750_DRIVING_2 GENMASK(27, 26) 34e51df6ceSBen Chuang #define GLI_9750_DRIVING_1_VALUE 0xFFF 35e51df6ceSBen Chuang #define GLI_9750_DRIVING_2_VALUE 0x3 36b56ff195SBen Chuang #define SDHCI_GLI_9750_SEL_1 BIT(29) 37b56ff195SBen Chuang #define SDHCI_GLI_9750_SEL_2 BIT(31) 38b56ff195SBen Chuang #define SDHCI_GLI_9750_ALL_RST (BIT(24)|BIT(25)|BIT(28)|BIT(30)) 39e51df6ceSBen Chuang 40e51df6ceSBen Chuang #define SDHCI_GLI_9750_PLL 0x864 41786d33c8SBen Chuang #define SDHCI_GLI_9750_PLL_LDIV GENMASK(9, 0) 42786d33c8SBen Chuang #define SDHCI_GLI_9750_PLL_PDIV GENMASK(14, 12) 43786d33c8SBen Chuang #define SDHCI_GLI_9750_PLL_DIR BIT(15) 44e51df6ceSBen Chuang #define SDHCI_GLI_9750_PLL_TX2_INV BIT(23) 45e51df6ceSBen Chuang #define SDHCI_GLI_9750_PLL_TX2_DLY GENMASK(22, 20) 46e51df6ceSBen Chuang #define GLI_9750_PLL_TX2_INV_VALUE 0x1 47e51df6ceSBen Chuang #define GLI_9750_PLL_TX2_DLY_VALUE 0x0 48786d33c8SBen Chuang #define SDHCI_GLI_9750_PLLSSC_STEP GENMASK(28, 24) 49786d33c8SBen Chuang #define SDHCI_GLI_9750_PLLSSC_EN BIT(31) 50786d33c8SBen Chuang 51786d33c8SBen Chuang #define SDHCI_GLI_9750_PLLSSC 0x86C 52786d33c8SBen Chuang #define SDHCI_GLI_9750_PLLSSC_PPM GENMASK(31, 16) 53e51df6ceSBen Chuang 54e51df6ceSBen Chuang #define SDHCI_GLI_9750_SW_CTRL 0x874 55e51df6ceSBen Chuang #define SDHCI_GLI_9750_SW_CTRL_4 GENMASK(7, 6) 56e51df6ceSBen Chuang #define GLI_9750_SW_CTRL_4_VALUE 0x3 57e51df6ceSBen Chuang 58e51df6ceSBen Chuang #define SDHCI_GLI_9750_MISC 0x878 59e51df6ceSBen Chuang #define SDHCI_GLI_9750_MISC_TX1_INV BIT(2) 60e51df6ceSBen Chuang #define SDHCI_GLI_9750_MISC_RX_INV BIT(3) 61e51df6ceSBen Chuang #define SDHCI_GLI_9750_MISC_TX1_DLY GENMASK(6, 4) 62e51df6ceSBen Chuang #define GLI_9750_MISC_TX1_INV_VALUE 0x0 63e51df6ceSBen Chuang #define GLI_9750_MISC_RX_INV_ON 0x1 64e51df6ceSBen Chuang #define GLI_9750_MISC_RX_INV_OFF 0x0 65e51df6ceSBen Chuang #define GLI_9750_MISC_RX_INV_VALUE GLI_9750_MISC_RX_INV_OFF 66e51df6ceSBen Chuang #define GLI_9750_MISC_TX1_DLY_VALUE 0x5 6708df1a50SBen Chuang #define SDHCI_GLI_9750_MISC_SSC_OFF BIT(26) 68e51df6ceSBen Chuang 69e51df6ceSBen Chuang #define SDHCI_GLI_9750_TUNING_CONTROL 0x540 70e51df6ceSBen Chuang #define SDHCI_GLI_9750_TUNING_CONTROL_EN BIT(4) 71e51df6ceSBen Chuang #define GLI_9750_TUNING_CONTROL_EN_ON 0x1 72e51df6ceSBen Chuang #define GLI_9750_TUNING_CONTROL_EN_OFF 0x0 73e51df6ceSBen Chuang #define SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_1 BIT(16) 74e51df6ceSBen Chuang #define SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_2 GENMASK(20, 19) 75e51df6ceSBen Chuang #define GLI_9750_TUNING_CONTROL_GLITCH_1_VALUE 0x1 76e51df6ceSBen Chuang #define GLI_9750_TUNING_CONTROL_GLITCH_2_VALUE 0x2 77e51df6ceSBen Chuang 78e51df6ceSBen Chuang #define SDHCI_GLI_9750_TUNING_PARAMETERS 0x544 79e51df6ceSBen Chuang #define SDHCI_GLI_9750_TUNING_PARAMETERS_RX_DLY GENMASK(2, 0) 80e51df6ceSBen Chuang #define GLI_9750_TUNING_PARAMETERS_RX_DLY_VALUE 0x1 81e51df6ceSBen Chuang 821ae1d2d6SBen Chuang #define SDHCI_GLI_9763E_CTRL_HS400 0x7 831ae1d2d6SBen Chuang 841ae1d2d6SBen Chuang #define SDHCI_GLI_9763E_HS400_ES_REG 0x52C 851ae1d2d6SBen Chuang #define SDHCI_GLI_9763E_HS400_ES_BIT BIT(8) 861ae1d2d6SBen Chuang 871ae1d2d6SBen Chuang #define PCIE_GLI_9763E_VHS 0x884 881ae1d2d6SBen Chuang #define GLI_9763E_VHS_REV GENMASK(19, 16) 891ae1d2d6SBen Chuang #define GLI_9763E_VHS_REV_R 0x0 901ae1d2d6SBen Chuang #define GLI_9763E_VHS_REV_M 0x1 911ae1d2d6SBen Chuang #define GLI_9763E_VHS_REV_W 0x2 92347f6be1SBen Chuang #define PCIE_GLI_9763E_MB 0x888 93347f6be1SBen Chuang #define GLI_9763E_MB_CMDQ_OFF BIT(19) 9415f908faSRenius Chen #define GLI_9763E_MB_ERP_ON BIT(7) 951ae1d2d6SBen Chuang #define PCIE_GLI_9763E_SCR 0x8E0 961ae1d2d6SBen Chuang #define GLI_9763E_SCR_AXI_REQ BIT(9) 971ae1d2d6SBen Chuang 98edee82f7SRenius Chen #define PCIE_GLI_9763E_CFG2 0x8A4 99edee82f7SRenius Chen #define GLI_9763E_CFG2_L1DLY GENMASK(28, 19) 10034dd3cccSBen Chuang #define GLI_9763E_CFG2_L1DLY_MID 0x54 101edee82f7SRenius Chen 10298991b18SBen Chuang #define PCIE_GLI_9763E_MMC_CTRL 0x960 10398991b18SBen Chuang #define GLI_9763E_HS400_SLOW BIT(3) 10498991b18SBen Chuang 105c58c5950SRenius Chen #define PCIE_GLI_9763E_CLKRXDLY 0x934 106c58c5950SRenius Chen #define GLI_9763E_HS400_RXDLY GENMASK(31, 28) 107c58c5950SRenius Chen #define GLI_9763E_HS400_RXDLY_5 0x5 108c58c5950SRenius Chen 109347f6be1SBen Chuang #define SDHCI_GLI_9763E_CQE_BASE_ADDR 0x200 110347f6be1SBen Chuang #define GLI_9763E_CQE_TRNS_MODE (SDHCI_TRNS_MULTI | \ 111347f6be1SBen Chuang SDHCI_TRNS_BLK_CNT_EN | \ 112347f6be1SBen Chuang SDHCI_TRNS_DMA) 113347f6be1SBen Chuang 114786d33c8SBen Chuang #define PCI_GLI_9755_WT 0x800 115786d33c8SBen Chuang #define PCI_GLI_9755_WT_EN BIT(0) 116786d33c8SBen Chuang #define GLI_9755_WT_EN_ON 0x1 117786d33c8SBen Chuang #define GLI_9755_WT_EN_OFF 0x0 118786d33c8SBen Chuang 1190f1d9961SBen Chuang #define PCI_GLI_9755_PECONF 0x44 1200f1d9961SBen Chuang #define PCI_GLI_9755_LFCLK GENMASK(14, 12) 1210f1d9961SBen Chuang #define PCI_GLI_9755_DMACLK BIT(29) 122189f1d9bSHector Martin #define PCI_GLI_9755_INVERT_CD BIT(30) 123189f1d9bSHector Martin #define PCI_GLI_9755_INVERT_WP BIT(31) 1240f1d9961SBen Chuang 1259751baccSBen Chuang #define PCI_GLI_9755_CFG2 0x48 1269751baccSBen Chuang #define PCI_GLI_9755_CFG2_L1DLY GENMASK(28, 24) 1279751baccSBen Chuang #define GLI_9755_CFG2_L1DLY_VALUE 0x1F 1289751baccSBen Chuang 129786d33c8SBen Chuang #define PCI_GLI_9755_PLL 0x64 130786d33c8SBen Chuang #define PCI_GLI_9755_PLL_LDIV GENMASK(9, 0) 131786d33c8SBen Chuang #define PCI_GLI_9755_PLL_PDIV GENMASK(14, 12) 132786d33c8SBen Chuang #define PCI_GLI_9755_PLL_DIR BIT(15) 133786d33c8SBen Chuang #define PCI_GLI_9755_PLLSSC_STEP GENMASK(28, 24) 134786d33c8SBen Chuang #define PCI_GLI_9755_PLLSSC_EN BIT(31) 135786d33c8SBen Chuang 136786d33c8SBen Chuang #define PCI_GLI_9755_PLLSSC 0x68 137786d33c8SBen Chuang #define PCI_GLI_9755_PLLSSC_PPM GENMASK(15, 0) 138786d33c8SBen Chuang 139f46b54ccSRenius Chen #define PCI_GLI_9755_SerDes 0x70 140f46b54ccSRenius Chen #define PCI_GLI_9755_SCP_DIS BIT(19) 141f46b54ccSRenius Chen 14208df1a50SBen Chuang #define PCI_GLI_9755_MISC 0x78 14308df1a50SBen Chuang #define PCI_GLI_9755_MISC_SSC_OFF BIT(26) 14408df1a50SBen Chuang 14536ed2fd3SBen Chuang #define PCI_GLI_9755_PM_CTRL 0xFC 14636ed2fd3SBen Chuang #define PCI_GLI_9755_PM_STATE GENMASK(1, 0) 14736ed2fd3SBen Chuang 148e51df6ceSBen Chuang #define GLI_MAX_TUNING_LOOP 40 149e51df6ceSBen Chuang 150e51df6ceSBen Chuang /* Genesys Logic chipset */ 151e51df6ceSBen Chuang static inline void gl9750_wt_on(struct sdhci_host *host) 152e51df6ceSBen Chuang { 153e51df6ceSBen Chuang u32 wt_value; 154e51df6ceSBen Chuang u32 wt_enable; 155e51df6ceSBen Chuang 156e51df6ceSBen Chuang wt_value = sdhci_readl(host, SDHCI_GLI_9750_WT); 157e51df6ceSBen Chuang wt_enable = FIELD_GET(SDHCI_GLI_9750_WT_EN, wt_value); 158e51df6ceSBen Chuang 159e51df6ceSBen Chuang if (wt_enable == GLI_9750_WT_EN_ON) 160e51df6ceSBen Chuang return; 161e51df6ceSBen Chuang 162e51df6ceSBen Chuang wt_value &= ~SDHCI_GLI_9750_WT_EN; 163e51df6ceSBen Chuang wt_value |= FIELD_PREP(SDHCI_GLI_9750_WT_EN, GLI_9750_WT_EN_ON); 164e51df6ceSBen Chuang 165e51df6ceSBen Chuang sdhci_writel(host, wt_value, SDHCI_GLI_9750_WT); 166e51df6ceSBen Chuang } 167e51df6ceSBen Chuang 168e51df6ceSBen Chuang static inline void gl9750_wt_off(struct sdhci_host *host) 169e51df6ceSBen Chuang { 170e51df6ceSBen Chuang u32 wt_value; 171e51df6ceSBen Chuang u32 wt_enable; 172e51df6ceSBen Chuang 173e51df6ceSBen Chuang wt_value = sdhci_readl(host, SDHCI_GLI_9750_WT); 174e51df6ceSBen Chuang wt_enable = FIELD_GET(SDHCI_GLI_9750_WT_EN, wt_value); 175e51df6ceSBen Chuang 176e51df6ceSBen Chuang if (wt_enable == GLI_9750_WT_EN_OFF) 177e51df6ceSBen Chuang return; 178e51df6ceSBen Chuang 179e51df6ceSBen Chuang wt_value &= ~SDHCI_GLI_9750_WT_EN; 180e51df6ceSBen Chuang wt_value |= FIELD_PREP(SDHCI_GLI_9750_WT_EN, GLI_9750_WT_EN_OFF); 181e51df6ceSBen Chuang 182e51df6ceSBen Chuang sdhci_writel(host, wt_value, SDHCI_GLI_9750_WT); 183e51df6ceSBen Chuang } 184e51df6ceSBen Chuang 185e51df6ceSBen Chuang static void gli_set_9750(struct sdhci_host *host) 186e51df6ceSBen Chuang { 187e51df6ceSBen Chuang u32 driving_value; 188e51df6ceSBen Chuang u32 pll_value; 189e51df6ceSBen Chuang u32 sw_ctrl_value; 190e51df6ceSBen Chuang u32 misc_value; 191e51df6ceSBen Chuang u32 parameter_value; 192e51df6ceSBen Chuang u32 control_value; 193e51df6ceSBen Chuang u16 ctrl2; 194e51df6ceSBen Chuang 195e51df6ceSBen Chuang gl9750_wt_on(host); 196e51df6ceSBen Chuang 197e51df6ceSBen Chuang driving_value = sdhci_readl(host, SDHCI_GLI_9750_DRIVING); 198e51df6ceSBen Chuang pll_value = sdhci_readl(host, SDHCI_GLI_9750_PLL); 199e51df6ceSBen Chuang sw_ctrl_value = sdhci_readl(host, SDHCI_GLI_9750_SW_CTRL); 200e51df6ceSBen Chuang misc_value = sdhci_readl(host, SDHCI_GLI_9750_MISC); 201e51df6ceSBen Chuang parameter_value = sdhci_readl(host, SDHCI_GLI_9750_TUNING_PARAMETERS); 202e51df6ceSBen Chuang control_value = sdhci_readl(host, SDHCI_GLI_9750_TUNING_CONTROL); 203e51df6ceSBen Chuang 204e51df6ceSBen Chuang driving_value &= ~(SDHCI_GLI_9750_DRIVING_1); 205e51df6ceSBen Chuang driving_value &= ~(SDHCI_GLI_9750_DRIVING_2); 206e51df6ceSBen Chuang driving_value |= FIELD_PREP(SDHCI_GLI_9750_DRIVING_1, 207e51df6ceSBen Chuang GLI_9750_DRIVING_1_VALUE); 208e51df6ceSBen Chuang driving_value |= FIELD_PREP(SDHCI_GLI_9750_DRIVING_2, 209e51df6ceSBen Chuang GLI_9750_DRIVING_2_VALUE); 210b56ff195SBen Chuang driving_value &= ~(SDHCI_GLI_9750_SEL_1|SDHCI_GLI_9750_SEL_2|SDHCI_GLI_9750_ALL_RST); 211b56ff195SBen Chuang driving_value |= SDHCI_GLI_9750_SEL_2; 212e51df6ceSBen Chuang sdhci_writel(host, driving_value, SDHCI_GLI_9750_DRIVING); 213e51df6ceSBen Chuang 214e51df6ceSBen Chuang sw_ctrl_value &= ~SDHCI_GLI_9750_SW_CTRL_4; 215e51df6ceSBen Chuang sw_ctrl_value |= FIELD_PREP(SDHCI_GLI_9750_SW_CTRL_4, 216e51df6ceSBen Chuang GLI_9750_SW_CTRL_4_VALUE); 217e51df6ceSBen Chuang sdhci_writel(host, sw_ctrl_value, SDHCI_GLI_9750_SW_CTRL); 218e51df6ceSBen Chuang 219e51df6ceSBen Chuang /* reset the tuning flow after reinit and before starting tuning */ 220e51df6ceSBen Chuang pll_value &= ~SDHCI_GLI_9750_PLL_TX2_INV; 221e51df6ceSBen Chuang pll_value &= ~SDHCI_GLI_9750_PLL_TX2_DLY; 222e51df6ceSBen Chuang pll_value |= FIELD_PREP(SDHCI_GLI_9750_PLL_TX2_INV, 223e51df6ceSBen Chuang GLI_9750_PLL_TX2_INV_VALUE); 224e51df6ceSBen Chuang pll_value |= FIELD_PREP(SDHCI_GLI_9750_PLL_TX2_DLY, 225e51df6ceSBen Chuang GLI_9750_PLL_TX2_DLY_VALUE); 226e51df6ceSBen Chuang 227e51df6ceSBen Chuang misc_value &= ~SDHCI_GLI_9750_MISC_TX1_INV; 228e51df6ceSBen Chuang misc_value &= ~SDHCI_GLI_9750_MISC_RX_INV; 229e51df6ceSBen Chuang misc_value &= ~SDHCI_GLI_9750_MISC_TX1_DLY; 230e51df6ceSBen Chuang misc_value |= FIELD_PREP(SDHCI_GLI_9750_MISC_TX1_INV, 231e51df6ceSBen Chuang GLI_9750_MISC_TX1_INV_VALUE); 232e51df6ceSBen Chuang misc_value |= FIELD_PREP(SDHCI_GLI_9750_MISC_RX_INV, 233e51df6ceSBen Chuang GLI_9750_MISC_RX_INV_VALUE); 234e51df6ceSBen Chuang misc_value |= FIELD_PREP(SDHCI_GLI_9750_MISC_TX1_DLY, 235e51df6ceSBen Chuang GLI_9750_MISC_TX1_DLY_VALUE); 236e51df6ceSBen Chuang 237e51df6ceSBen Chuang parameter_value &= ~SDHCI_GLI_9750_TUNING_PARAMETERS_RX_DLY; 238e51df6ceSBen Chuang parameter_value |= FIELD_PREP(SDHCI_GLI_9750_TUNING_PARAMETERS_RX_DLY, 239e51df6ceSBen Chuang GLI_9750_TUNING_PARAMETERS_RX_DLY_VALUE); 240e51df6ceSBen Chuang 241e51df6ceSBen Chuang control_value &= ~SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_1; 242e51df6ceSBen Chuang control_value &= ~SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_2; 243e51df6ceSBen Chuang control_value |= FIELD_PREP(SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_1, 244e51df6ceSBen Chuang GLI_9750_TUNING_CONTROL_GLITCH_1_VALUE); 245e51df6ceSBen Chuang control_value |= FIELD_PREP(SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_2, 246e51df6ceSBen Chuang GLI_9750_TUNING_CONTROL_GLITCH_2_VALUE); 247e51df6ceSBen Chuang 248e51df6ceSBen Chuang sdhci_writel(host, pll_value, SDHCI_GLI_9750_PLL); 249e51df6ceSBen Chuang sdhci_writel(host, misc_value, SDHCI_GLI_9750_MISC); 250e51df6ceSBen Chuang 251e51df6ceSBen Chuang /* disable tuned clk */ 252e51df6ceSBen Chuang ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); 253e51df6ceSBen Chuang ctrl2 &= ~SDHCI_CTRL_TUNED_CLK; 254e51df6ceSBen Chuang sdhci_writew(host, ctrl2, SDHCI_HOST_CONTROL2); 255e51df6ceSBen Chuang 256e51df6ceSBen Chuang /* enable tuning parameters control */ 257e51df6ceSBen Chuang control_value &= ~SDHCI_GLI_9750_TUNING_CONTROL_EN; 258e51df6ceSBen Chuang control_value |= FIELD_PREP(SDHCI_GLI_9750_TUNING_CONTROL_EN, 259e51df6ceSBen Chuang GLI_9750_TUNING_CONTROL_EN_ON); 260e51df6ceSBen Chuang sdhci_writel(host, control_value, SDHCI_GLI_9750_TUNING_CONTROL); 261e51df6ceSBen Chuang 262e51df6ceSBen Chuang /* write tuning parameters */ 263e51df6ceSBen Chuang sdhci_writel(host, parameter_value, SDHCI_GLI_9750_TUNING_PARAMETERS); 264e51df6ceSBen Chuang 265e51df6ceSBen Chuang /* disable tuning parameters control */ 266e51df6ceSBen Chuang control_value &= ~SDHCI_GLI_9750_TUNING_CONTROL_EN; 267e51df6ceSBen Chuang control_value |= FIELD_PREP(SDHCI_GLI_9750_TUNING_CONTROL_EN, 268e51df6ceSBen Chuang GLI_9750_TUNING_CONTROL_EN_OFF); 269e51df6ceSBen Chuang sdhci_writel(host, control_value, SDHCI_GLI_9750_TUNING_CONTROL); 270e51df6ceSBen Chuang 271e51df6ceSBen Chuang /* clear tuned clk */ 272e51df6ceSBen Chuang ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); 273e51df6ceSBen Chuang ctrl2 &= ~SDHCI_CTRL_TUNED_CLK; 274e51df6ceSBen Chuang sdhci_writew(host, ctrl2, SDHCI_HOST_CONTROL2); 275e51df6ceSBen Chuang 276e51df6ceSBen Chuang gl9750_wt_off(host); 277e51df6ceSBen Chuang } 278e51df6ceSBen Chuang 279e51df6ceSBen Chuang static void gli_set_9750_rx_inv(struct sdhci_host *host, bool b) 280e51df6ceSBen Chuang { 281e51df6ceSBen Chuang u32 misc_value; 282e51df6ceSBen Chuang 283e51df6ceSBen Chuang gl9750_wt_on(host); 284e51df6ceSBen Chuang 285e51df6ceSBen Chuang misc_value = sdhci_readl(host, SDHCI_GLI_9750_MISC); 286e51df6ceSBen Chuang misc_value &= ~SDHCI_GLI_9750_MISC_RX_INV; 287e51df6ceSBen Chuang if (b) { 288e51df6ceSBen Chuang misc_value |= FIELD_PREP(SDHCI_GLI_9750_MISC_RX_INV, 289e51df6ceSBen Chuang GLI_9750_MISC_RX_INV_ON); 290e51df6ceSBen Chuang } else { 291e51df6ceSBen Chuang misc_value |= FIELD_PREP(SDHCI_GLI_9750_MISC_RX_INV, 292e51df6ceSBen Chuang GLI_9750_MISC_RX_INV_OFF); 293e51df6ceSBen Chuang } 294e51df6ceSBen Chuang sdhci_writel(host, misc_value, SDHCI_GLI_9750_MISC); 295e51df6ceSBen Chuang 296e51df6ceSBen Chuang gl9750_wt_off(host); 297e51df6ceSBen Chuang } 298e51df6ceSBen Chuang 299e51df6ceSBen Chuang static int __sdhci_execute_tuning_9750(struct sdhci_host *host, u32 opcode) 300e51df6ceSBen Chuang { 301e51df6ceSBen Chuang int i; 302e51df6ceSBen Chuang int rx_inv; 303e51df6ceSBen Chuang 304e51df6ceSBen Chuang for (rx_inv = 0; rx_inv < 2; rx_inv++) { 305e51df6ceSBen Chuang gli_set_9750_rx_inv(host, !!rx_inv); 306e51df6ceSBen Chuang sdhci_start_tuning(host); 307e51df6ceSBen Chuang 308e51df6ceSBen Chuang for (i = 0; i < GLI_MAX_TUNING_LOOP; i++) { 309e51df6ceSBen Chuang u16 ctrl; 310e51df6ceSBen Chuang 311e51df6ceSBen Chuang sdhci_send_tuning(host, opcode); 312e51df6ceSBen Chuang 313e51df6ceSBen Chuang if (!host->tuning_done) { 314e51df6ceSBen Chuang sdhci_abort_tuning(host, opcode); 315e51df6ceSBen Chuang break; 316e51df6ceSBen Chuang } 317e51df6ceSBen Chuang 318e51df6ceSBen Chuang ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); 319e51df6ceSBen Chuang if (!(ctrl & SDHCI_CTRL_EXEC_TUNING)) { 320e51df6ceSBen Chuang if (ctrl & SDHCI_CTRL_TUNED_CLK) 321e51df6ceSBen Chuang return 0; /* Success! */ 322e51df6ceSBen Chuang break; 323e51df6ceSBen Chuang } 324e51df6ceSBen Chuang } 325e51df6ceSBen Chuang } 326e51df6ceSBen Chuang if (!host->tuning_done) { 327e51df6ceSBen Chuang pr_info("%s: Tuning timeout, falling back to fixed sampling clock\n", 328e51df6ceSBen Chuang mmc_hostname(host->mmc)); 329e51df6ceSBen Chuang return -ETIMEDOUT; 330e51df6ceSBen Chuang } 331e51df6ceSBen Chuang 332e51df6ceSBen Chuang pr_info("%s: Tuning failed, falling back to fixed sampling clock\n", 333e51df6ceSBen Chuang mmc_hostname(host->mmc)); 334e51df6ceSBen Chuang sdhci_reset_tuning(host); 335e51df6ceSBen Chuang 336e51df6ceSBen Chuang return -EAGAIN; 337e51df6ceSBen Chuang } 338e51df6ceSBen Chuang 339e51df6ceSBen Chuang static int gl9750_execute_tuning(struct sdhci_host *host, u32 opcode) 340e51df6ceSBen Chuang { 341e51df6ceSBen Chuang host->mmc->retune_period = 0; 342e51df6ceSBen Chuang if (host->tuning_mode == SDHCI_TUNING_MODE_1) 343e51df6ceSBen Chuang host->mmc->retune_period = host->tuning_count; 344e51df6ceSBen Chuang 345e51df6ceSBen Chuang gli_set_9750(host); 346e51df6ceSBen Chuang host->tuning_err = __sdhci_execute_tuning_9750(host, opcode); 347e51df6ceSBen Chuang sdhci_end_tuning(host); 348e51df6ceSBen Chuang 349e51df6ceSBen Chuang return 0; 350e51df6ceSBen Chuang } 351e51df6ceSBen Chuang 352786d33c8SBen Chuang static void gl9750_disable_ssc_pll(struct sdhci_host *host) 353786d33c8SBen Chuang { 354786d33c8SBen Chuang u32 pll; 355786d33c8SBen Chuang 356786d33c8SBen Chuang gl9750_wt_on(host); 357786d33c8SBen Chuang pll = sdhci_readl(host, SDHCI_GLI_9750_PLL); 358786d33c8SBen Chuang pll &= ~(SDHCI_GLI_9750_PLL_DIR | SDHCI_GLI_9750_PLLSSC_EN); 359786d33c8SBen Chuang sdhci_writel(host, pll, SDHCI_GLI_9750_PLL); 360786d33c8SBen Chuang gl9750_wt_off(host); 361786d33c8SBen Chuang } 362786d33c8SBen Chuang 363786d33c8SBen Chuang static void gl9750_set_pll(struct sdhci_host *host, u8 dir, u16 ldiv, u8 pdiv) 364786d33c8SBen Chuang { 365786d33c8SBen Chuang u32 pll; 366786d33c8SBen Chuang 367786d33c8SBen Chuang gl9750_wt_on(host); 368786d33c8SBen Chuang pll = sdhci_readl(host, SDHCI_GLI_9750_PLL); 369786d33c8SBen Chuang pll &= ~(SDHCI_GLI_9750_PLL_LDIV | 370786d33c8SBen Chuang SDHCI_GLI_9750_PLL_PDIV | 371786d33c8SBen Chuang SDHCI_GLI_9750_PLL_DIR); 372786d33c8SBen Chuang pll |= FIELD_PREP(SDHCI_GLI_9750_PLL_LDIV, ldiv) | 373786d33c8SBen Chuang FIELD_PREP(SDHCI_GLI_9750_PLL_PDIV, pdiv) | 374786d33c8SBen Chuang FIELD_PREP(SDHCI_GLI_9750_PLL_DIR, dir); 375786d33c8SBen Chuang sdhci_writel(host, pll, SDHCI_GLI_9750_PLL); 376786d33c8SBen Chuang gl9750_wt_off(host); 377786d33c8SBen Chuang 378786d33c8SBen Chuang /* wait for pll stable */ 379786d33c8SBen Chuang mdelay(1); 380786d33c8SBen Chuang } 381786d33c8SBen Chuang 38208df1a50SBen Chuang static bool gl9750_ssc_enable(struct sdhci_host *host) 38308df1a50SBen Chuang { 38408df1a50SBen Chuang u32 misc; 38508df1a50SBen Chuang u8 off; 38608df1a50SBen Chuang 38708df1a50SBen Chuang gl9750_wt_on(host); 38808df1a50SBen Chuang misc = sdhci_readl(host, SDHCI_GLI_9750_MISC); 38908df1a50SBen Chuang off = FIELD_GET(SDHCI_GLI_9750_MISC_SSC_OFF, misc); 39008df1a50SBen Chuang gl9750_wt_off(host); 39108df1a50SBen Chuang 39208df1a50SBen Chuang return !off; 39308df1a50SBen Chuang } 39408df1a50SBen Chuang 395786d33c8SBen Chuang static void gl9750_set_ssc(struct sdhci_host *host, u8 enable, u8 step, u16 ppm) 396786d33c8SBen Chuang { 397786d33c8SBen Chuang u32 pll; 398786d33c8SBen Chuang u32 ssc; 399786d33c8SBen Chuang 400786d33c8SBen Chuang gl9750_wt_on(host); 401786d33c8SBen Chuang pll = sdhci_readl(host, SDHCI_GLI_9750_PLL); 402786d33c8SBen Chuang ssc = sdhci_readl(host, SDHCI_GLI_9750_PLLSSC); 403786d33c8SBen Chuang pll &= ~(SDHCI_GLI_9750_PLLSSC_STEP | 404786d33c8SBen Chuang SDHCI_GLI_9750_PLLSSC_EN); 405786d33c8SBen Chuang ssc &= ~SDHCI_GLI_9750_PLLSSC_PPM; 406786d33c8SBen Chuang pll |= FIELD_PREP(SDHCI_GLI_9750_PLLSSC_STEP, step) | 407786d33c8SBen Chuang FIELD_PREP(SDHCI_GLI_9750_PLLSSC_EN, enable); 408786d33c8SBen Chuang ssc |= FIELD_PREP(SDHCI_GLI_9750_PLLSSC_PPM, ppm); 409786d33c8SBen Chuang sdhci_writel(host, ssc, SDHCI_GLI_9750_PLLSSC); 410786d33c8SBen Chuang sdhci_writel(host, pll, SDHCI_GLI_9750_PLL); 411786d33c8SBen Chuang gl9750_wt_off(host); 412786d33c8SBen Chuang } 413786d33c8SBen Chuang 414786d33c8SBen Chuang static void gl9750_set_ssc_pll_205mhz(struct sdhci_host *host) 415786d33c8SBen Chuang { 41608df1a50SBen Chuang bool enable = gl9750_ssc_enable(host); 41708df1a50SBen Chuang 41808df1a50SBen Chuang /* set pll to 205MHz and ssc */ 41908df1a50SBen Chuang gl9750_set_ssc(host, enable, 0xF, 0x5A1D); 420786d33c8SBen Chuang gl9750_set_pll(host, 0x1, 0x246, 0x0); 421786d33c8SBen Chuang } 422786d33c8SBen Chuang 423d3c6bdb6SBen Chuang static void gl9750_set_ssc_pll_100mhz(struct sdhci_host *host) 424d3c6bdb6SBen Chuang { 42508df1a50SBen Chuang bool enable = gl9750_ssc_enable(host); 42608df1a50SBen Chuang 42708df1a50SBen Chuang /* set pll to 100MHz and ssc */ 42808df1a50SBen Chuang gl9750_set_ssc(host, enable, 0xE, 0x51EC); 429d3c6bdb6SBen Chuang gl9750_set_pll(host, 0x1, 0x244, 0x1); 430d3c6bdb6SBen Chuang } 431d3c6bdb6SBen Chuang 432d3c6bdb6SBen Chuang static void gl9750_set_ssc_pll_50mhz(struct sdhci_host *host) 433d3c6bdb6SBen Chuang { 43408df1a50SBen Chuang bool enable = gl9750_ssc_enable(host); 43508df1a50SBen Chuang 43608df1a50SBen Chuang /* set pll to 50MHz and ssc */ 43708df1a50SBen Chuang gl9750_set_ssc(host, enable, 0xE, 0x51EC); 438d3c6bdb6SBen Chuang gl9750_set_pll(host, 0x1, 0x244, 0x3); 439d3c6bdb6SBen Chuang } 440d3c6bdb6SBen Chuang 441786d33c8SBen Chuang static void sdhci_gl9750_set_clock(struct sdhci_host *host, unsigned int clock) 442786d33c8SBen Chuang { 443786d33c8SBen Chuang struct mmc_ios *ios = &host->mmc->ios; 444786d33c8SBen Chuang u16 clk; 445786d33c8SBen Chuang 446786d33c8SBen Chuang host->mmc->actual_clock = 0; 447786d33c8SBen Chuang 448786d33c8SBen Chuang gl9750_disable_ssc_pll(host); 449786d33c8SBen Chuang sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); 450786d33c8SBen Chuang 451786d33c8SBen Chuang if (clock == 0) 452786d33c8SBen Chuang return; 453786d33c8SBen Chuang 454786d33c8SBen Chuang clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock); 455786d33c8SBen Chuang if (clock == 200000000 && ios->timing == MMC_TIMING_UHS_SDR104) { 456786d33c8SBen Chuang host->mmc->actual_clock = 205000000; 457786d33c8SBen Chuang gl9750_set_ssc_pll_205mhz(host); 458d3c6bdb6SBen Chuang } else if (clock == 100000000) { 459d3c6bdb6SBen Chuang gl9750_set_ssc_pll_100mhz(host); 460d3c6bdb6SBen Chuang } else if (clock == 50000000) { 461d3c6bdb6SBen Chuang gl9750_set_ssc_pll_50mhz(host); 462786d33c8SBen Chuang } 463786d33c8SBen Chuang 464786d33c8SBen Chuang sdhci_enable_clk(host, clk); 465786d33c8SBen Chuang } 466786d33c8SBen Chuang 4679751baccSBen Chuang static void gl9750_hw_setting(struct sdhci_host *host) 4689751baccSBen Chuang { 4699751baccSBen Chuang u32 value; 4709751baccSBen Chuang 4719751baccSBen Chuang gl9750_wt_on(host); 4729751baccSBen Chuang 4739751baccSBen Chuang value = sdhci_readl(host, SDHCI_GLI_9750_CFG2); 4749751baccSBen Chuang value &= ~SDHCI_GLI_9750_CFG2_L1DLY; 4759751baccSBen Chuang /* set ASPM L1 entry delay to 7.9us */ 4769751baccSBen Chuang value |= FIELD_PREP(SDHCI_GLI_9750_CFG2_L1DLY, 4779751baccSBen Chuang GLI_9750_CFG2_L1DLY_VALUE); 4789751baccSBen Chuang sdhci_writel(host, value, SDHCI_GLI_9750_CFG2); 4799751baccSBen Chuang 4809751baccSBen Chuang gl9750_wt_off(host); 4819751baccSBen Chuang } 4829751baccSBen Chuang 48331e43f31SBen Chuang static void gli_pcie_enable_msi(struct sdhci_pci_slot *slot) 48431e43f31SBen Chuang { 48531e43f31SBen Chuang int ret; 48631e43f31SBen Chuang 48731e43f31SBen Chuang ret = pci_alloc_irq_vectors(slot->chip->pdev, 1, 1, 48831e43f31SBen Chuang PCI_IRQ_MSI | PCI_IRQ_MSIX); 48931e43f31SBen Chuang if (ret < 0) { 49031e43f31SBen Chuang pr_warn("%s: enable PCI MSI failed, error=%d\n", 49131e43f31SBen Chuang mmc_hostname(slot->host->mmc), ret); 49231e43f31SBen Chuang return; 49331e43f31SBen Chuang } 49431e43f31SBen Chuang 49531e43f31SBen Chuang slot->host->irq = pci_irq_vector(slot->chip->pdev, 0); 49631e43f31SBen Chuang } 49731e43f31SBen Chuang 498786d33c8SBen Chuang static inline void gl9755_wt_on(struct pci_dev *pdev) 499786d33c8SBen Chuang { 500786d33c8SBen Chuang u32 wt_value; 501786d33c8SBen Chuang u32 wt_enable; 502786d33c8SBen Chuang 503786d33c8SBen Chuang pci_read_config_dword(pdev, PCI_GLI_9755_WT, &wt_value); 504786d33c8SBen Chuang wt_enable = FIELD_GET(PCI_GLI_9755_WT_EN, wt_value); 505786d33c8SBen Chuang 506786d33c8SBen Chuang if (wt_enable == GLI_9755_WT_EN_ON) 507786d33c8SBen Chuang return; 508786d33c8SBen Chuang 509786d33c8SBen Chuang wt_value &= ~PCI_GLI_9755_WT_EN; 510786d33c8SBen Chuang wt_value |= FIELD_PREP(PCI_GLI_9755_WT_EN, GLI_9755_WT_EN_ON); 511786d33c8SBen Chuang 512786d33c8SBen Chuang pci_write_config_dword(pdev, PCI_GLI_9755_WT, wt_value); 513786d33c8SBen Chuang } 514786d33c8SBen Chuang 515786d33c8SBen Chuang static inline void gl9755_wt_off(struct pci_dev *pdev) 516786d33c8SBen Chuang { 517786d33c8SBen Chuang u32 wt_value; 518786d33c8SBen Chuang u32 wt_enable; 519786d33c8SBen Chuang 520786d33c8SBen Chuang pci_read_config_dword(pdev, PCI_GLI_9755_WT, &wt_value); 521786d33c8SBen Chuang wt_enable = FIELD_GET(PCI_GLI_9755_WT_EN, wt_value); 522786d33c8SBen Chuang 523786d33c8SBen Chuang if (wt_enable == GLI_9755_WT_EN_OFF) 524786d33c8SBen Chuang return; 525786d33c8SBen Chuang 526786d33c8SBen Chuang wt_value &= ~PCI_GLI_9755_WT_EN; 527786d33c8SBen Chuang wt_value |= FIELD_PREP(PCI_GLI_9755_WT_EN, GLI_9755_WT_EN_OFF); 528786d33c8SBen Chuang 529786d33c8SBen Chuang pci_write_config_dword(pdev, PCI_GLI_9755_WT, wt_value); 530786d33c8SBen Chuang } 531786d33c8SBen Chuang 532786d33c8SBen Chuang static void gl9755_disable_ssc_pll(struct pci_dev *pdev) 533786d33c8SBen Chuang { 534786d33c8SBen Chuang u32 pll; 535786d33c8SBen Chuang 536786d33c8SBen Chuang gl9755_wt_on(pdev); 537786d33c8SBen Chuang pci_read_config_dword(pdev, PCI_GLI_9755_PLL, &pll); 538786d33c8SBen Chuang pll &= ~(PCI_GLI_9755_PLL_DIR | PCI_GLI_9755_PLLSSC_EN); 539786d33c8SBen Chuang pci_write_config_dword(pdev, PCI_GLI_9755_PLL, pll); 540786d33c8SBen Chuang gl9755_wt_off(pdev); 541786d33c8SBen Chuang } 542786d33c8SBen Chuang 543786d33c8SBen Chuang static void gl9755_set_pll(struct pci_dev *pdev, u8 dir, u16 ldiv, u8 pdiv) 544786d33c8SBen Chuang { 545786d33c8SBen Chuang u32 pll; 546786d33c8SBen Chuang 547786d33c8SBen Chuang gl9755_wt_on(pdev); 548786d33c8SBen Chuang pci_read_config_dword(pdev, PCI_GLI_9755_PLL, &pll); 549786d33c8SBen Chuang pll &= ~(PCI_GLI_9755_PLL_LDIV | 550786d33c8SBen Chuang PCI_GLI_9755_PLL_PDIV | 551786d33c8SBen Chuang PCI_GLI_9755_PLL_DIR); 552786d33c8SBen Chuang pll |= FIELD_PREP(PCI_GLI_9755_PLL_LDIV, ldiv) | 553786d33c8SBen Chuang FIELD_PREP(PCI_GLI_9755_PLL_PDIV, pdiv) | 554786d33c8SBen Chuang FIELD_PREP(PCI_GLI_9755_PLL_DIR, dir); 555786d33c8SBen Chuang pci_write_config_dword(pdev, PCI_GLI_9755_PLL, pll); 556786d33c8SBen Chuang gl9755_wt_off(pdev); 557786d33c8SBen Chuang 558786d33c8SBen Chuang /* wait for pll stable */ 559786d33c8SBen Chuang mdelay(1); 560786d33c8SBen Chuang } 561786d33c8SBen Chuang 56208df1a50SBen Chuang static bool gl9755_ssc_enable(struct pci_dev *pdev) 56308df1a50SBen Chuang { 56408df1a50SBen Chuang u32 misc; 56508df1a50SBen Chuang u8 off; 56608df1a50SBen Chuang 56708df1a50SBen Chuang gl9755_wt_on(pdev); 56808df1a50SBen Chuang pci_read_config_dword(pdev, PCI_GLI_9755_MISC, &misc); 56908df1a50SBen Chuang off = FIELD_GET(PCI_GLI_9755_MISC_SSC_OFF, misc); 57008df1a50SBen Chuang gl9755_wt_off(pdev); 57108df1a50SBen Chuang 57208df1a50SBen Chuang return !off; 57308df1a50SBen Chuang } 57408df1a50SBen Chuang 575786d33c8SBen Chuang static void gl9755_set_ssc(struct pci_dev *pdev, u8 enable, u8 step, u16 ppm) 576786d33c8SBen Chuang { 577786d33c8SBen Chuang u32 pll; 578786d33c8SBen Chuang u32 ssc; 579786d33c8SBen Chuang 580786d33c8SBen Chuang gl9755_wt_on(pdev); 581786d33c8SBen Chuang pci_read_config_dword(pdev, PCI_GLI_9755_PLL, &pll); 582786d33c8SBen Chuang pci_read_config_dword(pdev, PCI_GLI_9755_PLLSSC, &ssc); 583786d33c8SBen Chuang pll &= ~(PCI_GLI_9755_PLLSSC_STEP | 584786d33c8SBen Chuang PCI_GLI_9755_PLLSSC_EN); 585786d33c8SBen Chuang ssc &= ~PCI_GLI_9755_PLLSSC_PPM; 586786d33c8SBen Chuang pll |= FIELD_PREP(PCI_GLI_9755_PLLSSC_STEP, step) | 587786d33c8SBen Chuang FIELD_PREP(PCI_GLI_9755_PLLSSC_EN, enable); 588786d33c8SBen Chuang ssc |= FIELD_PREP(PCI_GLI_9755_PLLSSC_PPM, ppm); 589786d33c8SBen Chuang pci_write_config_dword(pdev, PCI_GLI_9755_PLLSSC, ssc); 590786d33c8SBen Chuang pci_write_config_dword(pdev, PCI_GLI_9755_PLL, pll); 591786d33c8SBen Chuang gl9755_wt_off(pdev); 592786d33c8SBen Chuang } 593786d33c8SBen Chuang 594786d33c8SBen Chuang static void gl9755_set_ssc_pll_205mhz(struct pci_dev *pdev) 595786d33c8SBen Chuang { 59608df1a50SBen Chuang bool enable = gl9755_ssc_enable(pdev); 59708df1a50SBen Chuang 59808df1a50SBen Chuang /* set pll to 205MHz and ssc */ 59908df1a50SBen Chuang gl9755_set_ssc(pdev, enable, 0xF, 0x5A1D); 600786d33c8SBen Chuang gl9755_set_pll(pdev, 0x1, 0x246, 0x0); 601786d33c8SBen Chuang } 602786d33c8SBen Chuang 603d3c6bdb6SBen Chuang static void gl9755_set_ssc_pll_100mhz(struct pci_dev *pdev) 604d3c6bdb6SBen Chuang { 60508df1a50SBen Chuang bool enable = gl9755_ssc_enable(pdev); 60608df1a50SBen Chuang 60708df1a50SBen Chuang /* set pll to 100MHz and ssc */ 60808df1a50SBen Chuang gl9755_set_ssc(pdev, enable, 0xE, 0x51EC); 609d3c6bdb6SBen Chuang gl9755_set_pll(pdev, 0x1, 0x244, 0x1); 610d3c6bdb6SBen Chuang } 611d3c6bdb6SBen Chuang 612d3c6bdb6SBen Chuang static void gl9755_set_ssc_pll_50mhz(struct pci_dev *pdev) 613d3c6bdb6SBen Chuang { 61408df1a50SBen Chuang bool enable = gl9755_ssc_enable(pdev); 61508df1a50SBen Chuang 61608df1a50SBen Chuang /* set pll to 50MHz and ssc */ 61708df1a50SBen Chuang gl9755_set_ssc(pdev, enable, 0xE, 0x51EC); 618d3c6bdb6SBen Chuang gl9755_set_pll(pdev, 0x1, 0x244, 0x3); 619d3c6bdb6SBen Chuang } 620d3c6bdb6SBen Chuang 621786d33c8SBen Chuang static void sdhci_gl9755_set_clock(struct sdhci_host *host, unsigned int clock) 622786d33c8SBen Chuang { 623786d33c8SBen Chuang struct sdhci_pci_slot *slot = sdhci_priv(host); 624786d33c8SBen Chuang struct mmc_ios *ios = &host->mmc->ios; 625786d33c8SBen Chuang struct pci_dev *pdev; 626786d33c8SBen Chuang u16 clk; 627786d33c8SBen Chuang 628786d33c8SBen Chuang pdev = slot->chip->pdev; 629786d33c8SBen Chuang host->mmc->actual_clock = 0; 630786d33c8SBen Chuang 631786d33c8SBen Chuang gl9755_disable_ssc_pll(pdev); 632786d33c8SBen Chuang sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); 633786d33c8SBen Chuang 634786d33c8SBen Chuang if (clock == 0) 635786d33c8SBen Chuang return; 636786d33c8SBen Chuang 637786d33c8SBen Chuang clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock); 638786d33c8SBen Chuang if (clock == 200000000 && ios->timing == MMC_TIMING_UHS_SDR104) { 639786d33c8SBen Chuang host->mmc->actual_clock = 205000000; 640786d33c8SBen Chuang gl9755_set_ssc_pll_205mhz(pdev); 641d3c6bdb6SBen Chuang } else if (clock == 100000000) { 642d3c6bdb6SBen Chuang gl9755_set_ssc_pll_100mhz(pdev); 643d3c6bdb6SBen Chuang } else if (clock == 50000000) { 644d3c6bdb6SBen Chuang gl9755_set_ssc_pll_50mhz(pdev); 645786d33c8SBen Chuang } 646786d33c8SBen Chuang 647786d33c8SBen Chuang sdhci_enable_clk(host, clk); 648786d33c8SBen Chuang } 649786d33c8SBen Chuang 6500f1d9961SBen Chuang static void gl9755_hw_setting(struct sdhci_pci_slot *slot) 6510f1d9961SBen Chuang { 6520f1d9961SBen Chuang struct pci_dev *pdev = slot->chip->pdev; 6530f1d9961SBen Chuang u32 value; 6540f1d9961SBen Chuang 6550f1d9961SBen Chuang gl9755_wt_on(pdev); 6560f1d9961SBen Chuang 6570f1d9961SBen Chuang pci_read_config_dword(pdev, PCI_GLI_9755_PECONF, &value); 658189f1d9bSHector Martin /* 659189f1d9bSHector Martin * Apple ARM64 platforms using these chips may have 660189f1d9bSHector Martin * inverted CD/WP detection. 661189f1d9bSHector Martin */ 662189f1d9bSHector Martin if (of_property_read_bool(pdev->dev.of_node, "cd-inverted")) 663189f1d9bSHector Martin value |= PCI_GLI_9755_INVERT_CD; 664189f1d9bSHector Martin if (of_property_read_bool(pdev->dev.of_node, "wp-inverted")) 665189f1d9bSHector Martin value |= PCI_GLI_9755_INVERT_WP; 6660f1d9961SBen Chuang value &= ~PCI_GLI_9755_LFCLK; 6670f1d9961SBen Chuang value &= ~PCI_GLI_9755_DMACLK; 6680f1d9961SBen Chuang pci_write_config_dword(pdev, PCI_GLI_9755_PECONF, value); 6690f1d9961SBen Chuang 670f46b54ccSRenius Chen /* enable short circuit protection */ 671f46b54ccSRenius Chen pci_read_config_dword(pdev, PCI_GLI_9755_SerDes, &value); 672f46b54ccSRenius Chen value &= ~PCI_GLI_9755_SCP_DIS; 673f46b54ccSRenius Chen pci_write_config_dword(pdev, PCI_GLI_9755_SerDes, value); 674f46b54ccSRenius Chen 6759751baccSBen Chuang pci_read_config_dword(pdev, PCI_GLI_9755_CFG2, &value); 6769751baccSBen Chuang value &= ~PCI_GLI_9755_CFG2_L1DLY; 6779751baccSBen Chuang /* set ASPM L1 entry delay to 7.9us */ 6789751baccSBen Chuang value |= FIELD_PREP(PCI_GLI_9755_CFG2_L1DLY, 6799751baccSBen Chuang GLI_9755_CFG2_L1DLY_VALUE); 6809751baccSBen Chuang pci_write_config_dword(pdev, PCI_GLI_9755_CFG2, value); 6819751baccSBen Chuang 68236ed2fd3SBen Chuang /* toggle PM state to allow GL9755 to enter ASPM L1.2 */ 68336ed2fd3SBen Chuang pci_read_config_dword(pdev, PCI_GLI_9755_PM_CTRL, &value); 68436ed2fd3SBen Chuang value |= PCI_GLI_9755_PM_STATE; 68536ed2fd3SBen Chuang pci_write_config_dword(pdev, PCI_GLI_9755_PM_CTRL, value); 68636ed2fd3SBen Chuang value &= ~PCI_GLI_9755_PM_STATE; 68736ed2fd3SBen Chuang pci_write_config_dword(pdev, PCI_GLI_9755_PM_CTRL, value); 68836ed2fd3SBen Chuang 6890f1d9961SBen Chuang gl9755_wt_off(pdev); 6900f1d9961SBen Chuang } 6910f1d9961SBen Chuang 692e51df6ceSBen Chuang static int gli_probe_slot_gl9750(struct sdhci_pci_slot *slot) 693e51df6ceSBen Chuang { 694e51df6ceSBen Chuang struct sdhci_host *host = slot->host; 695e51df6ceSBen Chuang 6969751baccSBen Chuang gl9750_hw_setting(host); 69731e43f31SBen Chuang gli_pcie_enable_msi(slot); 698e51df6ceSBen Chuang slot->host->mmc->caps2 |= MMC_CAP2_NO_SDIO; 699e51df6ceSBen Chuang sdhci_enable_v4_mode(host); 700e51df6ceSBen Chuang 701e51df6ceSBen Chuang return 0; 702e51df6ceSBen Chuang } 703e51df6ceSBen Chuang 704e51df6ceSBen Chuang static int gli_probe_slot_gl9755(struct sdhci_pci_slot *slot) 705e51df6ceSBen Chuang { 706e51df6ceSBen Chuang struct sdhci_host *host = slot->host; 707e51df6ceSBen Chuang 7080f1d9961SBen Chuang gl9755_hw_setting(slot); 70931e43f31SBen Chuang gli_pcie_enable_msi(slot); 710e51df6ceSBen Chuang slot->host->mmc->caps2 |= MMC_CAP2_NO_SDIO; 711e51df6ceSBen Chuang sdhci_enable_v4_mode(host); 712e51df6ceSBen Chuang 713e51df6ceSBen Chuang return 0; 714e51df6ceSBen Chuang } 715e51df6ceSBen Chuang 716e51df6ceSBen Chuang static void sdhci_gli_voltage_switch(struct sdhci_host *host) 717e51df6ceSBen Chuang { 718e51df6ceSBen Chuang /* 719e51df6ceSBen Chuang * According to Section 3.6.1 signal voltage switch procedure in 720e51df6ceSBen Chuang * SD Host Controller Simplified Spec. 4.20, steps 6~8 are as 721e51df6ceSBen Chuang * follows: 722e51df6ceSBen Chuang * (6) Set 1.8V Signal Enable in the Host Control 2 register. 723e51df6ceSBen Chuang * (7) Wait 5ms. 1.8V voltage regulator shall be stable within this 724e51df6ceSBen Chuang * period. 725e51df6ceSBen Chuang * (8) If 1.8V Signal Enable is cleared by Host Controller, go to 726e51df6ceSBen Chuang * step (12). 727e51df6ceSBen Chuang * 728e51df6ceSBen Chuang * Wait 5ms after set 1.8V signal enable in Host Control 2 register 729e51df6ceSBen Chuang * to ensure 1.8V signal enable bit is set by GL9750/GL9755. 730a1149a6cSDaniel Beer * 731a1149a6cSDaniel Beer * ...however, the controller in the NUC10i3FNK4 (a 9755) requires 732a1149a6cSDaniel Beer * slightly longer than 5ms before the control register reports that 733a1149a6cSDaniel Beer * 1.8V is ready, and far longer still before the card will actually 734a1149a6cSDaniel Beer * work reliably. 735e51df6ceSBen Chuang */ 736a1149a6cSDaniel Beer usleep_range(100000, 110000); 737e51df6ceSBen Chuang } 738e51df6ceSBen Chuang 739e51df6ceSBen Chuang static void sdhci_gl9750_reset(struct sdhci_host *host, u8 mask) 740e51df6ceSBen Chuang { 741e51df6ceSBen Chuang sdhci_reset(host, mask); 742e51df6ceSBen Chuang gli_set_9750(host); 743e51df6ceSBen Chuang } 744e51df6ceSBen Chuang 745e51df6ceSBen Chuang static u32 sdhci_gl9750_readl(struct sdhci_host *host, int reg) 746e51df6ceSBen Chuang { 747e51df6ceSBen Chuang u32 value; 748e51df6ceSBen Chuang 749e51df6ceSBen Chuang value = readl(host->ioaddr + reg); 750e51df6ceSBen Chuang if (unlikely(reg == SDHCI_MAX_CURRENT && !(value & 0xff))) 751e51df6ceSBen Chuang value |= 0xc8; 752e51df6ceSBen Chuang 753e51df6ceSBen Chuang return value; 754e51df6ceSBen Chuang } 755e51df6ceSBen Chuang 756282ede76SBen Chuang #ifdef CONFIG_PM_SLEEP 757282ede76SBen Chuang static int sdhci_pci_gli_resume(struct sdhci_pci_chip *chip) 758282ede76SBen Chuang { 759282ede76SBen Chuang struct sdhci_pci_slot *slot = chip->slots[0]; 760282ede76SBen Chuang 761282ede76SBen Chuang pci_free_irq_vectors(slot->chip->pdev); 762282ede76SBen Chuang gli_pcie_enable_msi(slot); 763282ede76SBen Chuang 764282ede76SBen Chuang return sdhci_pci_resume_host(chip); 765282ede76SBen Chuang } 766347f6be1SBen Chuang 767347f6be1SBen Chuang static int sdhci_cqhci_gli_resume(struct sdhci_pci_chip *chip) 768347f6be1SBen Chuang { 769347f6be1SBen Chuang struct sdhci_pci_slot *slot = chip->slots[0]; 770347f6be1SBen Chuang int ret; 771347f6be1SBen Chuang 772347f6be1SBen Chuang ret = sdhci_pci_gli_resume(chip); 773347f6be1SBen Chuang if (ret) 774347f6be1SBen Chuang return ret; 775347f6be1SBen Chuang 776347f6be1SBen Chuang return cqhci_resume(slot->host->mmc); 777347f6be1SBen Chuang } 778347f6be1SBen Chuang 779347f6be1SBen Chuang static int sdhci_cqhci_gli_suspend(struct sdhci_pci_chip *chip) 780347f6be1SBen Chuang { 781347f6be1SBen Chuang struct sdhci_pci_slot *slot = chip->slots[0]; 782347f6be1SBen Chuang int ret; 783347f6be1SBen Chuang 784347f6be1SBen Chuang ret = cqhci_suspend(slot->host->mmc); 785347f6be1SBen Chuang if (ret) 786347f6be1SBen Chuang return ret; 787347f6be1SBen Chuang 788347f6be1SBen Chuang return sdhci_suspend_host(slot->host); 789347f6be1SBen Chuang } 790282ede76SBen Chuang #endif 791282ede76SBen Chuang 7921ae1d2d6SBen Chuang static void gl9763e_hs400_enhanced_strobe(struct mmc_host *mmc, 7931ae1d2d6SBen Chuang struct mmc_ios *ios) 7941ae1d2d6SBen Chuang { 7951ae1d2d6SBen Chuang struct sdhci_host *host = mmc_priv(mmc); 7961ae1d2d6SBen Chuang u32 val; 7971ae1d2d6SBen Chuang 7981ae1d2d6SBen Chuang val = sdhci_readl(host, SDHCI_GLI_9763E_HS400_ES_REG); 7991ae1d2d6SBen Chuang if (ios->enhanced_strobe) 8001ae1d2d6SBen Chuang val |= SDHCI_GLI_9763E_HS400_ES_BIT; 8011ae1d2d6SBen Chuang else 8021ae1d2d6SBen Chuang val &= ~SDHCI_GLI_9763E_HS400_ES_BIT; 8031ae1d2d6SBen Chuang 8041ae1d2d6SBen Chuang sdhci_writel(host, val, SDHCI_GLI_9763E_HS400_ES_REG); 8051ae1d2d6SBen Chuang } 8061ae1d2d6SBen Chuang 8071ae1d2d6SBen Chuang static void sdhci_set_gl9763e_signaling(struct sdhci_host *host, 8081ae1d2d6SBen Chuang unsigned int timing) 8091ae1d2d6SBen Chuang { 8101ae1d2d6SBen Chuang u16 ctrl_2; 8111ae1d2d6SBen Chuang 8121ae1d2d6SBen Chuang ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); 8131ae1d2d6SBen Chuang ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; 8141ae1d2d6SBen Chuang if (timing == MMC_TIMING_MMC_HS200) 8151ae1d2d6SBen Chuang ctrl_2 |= SDHCI_CTRL_UHS_SDR104; 8161ae1d2d6SBen Chuang else if (timing == MMC_TIMING_MMC_HS) 8171ae1d2d6SBen Chuang ctrl_2 |= SDHCI_CTRL_UHS_SDR25; 8181ae1d2d6SBen Chuang else if (timing == MMC_TIMING_MMC_DDR52) 8191ae1d2d6SBen Chuang ctrl_2 |= SDHCI_CTRL_UHS_DDR50; 8201ae1d2d6SBen Chuang else if (timing == MMC_TIMING_MMC_HS400) 8211ae1d2d6SBen Chuang ctrl_2 |= SDHCI_GLI_9763E_CTRL_HS400; 8221ae1d2d6SBen Chuang 8231ae1d2d6SBen Chuang sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); 8241ae1d2d6SBen Chuang } 8251ae1d2d6SBen Chuang 826347f6be1SBen Chuang static void sdhci_gl9763e_dumpregs(struct mmc_host *mmc) 827347f6be1SBen Chuang { 828347f6be1SBen Chuang sdhci_dumpregs(mmc_priv(mmc)); 829347f6be1SBen Chuang } 830347f6be1SBen Chuang 831347f6be1SBen Chuang static void sdhci_gl9763e_cqe_pre_enable(struct mmc_host *mmc) 832347f6be1SBen Chuang { 833347f6be1SBen Chuang struct cqhci_host *cq_host = mmc->cqe_private; 834347f6be1SBen Chuang u32 value; 835347f6be1SBen Chuang 836347f6be1SBen Chuang value = cqhci_readl(cq_host, CQHCI_CFG); 837347f6be1SBen Chuang value |= CQHCI_ENABLE; 838347f6be1SBen Chuang cqhci_writel(cq_host, value, CQHCI_CFG); 839347f6be1SBen Chuang } 840347f6be1SBen Chuang 841347f6be1SBen Chuang static void sdhci_gl9763e_cqe_enable(struct mmc_host *mmc) 842347f6be1SBen Chuang { 843347f6be1SBen Chuang struct sdhci_host *host = mmc_priv(mmc); 844347f6be1SBen Chuang 845347f6be1SBen Chuang sdhci_writew(host, GLI_9763E_CQE_TRNS_MODE, SDHCI_TRANSFER_MODE); 846347f6be1SBen Chuang sdhci_cqe_enable(mmc); 847347f6be1SBen Chuang } 848347f6be1SBen Chuang 849347f6be1SBen Chuang static u32 sdhci_gl9763e_cqhci_irq(struct sdhci_host *host, u32 intmask) 850347f6be1SBen Chuang { 851347f6be1SBen Chuang int cmd_error = 0; 852347f6be1SBen Chuang int data_error = 0; 853347f6be1SBen Chuang 854347f6be1SBen Chuang if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error)) 855347f6be1SBen Chuang return intmask; 856347f6be1SBen Chuang 857347f6be1SBen Chuang cqhci_irq(host->mmc, intmask, cmd_error, data_error); 858347f6be1SBen Chuang 859347f6be1SBen Chuang return 0; 860347f6be1SBen Chuang } 861347f6be1SBen Chuang 862347f6be1SBen Chuang static void sdhci_gl9763e_cqe_post_disable(struct mmc_host *mmc) 863347f6be1SBen Chuang { 864347f6be1SBen Chuang struct sdhci_host *host = mmc_priv(mmc); 865347f6be1SBen Chuang struct cqhci_host *cq_host = mmc->cqe_private; 866347f6be1SBen Chuang u32 value; 867347f6be1SBen Chuang 868347f6be1SBen Chuang value = cqhci_readl(cq_host, CQHCI_CFG); 869347f6be1SBen Chuang value &= ~CQHCI_ENABLE; 870347f6be1SBen Chuang cqhci_writel(cq_host, value, CQHCI_CFG); 871347f6be1SBen Chuang sdhci_writew(host, 0x0, SDHCI_TRANSFER_MODE); 872347f6be1SBen Chuang } 873347f6be1SBen Chuang 874347f6be1SBen Chuang static const struct cqhci_host_ops sdhci_gl9763e_cqhci_ops = { 875347f6be1SBen Chuang .enable = sdhci_gl9763e_cqe_enable, 876347f6be1SBen Chuang .disable = sdhci_cqe_disable, 877347f6be1SBen Chuang .dumpregs = sdhci_gl9763e_dumpregs, 878347f6be1SBen Chuang .pre_enable = sdhci_gl9763e_cqe_pre_enable, 879347f6be1SBen Chuang .post_disable = sdhci_gl9763e_cqe_post_disable, 880347f6be1SBen Chuang }; 881347f6be1SBen Chuang 882347f6be1SBen Chuang static int gl9763e_add_host(struct sdhci_pci_slot *slot) 883347f6be1SBen Chuang { 884347f6be1SBen Chuang struct device *dev = &slot->chip->pdev->dev; 885347f6be1SBen Chuang struct sdhci_host *host = slot->host; 886347f6be1SBen Chuang struct cqhci_host *cq_host; 887347f6be1SBen Chuang bool dma64; 888347f6be1SBen Chuang int ret; 889347f6be1SBen Chuang 890347f6be1SBen Chuang ret = sdhci_setup_host(host); 891347f6be1SBen Chuang if (ret) 892347f6be1SBen Chuang return ret; 893347f6be1SBen Chuang 894347f6be1SBen Chuang cq_host = devm_kzalloc(dev, sizeof(*cq_host), GFP_KERNEL); 895347f6be1SBen Chuang if (!cq_host) { 896347f6be1SBen Chuang ret = -ENOMEM; 897347f6be1SBen Chuang goto cleanup; 898347f6be1SBen Chuang } 899347f6be1SBen Chuang 900347f6be1SBen Chuang cq_host->mmio = host->ioaddr + SDHCI_GLI_9763E_CQE_BASE_ADDR; 901347f6be1SBen Chuang cq_host->ops = &sdhci_gl9763e_cqhci_ops; 902347f6be1SBen Chuang 903347f6be1SBen Chuang dma64 = host->flags & SDHCI_USE_64_BIT_DMA; 904347f6be1SBen Chuang if (dma64) 905347f6be1SBen Chuang cq_host->caps |= CQHCI_TASK_DESC_SZ_128; 906347f6be1SBen Chuang 907347f6be1SBen Chuang ret = cqhci_init(cq_host, host->mmc, dma64); 908347f6be1SBen Chuang if (ret) 909347f6be1SBen Chuang goto cleanup; 910347f6be1SBen Chuang 911347f6be1SBen Chuang ret = __sdhci_add_host(host); 912347f6be1SBen Chuang if (ret) 913347f6be1SBen Chuang goto cleanup; 914347f6be1SBen Chuang 915347f6be1SBen Chuang return 0; 916347f6be1SBen Chuang 917347f6be1SBen Chuang cleanup: 918347f6be1SBen Chuang sdhci_cleanup_host(host); 919347f6be1SBen Chuang return ret; 920347f6be1SBen Chuang } 921347f6be1SBen Chuang 922347f6be1SBen Chuang static void sdhci_gl9763e_reset(struct sdhci_host *host, u8 mask) 923347f6be1SBen Chuang { 924347f6be1SBen Chuang if ((host->mmc->caps2 & MMC_CAP2_CQE) && (mask & SDHCI_RESET_ALL) && 925347f6be1SBen Chuang host->mmc->cqe_private) 926347f6be1SBen Chuang cqhci_deactivate(host->mmc); 927347f6be1SBen Chuang sdhci_reset(host, mask); 928347f6be1SBen Chuang } 929347f6be1SBen Chuang 9301ae1d2d6SBen Chuang static void gli_set_gl9763e(struct sdhci_pci_slot *slot) 9311ae1d2d6SBen Chuang { 9321ae1d2d6SBen Chuang struct pci_dev *pdev = slot->chip->pdev; 9331ae1d2d6SBen Chuang u32 value; 9341ae1d2d6SBen Chuang 9351ae1d2d6SBen Chuang pci_read_config_dword(pdev, PCIE_GLI_9763E_VHS, &value); 9361ae1d2d6SBen Chuang value &= ~GLI_9763E_VHS_REV; 9371ae1d2d6SBen Chuang value |= FIELD_PREP(GLI_9763E_VHS_REV, GLI_9763E_VHS_REV_W); 9381ae1d2d6SBen Chuang pci_write_config_dword(pdev, PCIE_GLI_9763E_VHS, value); 9391ae1d2d6SBen Chuang 9401ae1d2d6SBen Chuang pci_read_config_dword(pdev, PCIE_GLI_9763E_SCR, &value); 9411ae1d2d6SBen Chuang value |= GLI_9763E_SCR_AXI_REQ; 9421ae1d2d6SBen Chuang pci_write_config_dword(pdev, PCIE_GLI_9763E_SCR, value); 9431ae1d2d6SBen Chuang 94498991b18SBen Chuang pci_read_config_dword(pdev, PCIE_GLI_9763E_MMC_CTRL, &value); 94598991b18SBen Chuang value &= ~GLI_9763E_HS400_SLOW; 94698991b18SBen Chuang pci_write_config_dword(pdev, PCIE_GLI_9763E_MMC_CTRL, value); 94798991b18SBen Chuang 948edee82f7SRenius Chen pci_read_config_dword(pdev, PCIE_GLI_9763E_CFG2, &value); 949edee82f7SRenius Chen value &= ~GLI_9763E_CFG2_L1DLY; 95034dd3cccSBen Chuang /* set ASPM L1 entry delay to 21us */ 951baaaf55dSBen Chuang value |= FIELD_PREP(GLI_9763E_CFG2_L1DLY, GLI_9763E_CFG2_L1DLY_MID); 952edee82f7SRenius Chen pci_write_config_dword(pdev, PCIE_GLI_9763E_CFG2, value); 953edee82f7SRenius Chen 954c58c5950SRenius Chen pci_read_config_dword(pdev, PCIE_GLI_9763E_CLKRXDLY, &value); 955c58c5950SRenius Chen value &= ~GLI_9763E_HS400_RXDLY; 956c58c5950SRenius Chen value |= FIELD_PREP(GLI_9763E_HS400_RXDLY, GLI_9763E_HS400_RXDLY_5); 957c58c5950SRenius Chen pci_write_config_dword(pdev, PCIE_GLI_9763E_CLKRXDLY, value); 958c58c5950SRenius Chen 9591ae1d2d6SBen Chuang pci_read_config_dword(pdev, PCIE_GLI_9763E_VHS, &value); 9601ae1d2d6SBen Chuang value &= ~GLI_9763E_VHS_REV; 9611ae1d2d6SBen Chuang value |= FIELD_PREP(GLI_9763E_VHS_REV, GLI_9763E_VHS_REV_R); 9621ae1d2d6SBen Chuang pci_write_config_dword(pdev, PCIE_GLI_9763E_VHS, value); 9631ae1d2d6SBen Chuang } 9641ae1d2d6SBen Chuang 965d607667bSBen Chuang #ifdef CONFIG_PM 966d607667bSBen Chuang static int gl9763e_runtime_suspend(struct sdhci_pci_chip *chip) 967d607667bSBen Chuang { 968d607667bSBen Chuang struct sdhci_pci_slot *slot = chip->slots[0]; 969d607667bSBen Chuang struct sdhci_host *host = slot->host; 970d607667bSBen Chuang u16 clock; 971d607667bSBen Chuang 972d607667bSBen Chuang clock = sdhci_readw(host, SDHCI_CLOCK_CONTROL); 973d607667bSBen Chuang clock &= ~(SDHCI_CLOCK_PLL_EN | SDHCI_CLOCK_CARD_EN); 974d607667bSBen Chuang sdhci_writew(host, clock, SDHCI_CLOCK_CONTROL); 975d607667bSBen Chuang 976d607667bSBen Chuang return 0; 977d607667bSBen Chuang } 978d607667bSBen Chuang 979d607667bSBen Chuang static int gl9763e_runtime_resume(struct sdhci_pci_chip *chip) 980d607667bSBen Chuang { 981d607667bSBen Chuang struct sdhci_pci_slot *slot = chip->slots[0]; 982d607667bSBen Chuang struct sdhci_host *host = slot->host; 983d607667bSBen Chuang u16 clock; 984d607667bSBen Chuang 985*291e7d52SBen Chuang if (host->mmc->ios.power_mode != MMC_POWER_ON) 986*291e7d52SBen Chuang return 0; 987*291e7d52SBen Chuang 988d607667bSBen Chuang clock = sdhci_readw(host, SDHCI_CLOCK_CONTROL); 989d607667bSBen Chuang 990d607667bSBen Chuang clock |= SDHCI_CLOCK_PLL_EN; 991d607667bSBen Chuang clock &= ~SDHCI_CLOCK_INT_STABLE; 992d607667bSBen Chuang sdhci_writew(host, clock, SDHCI_CLOCK_CONTROL); 993d607667bSBen Chuang 994d607667bSBen Chuang /* Wait max 150 ms */ 995d607667bSBen Chuang if (read_poll_timeout(sdhci_readw, clock, (clock & SDHCI_CLOCK_INT_STABLE), 996d607667bSBen Chuang 1000, 150000, false, host, SDHCI_CLOCK_CONTROL)) { 997d607667bSBen Chuang pr_err("%s: PLL clock never stabilised.\n", 998d607667bSBen Chuang mmc_hostname(host->mmc)); 999d607667bSBen Chuang sdhci_dumpregs(host); 1000d607667bSBen Chuang } 1001d607667bSBen Chuang 1002d607667bSBen Chuang clock |= SDHCI_CLOCK_CARD_EN; 1003d607667bSBen Chuang sdhci_writew(host, clock, SDHCI_CLOCK_CONTROL); 1004d607667bSBen Chuang 1005d607667bSBen Chuang return 0; 1006d607667bSBen Chuang } 1007d607667bSBen Chuang #endif 1008d607667bSBen Chuang 10091ae1d2d6SBen Chuang static int gli_probe_slot_gl9763e(struct sdhci_pci_slot *slot) 10101ae1d2d6SBen Chuang { 1011347f6be1SBen Chuang struct pci_dev *pdev = slot->chip->pdev; 10121ae1d2d6SBen Chuang struct sdhci_host *host = slot->host; 1013347f6be1SBen Chuang u32 value; 10141ae1d2d6SBen Chuang 10151ae1d2d6SBen Chuang host->mmc->caps |= MMC_CAP_8_BIT_DATA | 10161ae1d2d6SBen Chuang MMC_CAP_1_8V_DDR | 10171ae1d2d6SBen Chuang MMC_CAP_NONREMOVABLE; 10181ae1d2d6SBen Chuang host->mmc->caps2 |= MMC_CAP2_HS200_1_8V_SDR | 10191ae1d2d6SBen Chuang MMC_CAP2_HS400_1_8V | 10201ae1d2d6SBen Chuang MMC_CAP2_HS400_ES | 10211ae1d2d6SBen Chuang MMC_CAP2_NO_SDIO | 10221ae1d2d6SBen Chuang MMC_CAP2_NO_SD; 1023347f6be1SBen Chuang 1024347f6be1SBen Chuang pci_read_config_dword(pdev, PCIE_GLI_9763E_MB, &value); 1025347f6be1SBen Chuang if (!(value & GLI_9763E_MB_CMDQ_OFF)) 102615f908faSRenius Chen if (value & GLI_9763E_MB_ERP_ON) 1027347f6be1SBen Chuang host->mmc->caps2 |= MMC_CAP2_CQE | MMC_CAP2_CQE_DCMD; 1028347f6be1SBen Chuang 10291ae1d2d6SBen Chuang gli_pcie_enable_msi(slot); 10301ae1d2d6SBen Chuang host->mmc_host_ops.hs400_enhanced_strobe = 10311ae1d2d6SBen Chuang gl9763e_hs400_enhanced_strobe; 10321ae1d2d6SBen Chuang gli_set_gl9763e(slot); 10331ae1d2d6SBen Chuang sdhci_enable_v4_mode(host); 10341ae1d2d6SBen Chuang 10351ae1d2d6SBen Chuang return 0; 10361ae1d2d6SBen Chuang } 10371ae1d2d6SBen Chuang 1038c064bb5cSHector Martin #define REG_OFFSET_IN_BITS(reg) ((reg) << 3 & 0x18) 1039c064bb5cSHector Martin 1040c064bb5cSHector Martin static u16 sdhci_gli_readw(struct sdhci_host *host, int reg) 1041c064bb5cSHector Martin { 1042c064bb5cSHector Martin u32 val = readl(host->ioaddr + (reg & ~3)); 1043c064bb5cSHector Martin u16 word; 1044c064bb5cSHector Martin 1045c064bb5cSHector Martin word = (val >> REG_OFFSET_IN_BITS(reg)) & 0xffff; 1046c064bb5cSHector Martin return word; 1047c064bb5cSHector Martin } 1048c064bb5cSHector Martin 1049c064bb5cSHector Martin static u8 sdhci_gli_readb(struct sdhci_host *host, int reg) 1050c064bb5cSHector Martin { 1051c064bb5cSHector Martin u32 val = readl(host->ioaddr + (reg & ~3)); 1052c064bb5cSHector Martin u8 byte = (val >> REG_OFFSET_IN_BITS(reg)) & 0xff; 1053c064bb5cSHector Martin 1054c064bb5cSHector Martin return byte; 1055c064bb5cSHector Martin } 1056c064bb5cSHector Martin 1057e51df6ceSBen Chuang static const struct sdhci_ops sdhci_gl9755_ops = { 1058c064bb5cSHector Martin .read_w = sdhci_gli_readw, 1059c064bb5cSHector Martin .read_b = sdhci_gli_readb, 1060786d33c8SBen Chuang .set_clock = sdhci_gl9755_set_clock, 1061e51df6ceSBen Chuang .enable_dma = sdhci_pci_enable_dma, 1062e51df6ceSBen Chuang .set_bus_width = sdhci_set_bus_width, 1063e51df6ceSBen Chuang .reset = sdhci_reset, 1064e51df6ceSBen Chuang .set_uhs_signaling = sdhci_set_uhs_signaling, 1065e51df6ceSBen Chuang .voltage_switch = sdhci_gli_voltage_switch, 1066e51df6ceSBen Chuang }; 1067e51df6ceSBen Chuang 1068e51df6ceSBen Chuang const struct sdhci_pci_fixes sdhci_gl9755 = { 1069e51df6ceSBen Chuang .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, 1070e51df6ceSBen Chuang .quirks2 = SDHCI_QUIRK2_BROKEN_DDR50, 1071e51df6ceSBen Chuang .probe_slot = gli_probe_slot_gl9755, 1072e51df6ceSBen Chuang .ops = &sdhci_gl9755_ops, 1073282ede76SBen Chuang #ifdef CONFIG_PM_SLEEP 1074282ede76SBen Chuang .resume = sdhci_pci_gli_resume, 1075282ede76SBen Chuang #endif 1076e51df6ceSBen Chuang }; 1077e51df6ceSBen Chuang 1078e51df6ceSBen Chuang static const struct sdhci_ops sdhci_gl9750_ops = { 1079c064bb5cSHector Martin .read_w = sdhci_gli_readw, 1080c064bb5cSHector Martin .read_b = sdhci_gli_readb, 1081e51df6ceSBen Chuang .read_l = sdhci_gl9750_readl, 1082786d33c8SBen Chuang .set_clock = sdhci_gl9750_set_clock, 1083e51df6ceSBen Chuang .enable_dma = sdhci_pci_enable_dma, 1084e51df6ceSBen Chuang .set_bus_width = sdhci_set_bus_width, 1085e51df6ceSBen Chuang .reset = sdhci_gl9750_reset, 1086e51df6ceSBen Chuang .set_uhs_signaling = sdhci_set_uhs_signaling, 1087e51df6ceSBen Chuang .voltage_switch = sdhci_gli_voltage_switch, 1088e51df6ceSBen Chuang .platform_execute_tuning = gl9750_execute_tuning, 1089e51df6ceSBen Chuang }; 1090e51df6ceSBen Chuang 1091e51df6ceSBen Chuang const struct sdhci_pci_fixes sdhci_gl9750 = { 1092e51df6ceSBen Chuang .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, 1093e51df6ceSBen Chuang .quirks2 = SDHCI_QUIRK2_BROKEN_DDR50, 1094e51df6ceSBen Chuang .probe_slot = gli_probe_slot_gl9750, 1095e51df6ceSBen Chuang .ops = &sdhci_gl9750_ops, 1096282ede76SBen Chuang #ifdef CONFIG_PM_SLEEP 1097282ede76SBen Chuang .resume = sdhci_pci_gli_resume, 1098282ede76SBen Chuang #endif 1099e51df6ceSBen Chuang }; 11001ae1d2d6SBen Chuang 11011ae1d2d6SBen Chuang static const struct sdhci_ops sdhci_gl9763e_ops = { 11021ae1d2d6SBen Chuang .set_clock = sdhci_set_clock, 11031ae1d2d6SBen Chuang .enable_dma = sdhci_pci_enable_dma, 11041ae1d2d6SBen Chuang .set_bus_width = sdhci_set_bus_width, 1105347f6be1SBen Chuang .reset = sdhci_gl9763e_reset, 11061ae1d2d6SBen Chuang .set_uhs_signaling = sdhci_set_gl9763e_signaling, 11071ae1d2d6SBen Chuang .voltage_switch = sdhci_gli_voltage_switch, 1108347f6be1SBen Chuang .irq = sdhci_gl9763e_cqhci_irq, 11091ae1d2d6SBen Chuang }; 11101ae1d2d6SBen Chuang 11111ae1d2d6SBen Chuang const struct sdhci_pci_fixes sdhci_gl9763e = { 11121ae1d2d6SBen Chuang .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, 11131ae1d2d6SBen Chuang .probe_slot = gli_probe_slot_gl9763e, 11141ae1d2d6SBen Chuang .ops = &sdhci_gl9763e_ops, 11151ae1d2d6SBen Chuang #ifdef CONFIG_PM_SLEEP 1116347f6be1SBen Chuang .resume = sdhci_cqhci_gli_resume, 1117347f6be1SBen Chuang .suspend = sdhci_cqhci_gli_suspend, 11181ae1d2d6SBen Chuang #endif 1119d607667bSBen Chuang #ifdef CONFIG_PM 1120d607667bSBen Chuang .runtime_suspend = gl9763e_runtime_suspend, 1121d607667bSBen Chuang .runtime_resume = gl9763e_runtime_resume, 1122d607667bSBen Chuang .allow_runtime_pm = true, 1123d607667bSBen Chuang #endif 1124347f6be1SBen Chuang .add_host = gl9763e_add_host, 11251ae1d2d6SBen Chuang }; 1126