Skip to content

Commit e51df6c

Browse files
benchuangglistorulf
authored andcommitted
mmc: host: sdhci-pci: Add Genesys Logic GL975x support
Add support for the GL9750 and GL9755 chipsets. Enable v4 mode and wait 5ms after set 1.8V signal enable for GL9750/ GL9755. Fix the value of SDHCI_MAX_CURRENT register and use the vendor tuning flow for GL9750. Co-developed-by: Michael K Johnson <[email protected]> Signed-off-by: Michael K Johnson <[email protected]> Signed-off-by: Ben Chuang <[email protected]> Acked-by: Adrian Hunter <[email protected]> Signed-off-by: Ulf Hansson <[email protected]>
1 parent b960bc4 commit e51df6c

File tree

5 files changed

+361
-1
lines changed

5 files changed

+361
-1
lines changed

drivers/mmc/host/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ config MMC_SDHCI_PCI
9494
depends on MMC_SDHCI && PCI
9595
select MMC_CQHCI
9696
select IOSF_MBI if X86
97+
select MMC_SDHCI_IO_ACCESSORS
9798
help
9899
This selects the PCI Secure Digital Host Controller Interface.
99100
Most controllers found today are PCI devices.

drivers/mmc/host/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ obj-$(CONFIG_MMC_MXS) += mxs-mmc.o
1313
obj-$(CONFIG_MMC_SDHCI) += sdhci.o
1414
obj-$(CONFIG_MMC_SDHCI_PCI) += sdhci-pci.o
1515
sdhci-pci-y += sdhci-pci-core.o sdhci-pci-o2micro.o sdhci-pci-arasan.o \
16-
sdhci-pci-dwc-mshc.o
16+
sdhci-pci-dwc-mshc.o sdhci-pci-gli.o
1717
obj-$(subst m,y,$(CONFIG_MMC_SDHCI_PCI)) += sdhci-pci-data.o
1818
obj-$(CONFIG_MMC_SDHCI_ACPI) += sdhci-acpi.o
1919
obj-$(CONFIG_MMC_SDHCI_PXAV3) += sdhci-pxav3.o

drivers/mmc/host/sdhci-pci-core.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1685,6 +1685,8 @@ static const struct pci_device_id pci_ids[] = {
16851685
SDHCI_PCI_DEVICE(O2, SEABIRD1, o2),
16861686
SDHCI_PCI_DEVICE(ARASAN, PHY_EMMC, arasan),
16871687
SDHCI_PCI_DEVICE(SYNOPSYS, DWC_MSHC, snps),
1688+
SDHCI_PCI_DEVICE(GLI, 9750, gl9750),
1689+
SDHCI_PCI_DEVICE(GLI, 9755, gl9755),
16881690
SDHCI_PCI_DEVICE_CLASS(AMD, SYSTEM_SDHCI, PCI_CLASS_MASK, amd),
16891691
/* Generic SD host controller */
16901692
{PCI_DEVICE_CLASS(SYSTEM_SDHCI, PCI_CLASS_MASK)},

drivers/mmc/host/sdhci-pci-gli.c

Lines changed: 352 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,352 @@
1+
// SPDX-License-Identifier: GPL-2.0+
2+
/*
3+
* Copyright (C) 2019 Genesys Logic, Inc.
4+
*
5+
* Authors: Ben Chuang <[email protected]>
6+
*
7+
* Version: v0.9.0 (2019-08-08)
8+
*/
9+
10+
#include <linux/bitfield.h>
11+
#include <linux/bits.h>
12+
#include <linux/pci.h>
13+
#include <linux/mmc/mmc.h>
14+
#include <linux/delay.h>
15+
#include "sdhci.h"
16+
#include "sdhci-pci.h"
17+
18+
/* Genesys Logic extra registers */
19+
#define SDHCI_GLI_9750_WT 0x800
20+
#define SDHCI_GLI_9750_WT_EN BIT(0)
21+
#define GLI_9750_WT_EN_ON 0x1
22+
#define GLI_9750_WT_EN_OFF 0x0
23+
24+
#define SDHCI_GLI_9750_DRIVING 0x860
25+
#define SDHCI_GLI_9750_DRIVING_1 GENMASK(11, 0)
26+
#define SDHCI_GLI_9750_DRIVING_2 GENMASK(27, 26)
27+
#define GLI_9750_DRIVING_1_VALUE 0xFFF
28+
#define GLI_9750_DRIVING_2_VALUE 0x3
29+
30+
#define SDHCI_GLI_9750_PLL 0x864
31+
#define SDHCI_GLI_9750_PLL_TX2_INV BIT(23)
32+
#define SDHCI_GLI_9750_PLL_TX2_DLY GENMASK(22, 20)
33+
#define GLI_9750_PLL_TX2_INV_VALUE 0x1
34+
#define GLI_9750_PLL_TX2_DLY_VALUE 0x0
35+
36+
#define SDHCI_GLI_9750_SW_CTRL 0x874
37+
#define SDHCI_GLI_9750_SW_CTRL_4 GENMASK(7, 6)
38+
#define GLI_9750_SW_CTRL_4_VALUE 0x3
39+
40+
#define SDHCI_GLI_9750_MISC 0x878
41+
#define SDHCI_GLI_9750_MISC_TX1_INV BIT(2)
42+
#define SDHCI_GLI_9750_MISC_RX_INV BIT(3)
43+
#define SDHCI_GLI_9750_MISC_TX1_DLY GENMASK(6, 4)
44+
#define GLI_9750_MISC_TX1_INV_VALUE 0x0
45+
#define GLI_9750_MISC_RX_INV_ON 0x1
46+
#define GLI_9750_MISC_RX_INV_OFF 0x0
47+
#define GLI_9750_MISC_RX_INV_VALUE GLI_9750_MISC_RX_INV_OFF
48+
#define GLI_9750_MISC_TX1_DLY_VALUE 0x5
49+
50+
#define SDHCI_GLI_9750_TUNING_CONTROL 0x540
51+
#define SDHCI_GLI_9750_TUNING_CONTROL_EN BIT(4)
52+
#define GLI_9750_TUNING_CONTROL_EN_ON 0x1
53+
#define GLI_9750_TUNING_CONTROL_EN_OFF 0x0
54+
#define SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_1 BIT(16)
55+
#define SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_2 GENMASK(20, 19)
56+
#define GLI_9750_TUNING_CONTROL_GLITCH_1_VALUE 0x1
57+
#define GLI_9750_TUNING_CONTROL_GLITCH_2_VALUE 0x2
58+
59+
#define SDHCI_GLI_9750_TUNING_PARAMETERS 0x544
60+
#define SDHCI_GLI_9750_TUNING_PARAMETERS_RX_DLY GENMASK(2, 0)
61+
#define GLI_9750_TUNING_PARAMETERS_RX_DLY_VALUE 0x1
62+
63+
#define GLI_MAX_TUNING_LOOP 40
64+
65+
/* Genesys Logic chipset */
66+
static inline void gl9750_wt_on(struct sdhci_host *host)
67+
{
68+
u32 wt_value;
69+
u32 wt_enable;
70+
71+
wt_value = sdhci_readl(host, SDHCI_GLI_9750_WT);
72+
wt_enable = FIELD_GET(SDHCI_GLI_9750_WT_EN, wt_value);
73+
74+
if (wt_enable == GLI_9750_WT_EN_ON)
75+
return;
76+
77+
wt_value &= ~SDHCI_GLI_9750_WT_EN;
78+
wt_value |= FIELD_PREP(SDHCI_GLI_9750_WT_EN, GLI_9750_WT_EN_ON);
79+
80+
sdhci_writel(host, wt_value, SDHCI_GLI_9750_WT);
81+
}
82+
83+
static inline void gl9750_wt_off(struct sdhci_host *host)
84+
{
85+
u32 wt_value;
86+
u32 wt_enable;
87+
88+
wt_value = sdhci_readl(host, SDHCI_GLI_9750_WT);
89+
wt_enable = FIELD_GET(SDHCI_GLI_9750_WT_EN, wt_value);
90+
91+
if (wt_enable == GLI_9750_WT_EN_OFF)
92+
return;
93+
94+
wt_value &= ~SDHCI_GLI_9750_WT_EN;
95+
wt_value |= FIELD_PREP(SDHCI_GLI_9750_WT_EN, GLI_9750_WT_EN_OFF);
96+
97+
sdhci_writel(host, wt_value, SDHCI_GLI_9750_WT);
98+
}
99+
100+
static void gli_set_9750(struct sdhci_host *host)
101+
{
102+
u32 driving_value;
103+
u32 pll_value;
104+
u32 sw_ctrl_value;
105+
u32 misc_value;
106+
u32 parameter_value;
107+
u32 control_value;
108+
u16 ctrl2;
109+
110+
gl9750_wt_on(host);
111+
112+
driving_value = sdhci_readl(host, SDHCI_GLI_9750_DRIVING);
113+
pll_value = sdhci_readl(host, SDHCI_GLI_9750_PLL);
114+
sw_ctrl_value = sdhci_readl(host, SDHCI_GLI_9750_SW_CTRL);
115+
misc_value = sdhci_readl(host, SDHCI_GLI_9750_MISC);
116+
parameter_value = sdhci_readl(host, SDHCI_GLI_9750_TUNING_PARAMETERS);
117+
control_value = sdhci_readl(host, SDHCI_GLI_9750_TUNING_CONTROL);
118+
119+
driving_value &= ~(SDHCI_GLI_9750_DRIVING_1);
120+
driving_value &= ~(SDHCI_GLI_9750_DRIVING_2);
121+
driving_value |= FIELD_PREP(SDHCI_GLI_9750_DRIVING_1,
122+
GLI_9750_DRIVING_1_VALUE);
123+
driving_value |= FIELD_PREP(SDHCI_GLI_9750_DRIVING_2,
124+
GLI_9750_DRIVING_2_VALUE);
125+
sdhci_writel(host, driving_value, SDHCI_GLI_9750_DRIVING);
126+
127+
sw_ctrl_value &= ~SDHCI_GLI_9750_SW_CTRL_4;
128+
sw_ctrl_value |= FIELD_PREP(SDHCI_GLI_9750_SW_CTRL_4,
129+
GLI_9750_SW_CTRL_4_VALUE);
130+
sdhci_writel(host, sw_ctrl_value, SDHCI_GLI_9750_SW_CTRL);
131+
132+
/* reset the tuning flow after reinit and before starting tuning */
133+
pll_value &= ~SDHCI_GLI_9750_PLL_TX2_INV;
134+
pll_value &= ~SDHCI_GLI_9750_PLL_TX2_DLY;
135+
pll_value |= FIELD_PREP(SDHCI_GLI_9750_PLL_TX2_INV,
136+
GLI_9750_PLL_TX2_INV_VALUE);
137+
pll_value |= FIELD_PREP(SDHCI_GLI_9750_PLL_TX2_DLY,
138+
GLI_9750_PLL_TX2_DLY_VALUE);
139+
140+
misc_value &= ~SDHCI_GLI_9750_MISC_TX1_INV;
141+
misc_value &= ~SDHCI_GLI_9750_MISC_RX_INV;
142+
misc_value &= ~SDHCI_GLI_9750_MISC_TX1_DLY;
143+
misc_value |= FIELD_PREP(SDHCI_GLI_9750_MISC_TX1_INV,
144+
GLI_9750_MISC_TX1_INV_VALUE);
145+
misc_value |= FIELD_PREP(SDHCI_GLI_9750_MISC_RX_INV,
146+
GLI_9750_MISC_RX_INV_VALUE);
147+
misc_value |= FIELD_PREP(SDHCI_GLI_9750_MISC_TX1_DLY,
148+
GLI_9750_MISC_TX1_DLY_VALUE);
149+
150+
parameter_value &= ~SDHCI_GLI_9750_TUNING_PARAMETERS_RX_DLY;
151+
parameter_value |= FIELD_PREP(SDHCI_GLI_9750_TUNING_PARAMETERS_RX_DLY,
152+
GLI_9750_TUNING_PARAMETERS_RX_DLY_VALUE);
153+
154+
control_value &= ~SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_1;
155+
control_value &= ~SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_2;
156+
control_value |= FIELD_PREP(SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_1,
157+
GLI_9750_TUNING_CONTROL_GLITCH_1_VALUE);
158+
control_value |= FIELD_PREP(SDHCI_GLI_9750_TUNING_CONTROL_GLITCH_2,
159+
GLI_9750_TUNING_CONTROL_GLITCH_2_VALUE);
160+
161+
sdhci_writel(host, pll_value, SDHCI_GLI_9750_PLL);
162+
sdhci_writel(host, misc_value, SDHCI_GLI_9750_MISC);
163+
164+
/* disable tuned clk */
165+
ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
166+
ctrl2 &= ~SDHCI_CTRL_TUNED_CLK;
167+
sdhci_writew(host, ctrl2, SDHCI_HOST_CONTROL2);
168+
169+
/* enable tuning parameters control */
170+
control_value &= ~SDHCI_GLI_9750_TUNING_CONTROL_EN;
171+
control_value |= FIELD_PREP(SDHCI_GLI_9750_TUNING_CONTROL_EN,
172+
GLI_9750_TUNING_CONTROL_EN_ON);
173+
sdhci_writel(host, control_value, SDHCI_GLI_9750_TUNING_CONTROL);
174+
175+
/* write tuning parameters */
176+
sdhci_writel(host, parameter_value, SDHCI_GLI_9750_TUNING_PARAMETERS);
177+
178+
/* disable tuning parameters control */
179+
control_value &= ~SDHCI_GLI_9750_TUNING_CONTROL_EN;
180+
control_value |= FIELD_PREP(SDHCI_GLI_9750_TUNING_CONTROL_EN,
181+
GLI_9750_TUNING_CONTROL_EN_OFF);
182+
sdhci_writel(host, control_value, SDHCI_GLI_9750_TUNING_CONTROL);
183+
184+
/* clear tuned clk */
185+
ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
186+
ctrl2 &= ~SDHCI_CTRL_TUNED_CLK;
187+
sdhci_writew(host, ctrl2, SDHCI_HOST_CONTROL2);
188+
189+
gl9750_wt_off(host);
190+
}
191+
192+
static void gli_set_9750_rx_inv(struct sdhci_host *host, bool b)
193+
{
194+
u32 misc_value;
195+
196+
gl9750_wt_on(host);
197+
198+
misc_value = sdhci_readl(host, SDHCI_GLI_9750_MISC);
199+
misc_value &= ~SDHCI_GLI_9750_MISC_RX_INV;
200+
if (b) {
201+
misc_value |= FIELD_PREP(SDHCI_GLI_9750_MISC_RX_INV,
202+
GLI_9750_MISC_RX_INV_ON);
203+
} else {
204+
misc_value |= FIELD_PREP(SDHCI_GLI_9750_MISC_RX_INV,
205+
GLI_9750_MISC_RX_INV_OFF);
206+
}
207+
sdhci_writel(host, misc_value, SDHCI_GLI_9750_MISC);
208+
209+
gl9750_wt_off(host);
210+
}
211+
212+
static int __sdhci_execute_tuning_9750(struct sdhci_host *host, u32 opcode)
213+
{
214+
int i;
215+
int rx_inv;
216+
217+
for (rx_inv = 0; rx_inv < 2; rx_inv++) {
218+
gli_set_9750_rx_inv(host, !!rx_inv);
219+
sdhci_start_tuning(host);
220+
221+
for (i = 0; i < GLI_MAX_TUNING_LOOP; i++) {
222+
u16 ctrl;
223+
224+
sdhci_send_tuning(host, opcode);
225+
226+
if (!host->tuning_done) {
227+
sdhci_abort_tuning(host, opcode);
228+
break;
229+
}
230+
231+
ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
232+
if (!(ctrl & SDHCI_CTRL_EXEC_TUNING)) {
233+
if (ctrl & SDHCI_CTRL_TUNED_CLK)
234+
return 0; /* Success! */
235+
break;
236+
}
237+
}
238+
}
239+
if (!host->tuning_done) {
240+
pr_info("%s: Tuning timeout, falling back to fixed sampling clock\n",
241+
mmc_hostname(host->mmc));
242+
return -ETIMEDOUT;
243+
}
244+
245+
pr_info("%s: Tuning failed, falling back to fixed sampling clock\n",
246+
mmc_hostname(host->mmc));
247+
sdhci_reset_tuning(host);
248+
249+
return -EAGAIN;
250+
}
251+
252+
static int gl9750_execute_tuning(struct sdhci_host *host, u32 opcode)
253+
{
254+
host->mmc->retune_period = 0;
255+
if (host->tuning_mode == SDHCI_TUNING_MODE_1)
256+
host->mmc->retune_period = host->tuning_count;
257+
258+
gli_set_9750(host);
259+
host->tuning_err = __sdhci_execute_tuning_9750(host, opcode);
260+
sdhci_end_tuning(host);
261+
262+
return 0;
263+
}
264+
265+
static int gli_probe_slot_gl9750(struct sdhci_pci_slot *slot)
266+
{
267+
struct sdhci_host *host = slot->host;
268+
269+
slot->host->mmc->caps2 |= MMC_CAP2_NO_SDIO;
270+
sdhci_enable_v4_mode(host);
271+
272+
return 0;
273+
}
274+
275+
static int gli_probe_slot_gl9755(struct sdhci_pci_slot *slot)
276+
{
277+
struct sdhci_host *host = slot->host;
278+
279+
slot->host->mmc->caps2 |= MMC_CAP2_NO_SDIO;
280+
sdhci_enable_v4_mode(host);
281+
282+
return 0;
283+
}
284+
285+
static void sdhci_gli_voltage_switch(struct sdhci_host *host)
286+
{
287+
/*
288+
* According to Section 3.6.1 signal voltage switch procedure in
289+
* SD Host Controller Simplified Spec. 4.20, steps 6~8 are as
290+
* follows:
291+
* (6) Set 1.8V Signal Enable in the Host Control 2 register.
292+
* (7) Wait 5ms. 1.8V voltage regulator shall be stable within this
293+
* period.
294+
* (8) If 1.8V Signal Enable is cleared by Host Controller, go to
295+
* step (12).
296+
*
297+
* Wait 5ms after set 1.8V signal enable in Host Control 2 register
298+
* to ensure 1.8V signal enable bit is set by GL9750/GL9755.
299+
*/
300+
usleep_range(5000, 5500);
301+
}
302+
303+
static void sdhci_gl9750_reset(struct sdhci_host *host, u8 mask)
304+
{
305+
sdhci_reset(host, mask);
306+
gli_set_9750(host);
307+
}
308+
309+
static u32 sdhci_gl9750_readl(struct sdhci_host *host, int reg)
310+
{
311+
u32 value;
312+
313+
value = readl(host->ioaddr + reg);
314+
if (unlikely(reg == SDHCI_MAX_CURRENT && !(value & 0xff)))
315+
value |= 0xc8;
316+
317+
return value;
318+
}
319+
320+
static const struct sdhci_ops sdhci_gl9755_ops = {
321+
.set_clock = sdhci_set_clock,
322+
.enable_dma = sdhci_pci_enable_dma,
323+
.set_bus_width = sdhci_set_bus_width,
324+
.reset = sdhci_reset,
325+
.set_uhs_signaling = sdhci_set_uhs_signaling,
326+
.voltage_switch = sdhci_gli_voltage_switch,
327+
};
328+
329+
const struct sdhci_pci_fixes sdhci_gl9755 = {
330+
.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
331+
.quirks2 = SDHCI_QUIRK2_BROKEN_DDR50,
332+
.probe_slot = gli_probe_slot_gl9755,
333+
.ops = &sdhci_gl9755_ops,
334+
};
335+
336+
static const struct sdhci_ops sdhci_gl9750_ops = {
337+
.read_l = sdhci_gl9750_readl,
338+
.set_clock = sdhci_set_clock,
339+
.enable_dma = sdhci_pci_enable_dma,
340+
.set_bus_width = sdhci_set_bus_width,
341+
.reset = sdhci_gl9750_reset,
342+
.set_uhs_signaling = sdhci_set_uhs_signaling,
343+
.voltage_switch = sdhci_gli_voltage_switch,
344+
.platform_execute_tuning = gl9750_execute_tuning,
345+
};
346+
347+
const struct sdhci_pci_fixes sdhci_gl9750 = {
348+
.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
349+
.quirks2 = SDHCI_QUIRK2_BROKEN_DDR50,
350+
.probe_slot = gli_probe_slot_gl9750,
351+
.ops = &sdhci_gl9750_ops,
352+
};

drivers/mmc/host/sdhci-pci.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@
6868

6969
#define PCI_DEVICE_ID_SYNOPSYS_DWC_MSHC 0xc202
7070

71+
#define PCI_DEVICE_ID_GLI_9755 0x9755
72+
#define PCI_DEVICE_ID_GLI_9750 0x9750
73+
7174
/*
7275
* PCI device class and mask
7376
*/
@@ -188,5 +191,7 @@ int sdhci_pci_enable_dma(struct sdhci_host *host);
188191
extern const struct sdhci_pci_fixes sdhci_arasan;
189192
extern const struct sdhci_pci_fixes sdhci_snps;
190193
extern const struct sdhci_pci_fixes sdhci_o2;
194+
extern const struct sdhci_pci_fixes sdhci_gl9750;
195+
extern const struct sdhci_pci_fixes sdhci_gl9755;
191196

192197
#endif /* __SDHCI_PCI_H */

0 commit comments

Comments
 (0)