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> 15e51df6ceSBen Chuang #include "sdhci.h" 16e51df6ceSBen Chuang #include "sdhci-pci.h" 17347f6be1SBen Chuang #include "cqhci.h" 18e51df6ceSBen Chuang 19e51df6ceSBen Chuang /* Genesys Logic extra registers */ 20e51df6ceSBen Chuang #define SDHCI_GLI_9750_WT 0x800 21e51df6ceSBen Chuang #define SDHCI_GLI_9750_WT_EN BIT(0) 22e51df6ceSBen Chuang #define GLI_9750_WT_EN_ON 0x1 23e51df6ceSBen Chuang #define GLI_9750_WT_EN_OFF 0x0 24e51df6ceSBen Chuang 25e51df6ceSBen Chuang #define SDHCI_GLI_9750_DRIVING 0x860 26e51df6ceSBen Chuang #define SDHCI_GLI_9750_DRIVING_1 GENMASK(11, 0) 27e51df6ceSBen Chuang #define SDHCI_GLI_9750_DRIVING_2 GENMASK(27, 26) 28e51df6ceSBen Chuang #define GLI_9750_DRIVING_1_VALUE 0xFFF 29e51df6ceSBen Chuang #define GLI_9750_DRIVING_2_VALUE 0x3 30b56ff195SBen Chuang #define SDHCI_GLI_9750_SEL_1 BIT(29) 31b56ff195SBen Chuang #define SDHCI_GLI_9750_SEL_2 BIT(31) 32b56ff195SBen Chuang #define SDHCI_GLI_9750_ALL_RST (BIT(24)|BIT(25)|BIT(28)|BIT(30)) 33e51df6ceSBen Chuang 34e51df6ceSBen Chuang #define SDHCI_GLI_9750_PLL 0x864 35786d33c8SBen Chuang #define SDHCI_GLI_9750_PLL_LDIV GENMASK(9, 0) 36786d33c8SBen Chuang #define SDHCI_GLI_9750_PLL_PDIV GENMASK(14, 12) 37786d33c8SBen Chuang #define SDHCI_GLI_9750_PLL_DIR BIT(15) 38e51df6ceSBen Chuang #define SDHCI_GLI_9750_PLL_TX2_INV BIT(23) 39e51df6ceSBen Chuang #define SDHCI_GLI_9750_PLL_TX2_DLY GENMASK(22, 20) 40e51df6ceSBen Chuang #define GLI_9750_PLL_TX2_INV_VALUE 0x1 41e51df6ceSBen Chuang #define GLI_9750_PLL_TX2_DLY_VALUE 0x0 42786d33c8SBen Chuang #define SDHCI_GLI_9750_PLLSSC_STEP GENMASK(28, 24) 43786d33c8SBen Chuang #define SDHCI_GLI_9750_PLLSSC_EN BIT(31) 44786d33c8SBen Chuang 45786d33c8SBen Chuang #define SDHCI_GLI_9750_PLLSSC 0x86C 46786d33c8SBen Chuang #define SDHCI_GLI_9750_PLLSSC_PPM GENMASK(31, 16) 47e51df6ceSBen Chuang 48e51df6ceSBen Chuang #define SDHCI_GLI_9750_SW_CTRL 0x874 49e51df6ceSBen Chuang #define SDHCI_GLI_9750_SW_CTRL_4 GENMASK(7, 6) 50e51df6ceSBen Chuang #define GLI_9750_SW_CTRL_4_VALUE 0x3 51e51df6ceSBen Chuang 52e51df6ceSBen Chuang #define SDHCI_GLI_9750_MISC 0x878 53e51df6ceSBen Chuang #define SDHCI_GLI_9750_MISC_TX1_INV BIT(2) 54e51df6ceSBen Chuang #define SDHCI_GLI_9750_MISC_RX_INV BIT(3) 55e51df6ceSBen Chuang #define SDHCI_GLI_9750_MISC_TX1_DLY GENMASK(6, 4) 56e51df6ceSBen Chuang #define GLI_9750_MISC_TX1_INV_VALUE 0x0 57e51df6ceSBen Chuang #define GLI_9750_MISC_RX_INV_ON 0x1 58e51df6ceSBen Chuang #define GLI_9750_MISC_RX_INV_OFF 0x0 59e51df6ceSBen Chuang #define GLI_9750_MISC_RX_INV_VALUE GLI_9750_MISC_RX_INV_OFF 60e51df6ceSBen Chuang #define GLI_9750_MISC_TX1_DLY_VALUE 0x5 61e51df6ceSBen Chuang 62e51df6ceSBen Chuang #define SDHCI_GLI_9750_TUNING_CONTROL 0x540 63e51df6ceSBen Chuang #define SDHCI_GLI_9750_TUNING_CONTROL_EN BIT(4) 64e51df6ceSBen Chuang #define GLI_9750_TUNING_CONTROL_EN_ON 0x1 65e51df6ceSBen Chuang #define GLI_9750_TUNING_CONTROL_EN_OFF 0x0 66e51df6ceSBen Chuang #define SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_1 BIT(16) 67e51df6ceSBen Chuang #define SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_2 GENMASK(20, 19) 68e51df6ceSBen Chuang #define GLI_9750_TUNING_CONTROL_GLITCH_1_VALUE 0x1 69e51df6ceSBen Chuang #define GLI_9750_TUNING_CONTROL_GLITCH_2_VALUE 0x2 70e51df6ceSBen Chuang 71e51df6ceSBen Chuang #define SDHCI_GLI_9750_TUNING_PARAMETERS 0x544 72e51df6ceSBen Chuang #define SDHCI_GLI_9750_TUNING_PARAMETERS_RX_DLY GENMASK(2, 0) 73e51df6ceSBen Chuang #define GLI_9750_TUNING_PARAMETERS_RX_DLY_VALUE 0x1 74e51df6ceSBen Chuang 751ae1d2d6SBen Chuang #define SDHCI_GLI_9763E_CTRL_HS400 0x7 761ae1d2d6SBen Chuang 771ae1d2d6SBen Chuang #define SDHCI_GLI_9763E_HS400_ES_REG 0x52C 781ae1d2d6SBen Chuang #define SDHCI_GLI_9763E_HS400_ES_BIT BIT(8) 791ae1d2d6SBen Chuang 801ae1d2d6SBen Chuang #define PCIE_GLI_9763E_VHS 0x884 811ae1d2d6SBen Chuang #define GLI_9763E_VHS_REV GENMASK(19, 16) 821ae1d2d6SBen Chuang #define GLI_9763E_VHS_REV_R 0x0 831ae1d2d6SBen Chuang #define GLI_9763E_VHS_REV_M 0x1 841ae1d2d6SBen Chuang #define GLI_9763E_VHS_REV_W 0x2 85347f6be1SBen Chuang #define PCIE_GLI_9763E_MB 0x888 86347f6be1SBen Chuang #define GLI_9763E_MB_CMDQ_OFF BIT(19) 871ae1d2d6SBen Chuang #define PCIE_GLI_9763E_SCR 0x8E0 881ae1d2d6SBen Chuang #define GLI_9763E_SCR_AXI_REQ BIT(9) 891ae1d2d6SBen Chuang 90347f6be1SBen Chuang #define SDHCI_GLI_9763E_CQE_BASE_ADDR 0x200 91347f6be1SBen Chuang #define GLI_9763E_CQE_TRNS_MODE (SDHCI_TRNS_MULTI | \ 92347f6be1SBen Chuang SDHCI_TRNS_BLK_CNT_EN | \ 93347f6be1SBen Chuang SDHCI_TRNS_DMA) 94347f6be1SBen Chuang 95786d33c8SBen Chuang #define PCI_GLI_9755_WT 0x800 96786d33c8SBen Chuang #define PCI_GLI_9755_WT_EN BIT(0) 97786d33c8SBen Chuang #define GLI_9755_WT_EN_ON 0x1 98786d33c8SBen Chuang #define GLI_9755_WT_EN_OFF 0x0 99786d33c8SBen Chuang 100*0f1d9961SBen Chuang #define PCI_GLI_9755_PECONF 0x44 101*0f1d9961SBen Chuang #define PCI_GLI_9755_LFCLK GENMASK(14, 12) 102*0f1d9961SBen Chuang #define PCI_GLI_9755_DMACLK BIT(29) 103*0f1d9961SBen Chuang 104786d33c8SBen Chuang #define PCI_GLI_9755_PLL 0x64 105786d33c8SBen Chuang #define PCI_GLI_9755_PLL_LDIV GENMASK(9, 0) 106786d33c8SBen Chuang #define PCI_GLI_9755_PLL_PDIV GENMASK(14, 12) 107786d33c8SBen Chuang #define PCI_GLI_9755_PLL_DIR BIT(15) 108786d33c8SBen Chuang #define PCI_GLI_9755_PLLSSC_STEP GENMASK(28, 24) 109786d33c8SBen Chuang #define PCI_GLI_9755_PLLSSC_EN BIT(31) 110786d33c8SBen Chuang 111786d33c8SBen Chuang #define PCI_GLI_9755_PLLSSC 0x68 112786d33c8SBen Chuang #define PCI_GLI_9755_PLLSSC_PPM GENMASK(15, 0) 113786d33c8SBen Chuang 114e51df6ceSBen Chuang #define GLI_MAX_TUNING_LOOP 40 115e51df6ceSBen Chuang 116e51df6ceSBen Chuang /* Genesys Logic chipset */ 117e51df6ceSBen Chuang static inline void gl9750_wt_on(struct sdhci_host *host) 118e51df6ceSBen Chuang { 119e51df6ceSBen Chuang u32 wt_value; 120e51df6ceSBen Chuang u32 wt_enable; 121e51df6ceSBen Chuang 122e51df6ceSBen Chuang wt_value = sdhci_readl(host, SDHCI_GLI_9750_WT); 123e51df6ceSBen Chuang wt_enable = FIELD_GET(SDHCI_GLI_9750_WT_EN, wt_value); 124e51df6ceSBen Chuang 125e51df6ceSBen Chuang if (wt_enable == GLI_9750_WT_EN_ON) 126e51df6ceSBen Chuang return; 127e51df6ceSBen Chuang 128e51df6ceSBen Chuang wt_value &= ~SDHCI_GLI_9750_WT_EN; 129e51df6ceSBen Chuang wt_value |= FIELD_PREP(SDHCI_GLI_9750_WT_EN, GLI_9750_WT_EN_ON); 130e51df6ceSBen Chuang 131e51df6ceSBen Chuang sdhci_writel(host, wt_value, SDHCI_GLI_9750_WT); 132e51df6ceSBen Chuang } 133e51df6ceSBen Chuang 134e51df6ceSBen Chuang static inline void gl9750_wt_off(struct sdhci_host *host) 135e51df6ceSBen Chuang { 136e51df6ceSBen Chuang u32 wt_value; 137e51df6ceSBen Chuang u32 wt_enable; 138e51df6ceSBen Chuang 139e51df6ceSBen Chuang wt_value = sdhci_readl(host, SDHCI_GLI_9750_WT); 140e51df6ceSBen Chuang wt_enable = FIELD_GET(SDHCI_GLI_9750_WT_EN, wt_value); 141e51df6ceSBen Chuang 142e51df6ceSBen Chuang if (wt_enable == GLI_9750_WT_EN_OFF) 143e51df6ceSBen Chuang return; 144e51df6ceSBen Chuang 145e51df6ceSBen Chuang wt_value &= ~SDHCI_GLI_9750_WT_EN; 146e51df6ceSBen Chuang wt_value |= FIELD_PREP(SDHCI_GLI_9750_WT_EN, GLI_9750_WT_EN_OFF); 147e51df6ceSBen Chuang 148e51df6ceSBen Chuang sdhci_writel(host, wt_value, SDHCI_GLI_9750_WT); 149e51df6ceSBen Chuang } 150e51df6ceSBen Chuang 151e51df6ceSBen Chuang static void gli_set_9750(struct sdhci_host *host) 152e51df6ceSBen Chuang { 153e51df6ceSBen Chuang u32 driving_value; 154e51df6ceSBen Chuang u32 pll_value; 155e51df6ceSBen Chuang u32 sw_ctrl_value; 156e51df6ceSBen Chuang u32 misc_value; 157e51df6ceSBen Chuang u32 parameter_value; 158e51df6ceSBen Chuang u32 control_value; 159e51df6ceSBen Chuang u16 ctrl2; 160e51df6ceSBen Chuang 161e51df6ceSBen Chuang gl9750_wt_on(host); 162e51df6ceSBen Chuang 163e51df6ceSBen Chuang driving_value = sdhci_readl(host, SDHCI_GLI_9750_DRIVING); 164e51df6ceSBen Chuang pll_value = sdhci_readl(host, SDHCI_GLI_9750_PLL); 165e51df6ceSBen Chuang sw_ctrl_value = sdhci_readl(host, SDHCI_GLI_9750_SW_CTRL); 166e51df6ceSBen Chuang misc_value = sdhci_readl(host, SDHCI_GLI_9750_MISC); 167e51df6ceSBen Chuang parameter_value = sdhci_readl(host, SDHCI_GLI_9750_TUNING_PARAMETERS); 168e51df6ceSBen Chuang control_value = sdhci_readl(host, SDHCI_GLI_9750_TUNING_CONTROL); 169e51df6ceSBen Chuang 170e51df6ceSBen Chuang driving_value &= ~(SDHCI_GLI_9750_DRIVING_1); 171e51df6ceSBen Chuang driving_value &= ~(SDHCI_GLI_9750_DRIVING_2); 172e51df6ceSBen Chuang driving_value |= FIELD_PREP(SDHCI_GLI_9750_DRIVING_1, 173e51df6ceSBen Chuang GLI_9750_DRIVING_1_VALUE); 174e51df6ceSBen Chuang driving_value |= FIELD_PREP(SDHCI_GLI_9750_DRIVING_2, 175e51df6ceSBen Chuang GLI_9750_DRIVING_2_VALUE); 176b56ff195SBen Chuang driving_value &= ~(SDHCI_GLI_9750_SEL_1|SDHCI_GLI_9750_SEL_2|SDHCI_GLI_9750_ALL_RST); 177b56ff195SBen Chuang driving_value |= SDHCI_GLI_9750_SEL_2; 178e51df6ceSBen Chuang sdhci_writel(host, driving_value, SDHCI_GLI_9750_DRIVING); 179e51df6ceSBen Chuang 180e51df6ceSBen Chuang sw_ctrl_value &= ~SDHCI_GLI_9750_SW_CTRL_4; 181e51df6ceSBen Chuang sw_ctrl_value |= FIELD_PREP(SDHCI_GLI_9750_SW_CTRL_4, 182e51df6ceSBen Chuang GLI_9750_SW_CTRL_4_VALUE); 183e51df6ceSBen Chuang sdhci_writel(host, sw_ctrl_value, SDHCI_GLI_9750_SW_CTRL); 184e51df6ceSBen Chuang 185e51df6ceSBen Chuang /* reset the tuning flow after reinit and before starting tuning */ 186e51df6ceSBen Chuang pll_value &= ~SDHCI_GLI_9750_PLL_TX2_INV; 187e51df6ceSBen Chuang pll_value &= ~SDHCI_GLI_9750_PLL_TX2_DLY; 188e51df6ceSBen Chuang pll_value |= FIELD_PREP(SDHCI_GLI_9750_PLL_TX2_INV, 189e51df6ceSBen Chuang GLI_9750_PLL_TX2_INV_VALUE); 190e51df6ceSBen Chuang pll_value |= FIELD_PREP(SDHCI_GLI_9750_PLL_TX2_DLY, 191e51df6ceSBen Chuang GLI_9750_PLL_TX2_DLY_VALUE); 192e51df6ceSBen Chuang 193e51df6ceSBen Chuang misc_value &= ~SDHCI_GLI_9750_MISC_TX1_INV; 194e51df6ceSBen Chuang misc_value &= ~SDHCI_GLI_9750_MISC_RX_INV; 195e51df6ceSBen Chuang misc_value &= ~SDHCI_GLI_9750_MISC_TX1_DLY; 196e51df6ceSBen Chuang misc_value |= FIELD_PREP(SDHCI_GLI_9750_MISC_TX1_INV, 197e51df6ceSBen Chuang GLI_9750_MISC_TX1_INV_VALUE); 198e51df6ceSBen Chuang misc_value |= FIELD_PREP(SDHCI_GLI_9750_MISC_RX_INV, 199e51df6ceSBen Chuang GLI_9750_MISC_RX_INV_VALUE); 200e51df6ceSBen Chuang misc_value |= FIELD_PREP(SDHCI_GLI_9750_MISC_TX1_DLY, 201e51df6ceSBen Chuang GLI_9750_MISC_TX1_DLY_VALUE); 202e51df6ceSBen Chuang 203e51df6ceSBen Chuang parameter_value &= ~SDHCI_GLI_9750_TUNING_PARAMETERS_RX_DLY; 204e51df6ceSBen Chuang parameter_value |= FIELD_PREP(SDHCI_GLI_9750_TUNING_PARAMETERS_RX_DLY, 205e51df6ceSBen Chuang GLI_9750_TUNING_PARAMETERS_RX_DLY_VALUE); 206e51df6ceSBen Chuang 207e51df6ceSBen Chuang control_value &= ~SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_1; 208e51df6ceSBen Chuang control_value &= ~SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_2; 209e51df6ceSBen Chuang control_value |= FIELD_PREP(SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_1, 210e51df6ceSBen Chuang GLI_9750_TUNING_CONTROL_GLITCH_1_VALUE); 211e51df6ceSBen Chuang control_value |= FIELD_PREP(SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_2, 212e51df6ceSBen Chuang GLI_9750_TUNING_CONTROL_GLITCH_2_VALUE); 213e51df6ceSBen Chuang 214e51df6ceSBen Chuang sdhci_writel(host, pll_value, SDHCI_GLI_9750_PLL); 215e51df6ceSBen Chuang sdhci_writel(host, misc_value, SDHCI_GLI_9750_MISC); 216e51df6ceSBen Chuang 217e51df6ceSBen Chuang /* disable tuned clk */ 218e51df6ceSBen Chuang ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); 219e51df6ceSBen Chuang ctrl2 &= ~SDHCI_CTRL_TUNED_CLK; 220e51df6ceSBen Chuang sdhci_writew(host, ctrl2, SDHCI_HOST_CONTROL2); 221e51df6ceSBen Chuang 222e51df6ceSBen Chuang /* enable tuning parameters control */ 223e51df6ceSBen Chuang control_value &= ~SDHCI_GLI_9750_TUNING_CONTROL_EN; 224e51df6ceSBen Chuang control_value |= FIELD_PREP(SDHCI_GLI_9750_TUNING_CONTROL_EN, 225e51df6ceSBen Chuang GLI_9750_TUNING_CONTROL_EN_ON); 226e51df6ceSBen Chuang sdhci_writel(host, control_value, SDHCI_GLI_9750_TUNING_CONTROL); 227e51df6ceSBen Chuang 228e51df6ceSBen Chuang /* write tuning parameters */ 229e51df6ceSBen Chuang sdhci_writel(host, parameter_value, SDHCI_GLI_9750_TUNING_PARAMETERS); 230e51df6ceSBen Chuang 231e51df6ceSBen Chuang /* disable tuning parameters control */ 232e51df6ceSBen Chuang control_value &= ~SDHCI_GLI_9750_TUNING_CONTROL_EN; 233e51df6ceSBen Chuang control_value |= FIELD_PREP(SDHCI_GLI_9750_TUNING_CONTROL_EN, 234e51df6ceSBen Chuang GLI_9750_TUNING_CONTROL_EN_OFF); 235e51df6ceSBen Chuang sdhci_writel(host, control_value, SDHCI_GLI_9750_TUNING_CONTROL); 236e51df6ceSBen Chuang 237e51df6ceSBen Chuang /* clear tuned clk */ 238e51df6ceSBen Chuang ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); 239e51df6ceSBen Chuang ctrl2 &= ~SDHCI_CTRL_TUNED_CLK; 240e51df6ceSBen Chuang sdhci_writew(host, ctrl2, SDHCI_HOST_CONTROL2); 241e51df6ceSBen Chuang 242e51df6ceSBen Chuang gl9750_wt_off(host); 243e51df6ceSBen Chuang } 244e51df6ceSBen Chuang 245e51df6ceSBen Chuang static void gli_set_9750_rx_inv(struct sdhci_host *host, bool b) 246e51df6ceSBen Chuang { 247e51df6ceSBen Chuang u32 misc_value; 248e51df6ceSBen Chuang 249e51df6ceSBen Chuang gl9750_wt_on(host); 250e51df6ceSBen Chuang 251e51df6ceSBen Chuang misc_value = sdhci_readl(host, SDHCI_GLI_9750_MISC); 252e51df6ceSBen Chuang misc_value &= ~SDHCI_GLI_9750_MISC_RX_INV; 253e51df6ceSBen Chuang if (b) { 254e51df6ceSBen Chuang misc_value |= FIELD_PREP(SDHCI_GLI_9750_MISC_RX_INV, 255e51df6ceSBen Chuang GLI_9750_MISC_RX_INV_ON); 256e51df6ceSBen Chuang } else { 257e51df6ceSBen Chuang misc_value |= FIELD_PREP(SDHCI_GLI_9750_MISC_RX_INV, 258e51df6ceSBen Chuang GLI_9750_MISC_RX_INV_OFF); 259e51df6ceSBen Chuang } 260e51df6ceSBen Chuang sdhci_writel(host, misc_value, SDHCI_GLI_9750_MISC); 261e51df6ceSBen Chuang 262e51df6ceSBen Chuang gl9750_wt_off(host); 263e51df6ceSBen Chuang } 264e51df6ceSBen Chuang 265e51df6ceSBen Chuang static int __sdhci_execute_tuning_9750(struct sdhci_host *host, u32 opcode) 266e51df6ceSBen Chuang { 267e51df6ceSBen Chuang int i; 268e51df6ceSBen Chuang int rx_inv; 269e51df6ceSBen Chuang 270e51df6ceSBen Chuang for (rx_inv = 0; rx_inv < 2; rx_inv++) { 271e51df6ceSBen Chuang gli_set_9750_rx_inv(host, !!rx_inv); 272e51df6ceSBen Chuang sdhci_start_tuning(host); 273e51df6ceSBen Chuang 274e51df6ceSBen Chuang for (i = 0; i < GLI_MAX_TUNING_LOOP; i++) { 275e51df6ceSBen Chuang u16 ctrl; 276e51df6ceSBen Chuang 277e51df6ceSBen Chuang sdhci_send_tuning(host, opcode); 278e51df6ceSBen Chuang 279e51df6ceSBen Chuang if (!host->tuning_done) { 280e51df6ceSBen Chuang sdhci_abort_tuning(host, opcode); 281e51df6ceSBen Chuang break; 282e51df6ceSBen Chuang } 283e51df6ceSBen Chuang 284e51df6ceSBen Chuang ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); 285e51df6ceSBen Chuang if (!(ctrl & SDHCI_CTRL_EXEC_TUNING)) { 286e51df6ceSBen Chuang if (ctrl & SDHCI_CTRL_TUNED_CLK) 287e51df6ceSBen Chuang return 0; /* Success! */ 288e51df6ceSBen Chuang break; 289e51df6ceSBen Chuang } 290e51df6ceSBen Chuang } 291e51df6ceSBen Chuang } 292e51df6ceSBen Chuang if (!host->tuning_done) { 293e51df6ceSBen Chuang pr_info("%s: Tuning timeout, falling back to fixed sampling clock\n", 294e51df6ceSBen Chuang mmc_hostname(host->mmc)); 295e51df6ceSBen Chuang return -ETIMEDOUT; 296e51df6ceSBen Chuang } 297e51df6ceSBen Chuang 298e51df6ceSBen Chuang pr_info("%s: Tuning failed, falling back to fixed sampling clock\n", 299e51df6ceSBen Chuang mmc_hostname(host->mmc)); 300e51df6ceSBen Chuang sdhci_reset_tuning(host); 301e51df6ceSBen Chuang 302e51df6ceSBen Chuang return -EAGAIN; 303e51df6ceSBen Chuang } 304e51df6ceSBen Chuang 305e51df6ceSBen Chuang static int gl9750_execute_tuning(struct sdhci_host *host, u32 opcode) 306e51df6ceSBen Chuang { 307e51df6ceSBen Chuang host->mmc->retune_period = 0; 308e51df6ceSBen Chuang if (host->tuning_mode == SDHCI_TUNING_MODE_1) 309e51df6ceSBen Chuang host->mmc->retune_period = host->tuning_count; 310e51df6ceSBen Chuang 311e51df6ceSBen Chuang gli_set_9750(host); 312e51df6ceSBen Chuang host->tuning_err = __sdhci_execute_tuning_9750(host, opcode); 313e51df6ceSBen Chuang sdhci_end_tuning(host); 314e51df6ceSBen Chuang 315e51df6ceSBen Chuang return 0; 316e51df6ceSBen Chuang } 317e51df6ceSBen Chuang 318786d33c8SBen Chuang static void gl9750_disable_ssc_pll(struct sdhci_host *host) 319786d33c8SBen Chuang { 320786d33c8SBen Chuang u32 pll; 321786d33c8SBen Chuang 322786d33c8SBen Chuang gl9750_wt_on(host); 323786d33c8SBen Chuang pll = sdhci_readl(host, SDHCI_GLI_9750_PLL); 324786d33c8SBen Chuang pll &= ~(SDHCI_GLI_9750_PLL_DIR | SDHCI_GLI_9750_PLLSSC_EN); 325786d33c8SBen Chuang sdhci_writel(host, pll, SDHCI_GLI_9750_PLL); 326786d33c8SBen Chuang gl9750_wt_off(host); 327786d33c8SBen Chuang } 328786d33c8SBen Chuang 329786d33c8SBen Chuang static void gl9750_set_pll(struct sdhci_host *host, u8 dir, u16 ldiv, u8 pdiv) 330786d33c8SBen Chuang { 331786d33c8SBen Chuang u32 pll; 332786d33c8SBen Chuang 333786d33c8SBen Chuang gl9750_wt_on(host); 334786d33c8SBen Chuang pll = sdhci_readl(host, SDHCI_GLI_9750_PLL); 335786d33c8SBen Chuang pll &= ~(SDHCI_GLI_9750_PLL_LDIV | 336786d33c8SBen Chuang SDHCI_GLI_9750_PLL_PDIV | 337786d33c8SBen Chuang SDHCI_GLI_9750_PLL_DIR); 338786d33c8SBen Chuang pll |= FIELD_PREP(SDHCI_GLI_9750_PLL_LDIV, ldiv) | 339786d33c8SBen Chuang FIELD_PREP(SDHCI_GLI_9750_PLL_PDIV, pdiv) | 340786d33c8SBen Chuang FIELD_PREP(SDHCI_GLI_9750_PLL_DIR, dir); 341786d33c8SBen Chuang sdhci_writel(host, pll, SDHCI_GLI_9750_PLL); 342786d33c8SBen Chuang gl9750_wt_off(host); 343786d33c8SBen Chuang 344786d33c8SBen Chuang /* wait for pll stable */ 345786d33c8SBen Chuang mdelay(1); 346786d33c8SBen Chuang } 347786d33c8SBen Chuang 348786d33c8SBen Chuang static void gl9750_set_ssc(struct sdhci_host *host, u8 enable, u8 step, u16 ppm) 349786d33c8SBen Chuang { 350786d33c8SBen Chuang u32 pll; 351786d33c8SBen Chuang u32 ssc; 352786d33c8SBen Chuang 353786d33c8SBen Chuang gl9750_wt_on(host); 354786d33c8SBen Chuang pll = sdhci_readl(host, SDHCI_GLI_9750_PLL); 355786d33c8SBen Chuang ssc = sdhci_readl(host, SDHCI_GLI_9750_PLLSSC); 356786d33c8SBen Chuang pll &= ~(SDHCI_GLI_9750_PLLSSC_STEP | 357786d33c8SBen Chuang SDHCI_GLI_9750_PLLSSC_EN); 358786d33c8SBen Chuang ssc &= ~SDHCI_GLI_9750_PLLSSC_PPM; 359786d33c8SBen Chuang pll |= FIELD_PREP(SDHCI_GLI_9750_PLLSSC_STEP, step) | 360786d33c8SBen Chuang FIELD_PREP(SDHCI_GLI_9750_PLLSSC_EN, enable); 361786d33c8SBen Chuang ssc |= FIELD_PREP(SDHCI_GLI_9750_PLLSSC_PPM, ppm); 362786d33c8SBen Chuang sdhci_writel(host, ssc, SDHCI_GLI_9750_PLLSSC); 363786d33c8SBen Chuang sdhci_writel(host, pll, SDHCI_GLI_9750_PLL); 364786d33c8SBen Chuang gl9750_wt_off(host); 365786d33c8SBen Chuang } 366786d33c8SBen Chuang 367786d33c8SBen Chuang static void gl9750_set_ssc_pll_205mhz(struct sdhci_host *host) 368786d33c8SBen Chuang { 369786d33c8SBen Chuang /* set pll to 205MHz and enable ssc */ 370786d33c8SBen Chuang gl9750_set_ssc(host, 0x1, 0x1F, 0xFFE7); 371786d33c8SBen Chuang gl9750_set_pll(host, 0x1, 0x246, 0x0); 372786d33c8SBen Chuang } 373786d33c8SBen Chuang 374786d33c8SBen Chuang static void sdhci_gl9750_set_clock(struct sdhci_host *host, unsigned int clock) 375786d33c8SBen Chuang { 376786d33c8SBen Chuang struct mmc_ios *ios = &host->mmc->ios; 377786d33c8SBen Chuang u16 clk; 378786d33c8SBen Chuang 379786d33c8SBen Chuang host->mmc->actual_clock = 0; 380786d33c8SBen Chuang 381786d33c8SBen Chuang gl9750_disable_ssc_pll(host); 382786d33c8SBen Chuang sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); 383786d33c8SBen Chuang 384786d33c8SBen Chuang if (clock == 0) 385786d33c8SBen Chuang return; 386786d33c8SBen Chuang 387786d33c8SBen Chuang clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock); 388786d33c8SBen Chuang if (clock == 200000000 && ios->timing == MMC_TIMING_UHS_SDR104) { 389786d33c8SBen Chuang host->mmc->actual_clock = 205000000; 390786d33c8SBen Chuang gl9750_set_ssc_pll_205mhz(host); 391786d33c8SBen Chuang } 392786d33c8SBen Chuang 393786d33c8SBen Chuang sdhci_enable_clk(host, clk); 394786d33c8SBen Chuang } 395786d33c8SBen Chuang 39631e43f31SBen Chuang static void gli_pcie_enable_msi(struct sdhci_pci_slot *slot) 39731e43f31SBen Chuang { 39831e43f31SBen Chuang int ret; 39931e43f31SBen Chuang 40031e43f31SBen Chuang ret = pci_alloc_irq_vectors(slot->chip->pdev, 1, 1, 40131e43f31SBen Chuang PCI_IRQ_MSI | PCI_IRQ_MSIX); 40231e43f31SBen Chuang if (ret < 0) { 40331e43f31SBen Chuang pr_warn("%s: enable PCI MSI failed, error=%d\n", 40431e43f31SBen Chuang mmc_hostname(slot->host->mmc), ret); 40531e43f31SBen Chuang return; 40631e43f31SBen Chuang } 40731e43f31SBen Chuang 40831e43f31SBen Chuang slot->host->irq = pci_irq_vector(slot->chip->pdev, 0); 40931e43f31SBen Chuang } 41031e43f31SBen Chuang 411786d33c8SBen Chuang static inline void gl9755_wt_on(struct pci_dev *pdev) 412786d33c8SBen Chuang { 413786d33c8SBen Chuang u32 wt_value; 414786d33c8SBen Chuang u32 wt_enable; 415786d33c8SBen Chuang 416786d33c8SBen Chuang pci_read_config_dword(pdev, PCI_GLI_9755_WT, &wt_value); 417786d33c8SBen Chuang wt_enable = FIELD_GET(PCI_GLI_9755_WT_EN, wt_value); 418786d33c8SBen Chuang 419786d33c8SBen Chuang if (wt_enable == GLI_9755_WT_EN_ON) 420786d33c8SBen Chuang return; 421786d33c8SBen Chuang 422786d33c8SBen Chuang wt_value &= ~PCI_GLI_9755_WT_EN; 423786d33c8SBen Chuang wt_value |= FIELD_PREP(PCI_GLI_9755_WT_EN, GLI_9755_WT_EN_ON); 424786d33c8SBen Chuang 425786d33c8SBen Chuang pci_write_config_dword(pdev, PCI_GLI_9755_WT, wt_value); 426786d33c8SBen Chuang } 427786d33c8SBen Chuang 428786d33c8SBen Chuang static inline void gl9755_wt_off(struct pci_dev *pdev) 429786d33c8SBen Chuang { 430786d33c8SBen Chuang u32 wt_value; 431786d33c8SBen Chuang u32 wt_enable; 432786d33c8SBen Chuang 433786d33c8SBen Chuang pci_read_config_dword(pdev, PCI_GLI_9755_WT, &wt_value); 434786d33c8SBen Chuang wt_enable = FIELD_GET(PCI_GLI_9755_WT_EN, wt_value); 435786d33c8SBen Chuang 436786d33c8SBen Chuang if (wt_enable == GLI_9755_WT_EN_OFF) 437786d33c8SBen Chuang return; 438786d33c8SBen Chuang 439786d33c8SBen Chuang wt_value &= ~PCI_GLI_9755_WT_EN; 440786d33c8SBen Chuang wt_value |= FIELD_PREP(PCI_GLI_9755_WT_EN, GLI_9755_WT_EN_OFF); 441786d33c8SBen Chuang 442786d33c8SBen Chuang pci_write_config_dword(pdev, PCI_GLI_9755_WT, wt_value); 443786d33c8SBen Chuang } 444786d33c8SBen Chuang 445786d33c8SBen Chuang static void gl9755_disable_ssc_pll(struct pci_dev *pdev) 446786d33c8SBen Chuang { 447786d33c8SBen Chuang u32 pll; 448786d33c8SBen Chuang 449786d33c8SBen Chuang gl9755_wt_on(pdev); 450786d33c8SBen Chuang pci_read_config_dword(pdev, PCI_GLI_9755_PLL, &pll); 451786d33c8SBen Chuang pll &= ~(PCI_GLI_9755_PLL_DIR | PCI_GLI_9755_PLLSSC_EN); 452786d33c8SBen Chuang pci_write_config_dword(pdev, PCI_GLI_9755_PLL, pll); 453786d33c8SBen Chuang gl9755_wt_off(pdev); 454786d33c8SBen Chuang } 455786d33c8SBen Chuang 456786d33c8SBen Chuang static void gl9755_set_pll(struct pci_dev *pdev, u8 dir, u16 ldiv, u8 pdiv) 457786d33c8SBen Chuang { 458786d33c8SBen Chuang u32 pll; 459786d33c8SBen Chuang 460786d33c8SBen Chuang gl9755_wt_on(pdev); 461786d33c8SBen Chuang pci_read_config_dword(pdev, PCI_GLI_9755_PLL, &pll); 462786d33c8SBen Chuang pll &= ~(PCI_GLI_9755_PLL_LDIV | 463786d33c8SBen Chuang PCI_GLI_9755_PLL_PDIV | 464786d33c8SBen Chuang PCI_GLI_9755_PLL_DIR); 465786d33c8SBen Chuang pll |= FIELD_PREP(PCI_GLI_9755_PLL_LDIV, ldiv) | 466786d33c8SBen Chuang FIELD_PREP(PCI_GLI_9755_PLL_PDIV, pdiv) | 467786d33c8SBen Chuang FIELD_PREP(PCI_GLI_9755_PLL_DIR, dir); 468786d33c8SBen Chuang pci_write_config_dword(pdev, PCI_GLI_9755_PLL, pll); 469786d33c8SBen Chuang gl9755_wt_off(pdev); 470786d33c8SBen Chuang 471786d33c8SBen Chuang /* wait for pll stable */ 472786d33c8SBen Chuang mdelay(1); 473786d33c8SBen Chuang } 474786d33c8SBen Chuang 475786d33c8SBen Chuang static void gl9755_set_ssc(struct pci_dev *pdev, u8 enable, u8 step, u16 ppm) 476786d33c8SBen Chuang { 477786d33c8SBen Chuang u32 pll; 478786d33c8SBen Chuang u32 ssc; 479786d33c8SBen Chuang 480786d33c8SBen Chuang gl9755_wt_on(pdev); 481786d33c8SBen Chuang pci_read_config_dword(pdev, PCI_GLI_9755_PLL, &pll); 482786d33c8SBen Chuang pci_read_config_dword(pdev, PCI_GLI_9755_PLLSSC, &ssc); 483786d33c8SBen Chuang pll &= ~(PCI_GLI_9755_PLLSSC_STEP | 484786d33c8SBen Chuang PCI_GLI_9755_PLLSSC_EN); 485786d33c8SBen Chuang ssc &= ~PCI_GLI_9755_PLLSSC_PPM; 486786d33c8SBen Chuang pll |= FIELD_PREP(PCI_GLI_9755_PLLSSC_STEP, step) | 487786d33c8SBen Chuang FIELD_PREP(PCI_GLI_9755_PLLSSC_EN, enable); 488786d33c8SBen Chuang ssc |= FIELD_PREP(PCI_GLI_9755_PLLSSC_PPM, ppm); 489786d33c8SBen Chuang pci_write_config_dword(pdev, PCI_GLI_9755_PLLSSC, ssc); 490786d33c8SBen Chuang pci_write_config_dword(pdev, PCI_GLI_9755_PLL, pll); 491786d33c8SBen Chuang gl9755_wt_off(pdev); 492786d33c8SBen Chuang } 493786d33c8SBen Chuang 494786d33c8SBen Chuang static void gl9755_set_ssc_pll_205mhz(struct pci_dev *pdev) 495786d33c8SBen Chuang { 496786d33c8SBen Chuang /* set pll to 205MHz and enable ssc */ 497786d33c8SBen Chuang gl9755_set_ssc(pdev, 0x1, 0x1F, 0xFFE7); 498786d33c8SBen Chuang gl9755_set_pll(pdev, 0x1, 0x246, 0x0); 499786d33c8SBen Chuang } 500786d33c8SBen Chuang 501786d33c8SBen Chuang static void sdhci_gl9755_set_clock(struct sdhci_host *host, unsigned int clock) 502786d33c8SBen Chuang { 503786d33c8SBen Chuang struct sdhci_pci_slot *slot = sdhci_priv(host); 504786d33c8SBen Chuang struct mmc_ios *ios = &host->mmc->ios; 505786d33c8SBen Chuang struct pci_dev *pdev; 506786d33c8SBen Chuang u16 clk; 507786d33c8SBen Chuang 508786d33c8SBen Chuang pdev = slot->chip->pdev; 509786d33c8SBen Chuang host->mmc->actual_clock = 0; 510786d33c8SBen Chuang 511786d33c8SBen Chuang gl9755_disable_ssc_pll(pdev); 512786d33c8SBen Chuang sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); 513786d33c8SBen Chuang 514786d33c8SBen Chuang if (clock == 0) 515786d33c8SBen Chuang return; 516786d33c8SBen Chuang 517786d33c8SBen Chuang clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock); 518786d33c8SBen Chuang if (clock == 200000000 && ios->timing == MMC_TIMING_UHS_SDR104) { 519786d33c8SBen Chuang host->mmc->actual_clock = 205000000; 520786d33c8SBen Chuang gl9755_set_ssc_pll_205mhz(pdev); 521786d33c8SBen Chuang } 522786d33c8SBen Chuang 523786d33c8SBen Chuang sdhci_enable_clk(host, clk); 524786d33c8SBen Chuang } 525786d33c8SBen Chuang 526*0f1d9961SBen Chuang static void gl9755_hw_setting(struct sdhci_pci_slot *slot) 527*0f1d9961SBen Chuang { 528*0f1d9961SBen Chuang struct pci_dev *pdev = slot->chip->pdev; 529*0f1d9961SBen Chuang u32 value; 530*0f1d9961SBen Chuang 531*0f1d9961SBen Chuang gl9755_wt_on(pdev); 532*0f1d9961SBen Chuang 533*0f1d9961SBen Chuang pci_read_config_dword(pdev, PCI_GLI_9755_PECONF, &value); 534*0f1d9961SBen Chuang value &= ~PCI_GLI_9755_LFCLK; 535*0f1d9961SBen Chuang value &= ~PCI_GLI_9755_DMACLK; 536*0f1d9961SBen Chuang pci_write_config_dword(pdev, PCI_GLI_9755_PECONF, value); 537*0f1d9961SBen Chuang 538*0f1d9961SBen Chuang gl9755_wt_off(pdev); 539*0f1d9961SBen Chuang } 540*0f1d9961SBen Chuang 541e51df6ceSBen Chuang static int gli_probe_slot_gl9750(struct sdhci_pci_slot *slot) 542e51df6ceSBen Chuang { 543e51df6ceSBen Chuang struct sdhci_host *host = slot->host; 544e51df6ceSBen Chuang 54531e43f31SBen Chuang gli_pcie_enable_msi(slot); 546e51df6ceSBen Chuang slot->host->mmc->caps2 |= MMC_CAP2_NO_SDIO; 547e51df6ceSBen Chuang sdhci_enable_v4_mode(host); 548e51df6ceSBen Chuang 549e51df6ceSBen Chuang return 0; 550e51df6ceSBen Chuang } 551e51df6ceSBen Chuang 552e51df6ceSBen Chuang static int gli_probe_slot_gl9755(struct sdhci_pci_slot *slot) 553e51df6ceSBen Chuang { 554e51df6ceSBen Chuang struct sdhci_host *host = slot->host; 555e51df6ceSBen Chuang 556*0f1d9961SBen Chuang gl9755_hw_setting(slot); 55731e43f31SBen Chuang gli_pcie_enable_msi(slot); 558e51df6ceSBen Chuang slot->host->mmc->caps2 |= MMC_CAP2_NO_SDIO; 559e51df6ceSBen Chuang sdhci_enable_v4_mode(host); 560e51df6ceSBen Chuang 561e51df6ceSBen Chuang return 0; 562e51df6ceSBen Chuang } 563e51df6ceSBen Chuang 564e51df6ceSBen Chuang static void sdhci_gli_voltage_switch(struct sdhci_host *host) 565e51df6ceSBen Chuang { 566e51df6ceSBen Chuang /* 567e51df6ceSBen Chuang * According to Section 3.6.1 signal voltage switch procedure in 568e51df6ceSBen Chuang * SD Host Controller Simplified Spec. 4.20, steps 6~8 are as 569e51df6ceSBen Chuang * follows: 570e51df6ceSBen Chuang * (6) Set 1.8V Signal Enable in the Host Control 2 register. 571e51df6ceSBen Chuang * (7) Wait 5ms. 1.8V voltage regulator shall be stable within this 572e51df6ceSBen Chuang * period. 573e51df6ceSBen Chuang * (8) If 1.8V Signal Enable is cleared by Host Controller, go to 574e51df6ceSBen Chuang * step (12). 575e51df6ceSBen Chuang * 576e51df6ceSBen Chuang * Wait 5ms after set 1.8V signal enable in Host Control 2 register 577e51df6ceSBen Chuang * to ensure 1.8V signal enable bit is set by GL9750/GL9755. 578e51df6ceSBen Chuang */ 579e51df6ceSBen Chuang usleep_range(5000, 5500); 580e51df6ceSBen Chuang } 581e51df6ceSBen Chuang 582e51df6ceSBen Chuang static void sdhci_gl9750_reset(struct sdhci_host *host, u8 mask) 583e51df6ceSBen Chuang { 584e51df6ceSBen Chuang sdhci_reset(host, mask); 585e51df6ceSBen Chuang gli_set_9750(host); 586e51df6ceSBen Chuang } 587e51df6ceSBen Chuang 588e51df6ceSBen Chuang static u32 sdhci_gl9750_readl(struct sdhci_host *host, int reg) 589e51df6ceSBen Chuang { 590e51df6ceSBen Chuang u32 value; 591e51df6ceSBen Chuang 592e51df6ceSBen Chuang value = readl(host->ioaddr + reg); 593e51df6ceSBen Chuang if (unlikely(reg == SDHCI_MAX_CURRENT && !(value & 0xff))) 594e51df6ceSBen Chuang value |= 0xc8; 595e51df6ceSBen Chuang 596e51df6ceSBen Chuang return value; 597e51df6ceSBen Chuang } 598e51df6ceSBen Chuang 599282ede76SBen Chuang #ifdef CONFIG_PM_SLEEP 600282ede76SBen Chuang static int sdhci_pci_gli_resume(struct sdhci_pci_chip *chip) 601282ede76SBen Chuang { 602282ede76SBen Chuang struct sdhci_pci_slot *slot = chip->slots[0]; 603282ede76SBen Chuang 604282ede76SBen Chuang pci_free_irq_vectors(slot->chip->pdev); 605282ede76SBen Chuang gli_pcie_enable_msi(slot); 606282ede76SBen Chuang 607282ede76SBen Chuang return sdhci_pci_resume_host(chip); 608282ede76SBen Chuang } 609347f6be1SBen Chuang 610347f6be1SBen Chuang static int sdhci_cqhci_gli_resume(struct sdhci_pci_chip *chip) 611347f6be1SBen Chuang { 612347f6be1SBen Chuang struct sdhci_pci_slot *slot = chip->slots[0]; 613347f6be1SBen Chuang int ret; 614347f6be1SBen Chuang 615347f6be1SBen Chuang ret = sdhci_pci_gli_resume(chip); 616347f6be1SBen Chuang if (ret) 617347f6be1SBen Chuang return ret; 618347f6be1SBen Chuang 619347f6be1SBen Chuang return cqhci_resume(slot->host->mmc); 620347f6be1SBen Chuang } 621347f6be1SBen Chuang 622347f6be1SBen Chuang static int sdhci_cqhci_gli_suspend(struct sdhci_pci_chip *chip) 623347f6be1SBen Chuang { 624347f6be1SBen Chuang struct sdhci_pci_slot *slot = chip->slots[0]; 625347f6be1SBen Chuang int ret; 626347f6be1SBen Chuang 627347f6be1SBen Chuang ret = cqhci_suspend(slot->host->mmc); 628347f6be1SBen Chuang if (ret) 629347f6be1SBen Chuang return ret; 630347f6be1SBen Chuang 631347f6be1SBen Chuang return sdhci_suspend_host(slot->host); 632347f6be1SBen Chuang } 633282ede76SBen Chuang #endif 634282ede76SBen Chuang 6351ae1d2d6SBen Chuang static void gl9763e_hs400_enhanced_strobe(struct mmc_host *mmc, 6361ae1d2d6SBen Chuang struct mmc_ios *ios) 6371ae1d2d6SBen Chuang { 6381ae1d2d6SBen Chuang struct sdhci_host *host = mmc_priv(mmc); 6391ae1d2d6SBen Chuang u32 val; 6401ae1d2d6SBen Chuang 6411ae1d2d6SBen Chuang val = sdhci_readl(host, SDHCI_GLI_9763E_HS400_ES_REG); 6421ae1d2d6SBen Chuang if (ios->enhanced_strobe) 6431ae1d2d6SBen Chuang val |= SDHCI_GLI_9763E_HS400_ES_BIT; 6441ae1d2d6SBen Chuang else 6451ae1d2d6SBen Chuang val &= ~SDHCI_GLI_9763E_HS400_ES_BIT; 6461ae1d2d6SBen Chuang 6471ae1d2d6SBen Chuang sdhci_writel(host, val, SDHCI_GLI_9763E_HS400_ES_REG); 6481ae1d2d6SBen Chuang } 6491ae1d2d6SBen Chuang 6501ae1d2d6SBen Chuang static void sdhci_set_gl9763e_signaling(struct sdhci_host *host, 6511ae1d2d6SBen Chuang unsigned int timing) 6521ae1d2d6SBen Chuang { 6531ae1d2d6SBen Chuang u16 ctrl_2; 6541ae1d2d6SBen Chuang 6551ae1d2d6SBen Chuang ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); 6561ae1d2d6SBen Chuang ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; 6571ae1d2d6SBen Chuang if (timing == MMC_TIMING_MMC_HS200) 6581ae1d2d6SBen Chuang ctrl_2 |= SDHCI_CTRL_UHS_SDR104; 6591ae1d2d6SBen Chuang else if (timing == MMC_TIMING_MMC_HS) 6601ae1d2d6SBen Chuang ctrl_2 |= SDHCI_CTRL_UHS_SDR25; 6611ae1d2d6SBen Chuang else if (timing == MMC_TIMING_MMC_DDR52) 6621ae1d2d6SBen Chuang ctrl_2 |= SDHCI_CTRL_UHS_DDR50; 6631ae1d2d6SBen Chuang else if (timing == MMC_TIMING_MMC_HS400) 6641ae1d2d6SBen Chuang ctrl_2 |= SDHCI_GLI_9763E_CTRL_HS400; 6651ae1d2d6SBen Chuang 6661ae1d2d6SBen Chuang sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); 6671ae1d2d6SBen Chuang } 6681ae1d2d6SBen Chuang 669347f6be1SBen Chuang static void sdhci_gl9763e_dumpregs(struct mmc_host *mmc) 670347f6be1SBen Chuang { 671347f6be1SBen Chuang sdhci_dumpregs(mmc_priv(mmc)); 672347f6be1SBen Chuang } 673347f6be1SBen Chuang 674347f6be1SBen Chuang static void sdhci_gl9763e_cqe_pre_enable(struct mmc_host *mmc) 675347f6be1SBen Chuang { 676347f6be1SBen Chuang struct cqhci_host *cq_host = mmc->cqe_private; 677347f6be1SBen Chuang u32 value; 678347f6be1SBen Chuang 679347f6be1SBen Chuang value = cqhci_readl(cq_host, CQHCI_CFG); 680347f6be1SBen Chuang value |= CQHCI_ENABLE; 681347f6be1SBen Chuang cqhci_writel(cq_host, value, CQHCI_CFG); 682347f6be1SBen Chuang } 683347f6be1SBen Chuang 684347f6be1SBen Chuang static void sdhci_gl9763e_cqe_enable(struct mmc_host *mmc) 685347f6be1SBen Chuang { 686347f6be1SBen Chuang struct sdhci_host *host = mmc_priv(mmc); 687347f6be1SBen Chuang 688347f6be1SBen Chuang sdhci_writew(host, GLI_9763E_CQE_TRNS_MODE, SDHCI_TRANSFER_MODE); 689347f6be1SBen Chuang sdhci_cqe_enable(mmc); 690347f6be1SBen Chuang } 691347f6be1SBen Chuang 692347f6be1SBen Chuang static u32 sdhci_gl9763e_cqhci_irq(struct sdhci_host *host, u32 intmask) 693347f6be1SBen Chuang { 694347f6be1SBen Chuang int cmd_error = 0; 695347f6be1SBen Chuang int data_error = 0; 696347f6be1SBen Chuang 697347f6be1SBen Chuang if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error)) 698347f6be1SBen Chuang return intmask; 699347f6be1SBen Chuang 700347f6be1SBen Chuang cqhci_irq(host->mmc, intmask, cmd_error, data_error); 701347f6be1SBen Chuang 702347f6be1SBen Chuang return 0; 703347f6be1SBen Chuang } 704347f6be1SBen Chuang 705347f6be1SBen Chuang static void sdhci_gl9763e_cqe_post_disable(struct mmc_host *mmc) 706347f6be1SBen Chuang { 707347f6be1SBen Chuang struct sdhci_host *host = mmc_priv(mmc); 708347f6be1SBen Chuang struct cqhci_host *cq_host = mmc->cqe_private; 709347f6be1SBen Chuang u32 value; 710347f6be1SBen Chuang 711347f6be1SBen Chuang value = cqhci_readl(cq_host, CQHCI_CFG); 712347f6be1SBen Chuang value &= ~CQHCI_ENABLE; 713347f6be1SBen Chuang cqhci_writel(cq_host, value, CQHCI_CFG); 714347f6be1SBen Chuang sdhci_writew(host, 0x0, SDHCI_TRANSFER_MODE); 715347f6be1SBen Chuang } 716347f6be1SBen Chuang 717347f6be1SBen Chuang static const struct cqhci_host_ops sdhci_gl9763e_cqhci_ops = { 718347f6be1SBen Chuang .enable = sdhci_gl9763e_cqe_enable, 719347f6be1SBen Chuang .disable = sdhci_cqe_disable, 720347f6be1SBen Chuang .dumpregs = sdhci_gl9763e_dumpregs, 721347f6be1SBen Chuang .pre_enable = sdhci_gl9763e_cqe_pre_enable, 722347f6be1SBen Chuang .post_disable = sdhci_gl9763e_cqe_post_disable, 723347f6be1SBen Chuang }; 724347f6be1SBen Chuang 725347f6be1SBen Chuang static int gl9763e_add_host(struct sdhci_pci_slot *slot) 726347f6be1SBen Chuang { 727347f6be1SBen Chuang struct device *dev = &slot->chip->pdev->dev; 728347f6be1SBen Chuang struct sdhci_host *host = slot->host; 729347f6be1SBen Chuang struct cqhci_host *cq_host; 730347f6be1SBen Chuang bool dma64; 731347f6be1SBen Chuang int ret; 732347f6be1SBen Chuang 733347f6be1SBen Chuang ret = sdhci_setup_host(host); 734347f6be1SBen Chuang if (ret) 735347f6be1SBen Chuang return ret; 736347f6be1SBen Chuang 737347f6be1SBen Chuang cq_host = devm_kzalloc(dev, sizeof(*cq_host), GFP_KERNEL); 738347f6be1SBen Chuang if (!cq_host) { 739347f6be1SBen Chuang ret = -ENOMEM; 740347f6be1SBen Chuang goto cleanup; 741347f6be1SBen Chuang } 742347f6be1SBen Chuang 743347f6be1SBen Chuang cq_host->mmio = host->ioaddr + SDHCI_GLI_9763E_CQE_BASE_ADDR; 744347f6be1SBen Chuang cq_host->ops = &sdhci_gl9763e_cqhci_ops; 745347f6be1SBen Chuang 746347f6be1SBen Chuang dma64 = host->flags & SDHCI_USE_64_BIT_DMA; 747347f6be1SBen Chuang if (dma64) 748347f6be1SBen Chuang cq_host->caps |= CQHCI_TASK_DESC_SZ_128; 749347f6be1SBen Chuang 750347f6be1SBen Chuang ret = cqhci_init(cq_host, host->mmc, dma64); 751347f6be1SBen Chuang if (ret) 752347f6be1SBen Chuang goto cleanup; 753347f6be1SBen Chuang 754347f6be1SBen Chuang ret = __sdhci_add_host(host); 755347f6be1SBen Chuang if (ret) 756347f6be1SBen Chuang goto cleanup; 757347f6be1SBen Chuang 758347f6be1SBen Chuang return 0; 759347f6be1SBen Chuang 760347f6be1SBen Chuang cleanup: 761347f6be1SBen Chuang sdhci_cleanup_host(host); 762347f6be1SBen Chuang return ret; 763347f6be1SBen Chuang } 764347f6be1SBen Chuang 765347f6be1SBen Chuang static void sdhci_gl9763e_reset(struct sdhci_host *host, u8 mask) 766347f6be1SBen Chuang { 767347f6be1SBen Chuang if ((host->mmc->caps2 & MMC_CAP2_CQE) && (mask & SDHCI_RESET_ALL) && 768347f6be1SBen Chuang host->mmc->cqe_private) 769347f6be1SBen Chuang cqhci_deactivate(host->mmc); 770347f6be1SBen Chuang sdhci_reset(host, mask); 771347f6be1SBen Chuang } 772347f6be1SBen Chuang 7731ae1d2d6SBen Chuang static void gli_set_gl9763e(struct sdhci_pci_slot *slot) 7741ae1d2d6SBen Chuang { 7751ae1d2d6SBen Chuang struct pci_dev *pdev = slot->chip->pdev; 7761ae1d2d6SBen Chuang u32 value; 7771ae1d2d6SBen Chuang 7781ae1d2d6SBen Chuang pci_read_config_dword(pdev, PCIE_GLI_9763E_VHS, &value); 7791ae1d2d6SBen Chuang value &= ~GLI_9763E_VHS_REV; 7801ae1d2d6SBen Chuang value |= FIELD_PREP(GLI_9763E_VHS_REV, GLI_9763E_VHS_REV_W); 7811ae1d2d6SBen Chuang pci_write_config_dword(pdev, PCIE_GLI_9763E_VHS, value); 7821ae1d2d6SBen Chuang 7831ae1d2d6SBen Chuang pci_read_config_dword(pdev, PCIE_GLI_9763E_SCR, &value); 7841ae1d2d6SBen Chuang value |= GLI_9763E_SCR_AXI_REQ; 7851ae1d2d6SBen Chuang pci_write_config_dword(pdev, PCIE_GLI_9763E_SCR, value); 7861ae1d2d6SBen Chuang 7871ae1d2d6SBen Chuang pci_read_config_dword(pdev, PCIE_GLI_9763E_VHS, &value); 7881ae1d2d6SBen Chuang value &= ~GLI_9763E_VHS_REV; 7891ae1d2d6SBen Chuang value |= FIELD_PREP(GLI_9763E_VHS_REV, GLI_9763E_VHS_REV_R); 7901ae1d2d6SBen Chuang pci_write_config_dword(pdev, PCIE_GLI_9763E_VHS, value); 7911ae1d2d6SBen Chuang } 7921ae1d2d6SBen Chuang 7931ae1d2d6SBen Chuang static int gli_probe_slot_gl9763e(struct sdhci_pci_slot *slot) 7941ae1d2d6SBen Chuang { 795347f6be1SBen Chuang struct pci_dev *pdev = slot->chip->pdev; 7961ae1d2d6SBen Chuang struct sdhci_host *host = slot->host; 797347f6be1SBen Chuang u32 value; 7981ae1d2d6SBen Chuang 7991ae1d2d6SBen Chuang host->mmc->caps |= MMC_CAP_8_BIT_DATA | 8001ae1d2d6SBen Chuang MMC_CAP_1_8V_DDR | 8011ae1d2d6SBen Chuang MMC_CAP_NONREMOVABLE; 8021ae1d2d6SBen Chuang host->mmc->caps2 |= MMC_CAP2_HS200_1_8V_SDR | 8031ae1d2d6SBen Chuang MMC_CAP2_HS400_1_8V | 8041ae1d2d6SBen Chuang MMC_CAP2_HS400_ES | 8051ae1d2d6SBen Chuang MMC_CAP2_NO_SDIO | 8061ae1d2d6SBen Chuang MMC_CAP2_NO_SD; 807347f6be1SBen Chuang 808347f6be1SBen Chuang pci_read_config_dword(pdev, PCIE_GLI_9763E_MB, &value); 809347f6be1SBen Chuang if (!(value & GLI_9763E_MB_CMDQ_OFF)) 810347f6be1SBen Chuang host->mmc->caps2 |= MMC_CAP2_CQE | MMC_CAP2_CQE_DCMD; 811347f6be1SBen Chuang 8121ae1d2d6SBen Chuang gli_pcie_enable_msi(slot); 8131ae1d2d6SBen Chuang host->mmc_host_ops.hs400_enhanced_strobe = 8141ae1d2d6SBen Chuang gl9763e_hs400_enhanced_strobe; 8151ae1d2d6SBen Chuang gli_set_gl9763e(slot); 8161ae1d2d6SBen Chuang sdhci_enable_v4_mode(host); 8171ae1d2d6SBen Chuang 8181ae1d2d6SBen Chuang return 0; 8191ae1d2d6SBen Chuang } 8201ae1d2d6SBen Chuang 821e51df6ceSBen Chuang static const struct sdhci_ops sdhci_gl9755_ops = { 822786d33c8SBen Chuang .set_clock = sdhci_gl9755_set_clock, 823e51df6ceSBen Chuang .enable_dma = sdhci_pci_enable_dma, 824e51df6ceSBen Chuang .set_bus_width = sdhci_set_bus_width, 825e51df6ceSBen Chuang .reset = sdhci_reset, 826e51df6ceSBen Chuang .set_uhs_signaling = sdhci_set_uhs_signaling, 827e51df6ceSBen Chuang .voltage_switch = sdhci_gli_voltage_switch, 828e51df6ceSBen Chuang }; 829e51df6ceSBen Chuang 830e51df6ceSBen Chuang const struct sdhci_pci_fixes sdhci_gl9755 = { 831e51df6ceSBen Chuang .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, 832e51df6ceSBen Chuang .quirks2 = SDHCI_QUIRK2_BROKEN_DDR50, 833e51df6ceSBen Chuang .probe_slot = gli_probe_slot_gl9755, 834e51df6ceSBen Chuang .ops = &sdhci_gl9755_ops, 835282ede76SBen Chuang #ifdef CONFIG_PM_SLEEP 836282ede76SBen Chuang .resume = sdhci_pci_gli_resume, 837282ede76SBen Chuang #endif 838e51df6ceSBen Chuang }; 839e51df6ceSBen Chuang 840e51df6ceSBen Chuang static const struct sdhci_ops sdhci_gl9750_ops = { 841e51df6ceSBen Chuang .read_l = sdhci_gl9750_readl, 842786d33c8SBen Chuang .set_clock = sdhci_gl9750_set_clock, 843e51df6ceSBen Chuang .enable_dma = sdhci_pci_enable_dma, 844e51df6ceSBen Chuang .set_bus_width = sdhci_set_bus_width, 845e51df6ceSBen Chuang .reset = sdhci_gl9750_reset, 846e51df6ceSBen Chuang .set_uhs_signaling = sdhci_set_uhs_signaling, 847e51df6ceSBen Chuang .voltage_switch = sdhci_gli_voltage_switch, 848e51df6ceSBen Chuang .platform_execute_tuning = gl9750_execute_tuning, 849e51df6ceSBen Chuang }; 850e51df6ceSBen Chuang 851e51df6ceSBen Chuang const struct sdhci_pci_fixes sdhci_gl9750 = { 852e51df6ceSBen Chuang .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, 853e51df6ceSBen Chuang .quirks2 = SDHCI_QUIRK2_BROKEN_DDR50, 854e51df6ceSBen Chuang .probe_slot = gli_probe_slot_gl9750, 855e51df6ceSBen Chuang .ops = &sdhci_gl9750_ops, 856282ede76SBen Chuang #ifdef CONFIG_PM_SLEEP 857282ede76SBen Chuang .resume = sdhci_pci_gli_resume, 858282ede76SBen Chuang #endif 859e51df6ceSBen Chuang }; 8601ae1d2d6SBen Chuang 8611ae1d2d6SBen Chuang static const struct sdhci_ops sdhci_gl9763e_ops = { 8621ae1d2d6SBen Chuang .set_clock = sdhci_set_clock, 8631ae1d2d6SBen Chuang .enable_dma = sdhci_pci_enable_dma, 8641ae1d2d6SBen Chuang .set_bus_width = sdhci_set_bus_width, 865347f6be1SBen Chuang .reset = sdhci_gl9763e_reset, 8661ae1d2d6SBen Chuang .set_uhs_signaling = sdhci_set_gl9763e_signaling, 8671ae1d2d6SBen Chuang .voltage_switch = sdhci_gli_voltage_switch, 868347f6be1SBen Chuang .irq = sdhci_gl9763e_cqhci_irq, 8691ae1d2d6SBen Chuang }; 8701ae1d2d6SBen Chuang 8711ae1d2d6SBen Chuang const struct sdhci_pci_fixes sdhci_gl9763e = { 8721ae1d2d6SBen Chuang .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, 8731ae1d2d6SBen Chuang .probe_slot = gli_probe_slot_gl9763e, 8741ae1d2d6SBen Chuang .ops = &sdhci_gl9763e_ops, 8751ae1d2d6SBen Chuang #ifdef CONFIG_PM_SLEEP 876347f6be1SBen Chuang .resume = sdhci_cqhci_gli_resume, 877347f6be1SBen Chuang .suspend = sdhci_cqhci_gli_suspend, 8781ae1d2d6SBen Chuang #endif 879347f6be1SBen Chuang .add_host = gl9763e_add_host, 8801ae1d2d6SBen Chuang }; 881