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