xref: /linux/drivers/mmc/host/sdhci-pci-arasan.c (revision 552c69b36ebd966186573b9c7a286b390935cce1)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * sdhci-pci-arasan.c - Driver for Arasan PCI Controller with
4  * integrated phy.
5  *
6  * Copyright (C) 2017 Arasan Chip Systems Inc.
7  *
8  * Author: Atul Garg <agarg@arasan.com>
9  */
10 
11 #include <linux/pci.h>
12 #include <linux/delay.h>
13 
14 #include "sdhci.h"
15 #include "sdhci-pci.h"
16 
17 /* Extra registers for Arasan SD/SDIO/MMC Host Controller with PHY */
18 #define PHY_ADDR_REG	0x300
19 #define PHY_DAT_REG	0x304
20 
21 #define PHY_WRITE	BIT(8)
22 #define PHY_BUSY	BIT(9)
23 #define DATA_MASK	0xFF
24 
25 /* PHY Specific Registers */
26 #define DLL_STATUS	0x00
27 #define IPAD_CTRL1	0x01
28 #define IPAD_CTRL2	0x02
29 #define IPAD_STS	0x03
30 #define IOREN_CTRL1	0x06
31 #define IOREN_CTRL2	0x07
32 #define IOPU_CTRL1	0x08
33 #define IOPU_CTRL2	0x09
34 #define ITAP_DELAY	0x0C
35 #define OTAP_DELAY	0x0D
36 #define STRB_SEL	0x0E
37 #define CLKBUF_SEL	0x0F
38 #define MODE_CTRL	0x11
39 #define DLL_TRIM	0x12
40 #define CMD_CTRL	0x20
41 #define DATA_CTRL	0x21
42 #define STRB_CTRL	0x22
43 #define CLK_CTRL	0x23
44 #define PHY_CTRL	0x24
45 
46 #define DLL_ENBL	BIT(3)
47 #define RTRIM_EN	BIT(1)
48 #define PDB_ENBL	BIT(1)
49 #define RETB_ENBL	BIT(6)
50 #define ODEN_CMD	BIT(1)
51 #define ODEN_DAT	0xFF
52 #define REN_STRB	BIT(0)
53 #define REN_CMND	BIT(1)
54 #define REN_DATA	0xFF
55 #define PU_CMD		BIT(1)
56 #define PU_DAT		0xFF
57 #define ITAPDLY_EN	BIT(0)
58 #define OTAPDLY_EN	BIT(0)
59 #define OD_REL_CMD	BIT(1)
60 #define OD_REL_DAT	0xFF
61 #define DLLTRM_ICP	0x8
62 #define PDB_CMND	BIT(0)
63 #define PDB_DATA	0xFF
64 #define PDB_STRB	BIT(0)
65 #define PDB_CLOCK	BIT(0)
66 #define CALDONE_MASK	0x10
67 #define DLL_RDY_MASK	0x10
68 #define MAX_CLK_BUF	0x7
69 
70 /* Mode Controls */
71 #define ENHSTRB_MODE	BIT(0)
72 #define HS400_MODE	BIT(1)
73 #define LEGACY_MODE	BIT(2)
74 #define DDR50_MODE	BIT(3)
75 
76 /*
77  * Controller has no specific bits for HS200/HS.
78  * Used BIT(4), BIT(5) for software programming.
79  */
80 #define HS200_MODE	BIT(4)
81 #define HISPD_MODE	BIT(5)
82 
83 #define OTAPDLY(x)	(((x) << 1) | OTAPDLY_EN)
84 #define ITAPDLY(x)	(((x) << 1) | ITAPDLY_EN)
85 #define FREQSEL(x)	(((x) << 5) | DLL_ENBL)
86 #define IOPAD(x, y)	((x) | ((y) << 2))
87 
88 /* Arasan private data */
89 struct arasan_host {
90 	u32 chg_clk;
91 };
92 
arasan_phy_addr_poll(struct sdhci_host * host,u32 offset,u32 mask)93 static int arasan_phy_addr_poll(struct sdhci_host *host, u32 offset, u32 mask)
94 {
95 	ktime_t timeout = ktime_add_us(ktime_get(), 100);
96 	bool failed;
97 	u8 val = 0;
98 
99 	while (1) {
100 		failed = ktime_after(ktime_get(), timeout);
101 		val = sdhci_readw(host, PHY_ADDR_REG);
102 		if (!(val & mask))
103 			return 0;
104 		if (failed)
105 			return -EBUSY;
106 	}
107 }
108 
arasan_phy_write(struct sdhci_host * host,u8 data,u8 offset)109 static int arasan_phy_write(struct sdhci_host *host, u8 data, u8 offset)
110 {
111 	sdhci_writew(host, data, PHY_DAT_REG);
112 	sdhci_writew(host, (PHY_WRITE | offset), PHY_ADDR_REG);
113 	return arasan_phy_addr_poll(host, PHY_ADDR_REG, PHY_BUSY);
114 }
115 
arasan_phy_read(struct sdhci_host * host,u8 offset,u8 * data)116 static int arasan_phy_read(struct sdhci_host *host, u8 offset, u8 *data)
117 {
118 	int ret;
119 
120 	sdhci_writew(host, 0, PHY_DAT_REG);
121 	sdhci_writew(host, offset, PHY_ADDR_REG);
122 	ret = arasan_phy_addr_poll(host, PHY_ADDR_REG, PHY_BUSY);
123 
124 	/* Masking valid data bits */
125 	*data = sdhci_readw(host, PHY_DAT_REG) & DATA_MASK;
126 	return ret;
127 }
128 
arasan_phy_sts_poll(struct sdhci_host * host,u32 offset,u32 mask)129 static int arasan_phy_sts_poll(struct sdhci_host *host, u32 offset, u32 mask)
130 {
131 	int ret;
132 	ktime_t timeout = ktime_add_us(ktime_get(), 100);
133 	bool failed;
134 	u8 val = 0;
135 
136 	while (1) {
137 		failed = ktime_after(ktime_get(), timeout);
138 		ret = arasan_phy_read(host, offset, &val);
139 		if (ret)
140 			return -EBUSY;
141 		else if (val & mask)
142 			return 0;
143 		if (failed)
144 			return -EBUSY;
145 	}
146 }
147 
148 /* Initialize the Arasan PHY */
arasan_phy_init(struct sdhci_host * host)149 static int arasan_phy_init(struct sdhci_host *host)
150 {
151 	int ret;
152 	u8 val;
153 
154 	/* Program IOPADs and wait for calibration to be done */
155 	if (arasan_phy_read(host, IPAD_CTRL1, &val) ||
156 	    arasan_phy_write(host, val | RETB_ENBL | PDB_ENBL, IPAD_CTRL1) ||
157 	    arasan_phy_read(host, IPAD_CTRL2, &val) ||
158 	    arasan_phy_write(host, val | RTRIM_EN, IPAD_CTRL2))
159 		return -EBUSY;
160 	ret = arasan_phy_sts_poll(host, IPAD_STS, CALDONE_MASK);
161 	if (ret)
162 		return -EBUSY;
163 
164 	/* Program CMD/Data lines */
165 	if (arasan_phy_read(host, IOREN_CTRL1, &val) ||
166 	    arasan_phy_write(host, val | REN_CMND | REN_STRB, IOREN_CTRL1) ||
167 	    arasan_phy_read(host, IOPU_CTRL1, &val) ||
168 	    arasan_phy_write(host, val | PU_CMD, IOPU_CTRL1) ||
169 	    arasan_phy_read(host, CMD_CTRL, &val) ||
170 	    arasan_phy_write(host, val | PDB_CMND, CMD_CTRL) ||
171 	    arasan_phy_read(host, IOREN_CTRL2, &val) ||
172 	    arasan_phy_write(host, val | REN_DATA, IOREN_CTRL2) ||
173 	    arasan_phy_read(host, IOPU_CTRL2, &val) ||
174 	    arasan_phy_write(host, val | PU_DAT, IOPU_CTRL2) ||
175 	    arasan_phy_read(host, DATA_CTRL, &val) ||
176 	    arasan_phy_write(host, val | PDB_DATA, DATA_CTRL) ||
177 	    arasan_phy_read(host, STRB_CTRL, &val) ||
178 	    arasan_phy_write(host, val | PDB_STRB, STRB_CTRL) ||
179 	    arasan_phy_read(host, CLK_CTRL, &val) ||
180 	    arasan_phy_write(host, val | PDB_CLOCK, CLK_CTRL) ||
181 	    arasan_phy_read(host, CLKBUF_SEL, &val) ||
182 	    arasan_phy_write(host, val | MAX_CLK_BUF, CLKBUF_SEL) ||
183 	    arasan_phy_write(host, LEGACY_MODE, MODE_CTRL))
184 		return -EBUSY;
185 	return 0;
186 }
187 
188 /* Set Arasan PHY for different modes */
arasan_phy_set(struct sdhci_host * host,u8 mode,u8 otap,u8 drv_type,u8 itap,u8 trim,u8 clk)189 static int arasan_phy_set(struct sdhci_host *host, u8 mode, u8 otap,
190 			  u8 drv_type, u8 itap, u8 trim, u8 clk)
191 {
192 	u8 val;
193 	int ret;
194 
195 	if (mode == HISPD_MODE || mode == HS200_MODE)
196 		ret = arasan_phy_write(host, 0x0, MODE_CTRL);
197 	else
198 		ret = arasan_phy_write(host, mode, MODE_CTRL);
199 	if (ret)
200 		return ret;
201 	if (mode == HS400_MODE || mode == HS200_MODE) {
202 		ret = arasan_phy_read(host, IPAD_CTRL1, &val);
203 		if (ret)
204 			return ret;
205 		ret = arasan_phy_write(host, IOPAD(val, drv_type), IPAD_CTRL1);
206 		if (ret)
207 			return ret;
208 	}
209 	if (mode == LEGACY_MODE) {
210 		ret = arasan_phy_write(host, 0x0, OTAP_DELAY);
211 		if (ret)
212 			return ret;
213 		ret = arasan_phy_write(host, 0x0, ITAP_DELAY);
214 	} else {
215 		ret = arasan_phy_write(host, OTAPDLY(otap), OTAP_DELAY);
216 		if (ret)
217 			return ret;
218 		if (mode != HS200_MODE)
219 			ret = arasan_phy_write(host, ITAPDLY(itap), ITAP_DELAY);
220 		else
221 			ret = arasan_phy_write(host, 0x0, ITAP_DELAY);
222 	}
223 	if (ret)
224 		return ret;
225 	if (mode != LEGACY_MODE) {
226 		ret = arasan_phy_write(host, trim, DLL_TRIM);
227 		if (ret)
228 			return ret;
229 	}
230 	ret = arasan_phy_write(host, 0, DLL_STATUS);
231 	if (ret)
232 		return ret;
233 	if (mode != LEGACY_MODE) {
234 		ret = arasan_phy_write(host, FREQSEL(clk), DLL_STATUS);
235 		if (ret)
236 			return ret;
237 		ret = arasan_phy_sts_poll(host, DLL_STATUS, DLL_RDY_MASK);
238 		if (ret)
239 			return -EBUSY;
240 	}
241 	return 0;
242 }
243 
arasan_select_phy_clock(struct sdhci_host * host)244 static int arasan_select_phy_clock(struct sdhci_host *host)
245 {
246 	struct sdhci_pci_slot *slot = sdhci_priv(host);
247 	struct arasan_host *arasan_host = sdhci_pci_priv(slot);
248 	u8 clk;
249 
250 	if (arasan_host->chg_clk == host->mmc->ios.clock)
251 		return 0;
252 
253 	arasan_host->chg_clk = host->mmc->ios.clock;
254 	if (host->mmc->ios.clock == 200000000)
255 		clk = 0x0;
256 	else if (host->mmc->ios.clock == 100000000)
257 		clk = 0x2;
258 	else if (host->mmc->ios.clock == 50000000)
259 		clk = 0x1;
260 	else
261 		clk = 0x0;
262 
263 	if (host->mmc_host_ops.hs400_enhanced_strobe) {
264 		arasan_phy_set(host, ENHSTRB_MODE, 1, 0x0, 0x0,
265 			       DLLTRM_ICP, clk);
266 	} else {
267 		switch (host->mmc->ios.timing) {
268 		case MMC_TIMING_LEGACY:
269 			arasan_phy_set(host, LEGACY_MODE, 0x0, 0x0, 0x0,
270 				       0x0, 0x0);
271 			break;
272 		case MMC_TIMING_MMC_HS:
273 		case MMC_TIMING_SD_HS:
274 			arasan_phy_set(host, HISPD_MODE, 0x3, 0x0, 0x2,
275 				       DLLTRM_ICP, clk);
276 			break;
277 		case MMC_TIMING_MMC_HS200:
278 		case MMC_TIMING_UHS_SDR104:
279 			arasan_phy_set(host, HS200_MODE, 0x2,
280 				       host->mmc->ios.drv_type, 0x0,
281 				       DLLTRM_ICP, clk);
282 			break;
283 		case MMC_TIMING_MMC_DDR52:
284 		case MMC_TIMING_UHS_DDR50:
285 			arasan_phy_set(host, DDR50_MODE, 0x1, 0x0,
286 				       0x0, DLLTRM_ICP, clk);
287 			break;
288 		case MMC_TIMING_MMC_HS400:
289 			arasan_phy_set(host, HS400_MODE, 0x1,
290 				       host->mmc->ios.drv_type, 0xa,
291 				       DLLTRM_ICP, clk);
292 			break;
293 		default:
294 			break;
295 		}
296 	}
297 	return 0;
298 }
299 
arasan_pci_probe_slot(struct sdhci_pci_slot * slot)300 static int arasan_pci_probe_slot(struct sdhci_pci_slot *slot)
301 {
302 	int err;
303 
304 	slot->host->mmc->caps |= MMC_CAP_NONREMOVABLE | MMC_CAP_8_BIT_DATA;
305 	err = arasan_phy_init(slot->host);
306 	if (err)
307 		return -ENODEV;
308 	return 0;
309 }
310 
arasan_sdhci_set_clock(struct sdhci_host * host,unsigned int clock)311 static void arasan_sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
312 {
313 	sdhci_set_clock(host, clock);
314 
315 	/* Change phy settings for the new clock */
316 	arasan_select_phy_clock(host);
317 }
318 
319 static const struct sdhci_ops arasan_sdhci_pci_ops = {
320 	.set_clock	= arasan_sdhci_set_clock,
321 	.enable_dma	= sdhci_pci_enable_dma,
322 	.set_bus_width	= sdhci_set_bus_width,
323 	.reset		= sdhci_reset,
324 	.set_uhs_signaling	= sdhci_set_uhs_signaling,
325 };
326 
327 const struct sdhci_pci_fixes sdhci_arasan = {
328 	.probe_slot = arasan_pci_probe_slot,
329 	.ops        = &arasan_sdhci_pci_ops,
330 	.priv_size  = sizeof(struct arasan_host),
331 };
332