xref: /openbmc/linux/drivers/mmc/host/sdhci-pci-gli.c (revision 0f1d9961)
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