Linux-libre 5.4.49-gnu
[librecmc/linux-libre.git] / drivers / mmc / host / sdhci-pci-arasan.c
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
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
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
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
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 */
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 */
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
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
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
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 };