]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm64/rockchip/rk3399_emmcphy.c
MFV: r362513
[FreeBSD/FreeBSD.git] / sys / arm64 / rockchip / rk3399_emmcphy.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2019 Ganbold Tsagaankhuu <ganbold@FreeBSD.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 /*
30  * Rockchip RK3399 eMMC PHY
31  */
32
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/bus.h>
39 #include <sys/rman.h>
40 #include <sys/kernel.h>
41 #include <sys/module.h>
42 #include <sys/gpio.h>
43 #include <machine/bus.h>
44
45 #include <dev/fdt/fdt_common.h>
46 #include <dev/ofw/ofw_bus.h>
47 #include <dev/ofw/ofw_bus_subr.h>
48
49 #include <dev/extres/clk/clk.h>
50 #include <dev/extres/syscon/syscon.h>
51 #include <dev/extres/phy/phy.h>
52
53 #include "syscon_if.h"
54
55 #define GRF_EMMCPHY_BASE        0xf780
56 #define GRF_EMMCPHY_CON0        (GRF_EMMCPHY_BASE + 0x00)
57 #define  PHYCTRL_FRQSEL         (1 << 13) | (1 << 12)
58 #define   PHYCTRL_FRQSEL_200M   0
59 #define   PHYCTRL_FRQSEL_50M    1
60 #define   PHYCTRL_FRQSEL_100M   2
61 #define   PHYCTRL_FRQSEL_150M   3
62 #define  PHYCTRL_OTAPDLYENA     (1 << 11)
63 #define  PHYCTRL_OTAPDLYSEL     (1 << 10) | (1 << 9) | (1 << 8) | (1 << 7)
64 #define  PHYCTRL_ITAPCHGWIN     (1 << 6)
65 #define  PHYCTRL_ITAPDLYSEL     (1 << 5) | (1 << 4)  | (1 << 3) | (1 << 2) | \
66     (1 << 1)
67 #define  PHYCTRL_ITAPDLYENA     (1 << 0)
68 #define GRF_EMMCPHY_CON1        (GRF_EMMCPHY_BASE + 0x04)
69 #define  PHYCTRL_CLKBUFSEL      (1 << 8) | (1 << 7) | (1 << 6)
70 #define  PHYCTRL_SELDLYTXCLK    (1 << 5)
71 #define  PHYCTRL_SELDLYRXCLK    (1 << 4)
72 #define  PHYCTRL_STRBSEL        0xf
73 #define GRF_EMMCPHY_CON2        (GRF_EMMCPHY_BASE + 0x08)
74 #define  PHYCTRL_REN_STRB       (1 << 9)
75 #define  PHYCTRL_REN_CMD        (1 << 8)
76 #define  PHYCTRL_REN_DAT        0xff
77 #define GRF_EMMCPHY_CON3        (GRF_EMMCPHY_BASE + 0x0c)
78 #define  PHYCTRL_PU_STRB        (1 << 9)
79 #define  PHYCTRL_PU_CMD         (1 << 8)
80 #define  PHYCTRL_PU_DAT         0xff
81 #define GRF_EMMCPHY_CON4        (GRF_EMMCPHY_BASE + 0x10)
82 #define  PHYCTRL_OD_RELEASE_CMD         (1 << 9)
83 #define  PHYCTRL_OD_RELEASE_STRB        (1 << 8)
84 #define  PHYCTRL_OD_RELEASE_DAT         0xff
85 #define GRF_EMMCPHY_CON5        (GRF_EMMCPHY_BASE + 0x14)
86 #define  PHYCTRL_ODEN_STRB      (1 << 9)
87 #define  PHYCTRL_ODEN_CMD       (1 << 8)
88 #define  PHYCTRL_ODEN_DAT       0xff
89 #define GRF_EMMCPHY_CON6        (GRF_EMMCPHY_BASE + 0x18)
90 #define  PHYCTRL_DLL_TRM_ICP    (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9)
91 #define  PHYCTRL_EN_RTRIM       (1 << 8)
92 #define  PHYCTRL_RETRIM         (1 << 7)
93 #define  PHYCTRL_DR_TY          (1 << 6) | (1 << 5) | (1 << 4)
94 #define  PHYCTRL_RETENB         (1 << 3)
95 #define  PHYCTRL_RETEN          (1 << 2)
96 #define  PHYCTRL_ENDLL          (1 << 1)
97 #define  PHYCTRL_PDB            (1 << 0)
98 #define GRF_EMMCPHY_STATUS      (GRF_EMMCPHY_BASE + 0x20)
99 #define  PHYCTRL_CALDONE        (1 << 6)
100 #define  PHYCTRL_DLLRDY         (1 << 5)
101 #define  PHYCTRL_RTRIM          (1 << 4) | (1 << 3) | (1 << 2) | (1 << 1)
102 #define  PHYCTRL_EXR_NINST      (1 << 0)
103
104 static struct ofw_compat_data compat_data[] = {
105         { "rockchip,rk3399-emmc-phy",   1 },
106         { NULL,                         0 }
107 };
108
109 struct rk_emmcphy_softc {
110         struct syscon           *syscon;
111         struct rk_emmcphy_conf  *phy_conf;
112         clk_t                   clk;
113 };
114
115 #define LOWEST_SET_BIT(mask)    ((((mask) - 1) & (mask)) ^ (mask))
116 #define SHIFTIN(x, mask)        ((x) * LOWEST_SET_BIT(mask))
117
118 /* Phy class and methods. */
119 static int rk_emmcphy_enable(struct phynode *phynode, bool enable);
120 static phynode_method_t rk_emmcphy_phynode_methods[] = {
121         PHYNODEMETHOD(phynode_enable,   rk_emmcphy_enable),
122         PHYNODEMETHOD_END
123 };
124
125 DEFINE_CLASS_1(rk_emmcphy_phynode, rk_emmcphy_phynode_class,
126     rk_emmcphy_phynode_methods, 0, phynode_class);
127
128 static int
129 rk_emmcphy_enable(struct phynode *phynode, bool enable)
130 {
131         struct rk_emmcphy_softc *sc;
132         device_t dev;
133         intptr_t phy;
134         uint64_t rate, frqsel;
135         uint32_t mask, val;
136         int error;
137
138         dev = phynode_get_device(phynode);
139         phy = phynode_get_id(phynode);
140         sc = device_get_softc(dev);
141
142         if (bootverbose)
143                 device_printf(dev, "Phy id: %ld\n", phy);
144
145         if (phy != 0) {
146                 device_printf(dev, "Unknown phy: %ld\n", phy);
147                 return (ERANGE);
148         }
149         if (enable) {
150                 /* Drive strength */
151                 mask = PHYCTRL_DR_TY;
152                 val = SHIFTIN(0, PHYCTRL_DR_TY);
153                 SYSCON_WRITE_4(sc->syscon, GRF_EMMCPHY_CON6,
154                     (mask << 16) | val);
155
156                 /* Enable output tap delay */
157                 mask = PHYCTRL_OTAPDLYENA | PHYCTRL_OTAPDLYSEL;
158                 val = PHYCTRL_OTAPDLYENA | SHIFTIN(4, PHYCTRL_OTAPDLYSEL);
159                 SYSCON_WRITE_4(sc->syscon, GRF_EMMCPHY_CON0,
160                     (mask << 16) | val);
161         }
162
163         /* Power down PHY and disable DLL before making changes */
164         mask = PHYCTRL_ENDLL | PHYCTRL_PDB;
165         val = 0;
166         SYSCON_WRITE_4(sc->syscon, GRF_EMMCPHY_CON6, (mask << 16) | val);
167
168         if (enable == false)
169                 return (0);
170
171         sc->phy_conf = (struct rk_emmcphy_conf *)ofw_bus_search_compatible(dev,
172             compat_data)->ocd_data;
173
174         /* Get clock */
175         error = clk_get_by_ofw_name(dev, 0, "emmcclk", &sc->clk);
176         if (error != 0) {
177                 device_printf(dev, "cannot get emmcclk clock, continue\n");
178                 sc->clk = NULL;
179         } else
180                 device_printf(dev, "got emmcclk clock\n");
181
182         if (sc->clk) {
183                 error = clk_get_freq(sc->clk, &rate);
184                 if (error != 0) {
185                         device_printf(dev, "cannot get clock frequency\n");
186                         return (ENXIO);
187                 }
188         } else
189                 rate = 0;
190
191         if (rate != 0) {
192                 if (rate < 75000000)
193                         frqsel = PHYCTRL_FRQSEL_50M;
194                 else if (rate < 125000000)
195                         frqsel = PHYCTRL_FRQSEL_100M;
196                 else if (rate < 175000000)
197                         frqsel = PHYCTRL_FRQSEL_150M;
198                 else
199                         frqsel = PHYCTRL_FRQSEL_200M;
200         } else
201                 frqsel = PHYCTRL_FRQSEL_200M;
202
203         DELAY(3);
204
205         /* Power up PHY */
206         mask = PHYCTRL_PDB;
207         val = PHYCTRL_PDB;
208         SYSCON_WRITE_4(sc->syscon, GRF_EMMCPHY_CON6, (mask << 16) | val);
209
210         /* Wait for calibration */
211         DELAY(10);
212         val = SYSCON_READ_4(sc->syscon, GRF_EMMCPHY_STATUS);
213         if ((val & PHYCTRL_CALDONE) == 0) {
214                 device_printf(dev, "PHY calibration did not complete\n");
215                 return (ENXIO);
216         }
217
218         /* Set DLL frequency */
219         mask = PHYCTRL_FRQSEL;
220         val = SHIFTIN(frqsel, PHYCTRL_FRQSEL);
221         SYSCON_WRITE_4(sc->syscon, GRF_EMMCPHY_CON0, (mask << 16) | val);
222
223         /* Enable DLL */
224         mask = PHYCTRL_ENDLL;
225         val = PHYCTRL_ENDLL;
226         SYSCON_WRITE_4(sc->syscon, GRF_EMMCPHY_CON6, (mask << 16) | val);
227
228         if (rate != 0) {
229                 /*
230                  * Rockchip RK3399 TRM V1.3 Part2.pdf says in page 698:
231                  * After the DLL control loop reaches steady state a DLL
232                  * ready signal is generated by the DLL circuits
233                  * 'phyctrl_dllrdy'.
234                  * The time from 'phyctrl_endll' to DLL ready signal
235                  * 'phyctrl_dllrdy' varies with the clock frequency.
236                  * At 200MHz clock frequency the DLL ready delay is 2.56us,
237                  * at 100MHz clock frequency the DLL ready delay is 5.112us and
238                  * at 50 MHz clock frequency the DLL ready delay is 10.231us.
239                  * We could use safe values for wait, 12us, 8us, 6us and 4us
240                  * respectively.
241                  * However due to some unknown reason it is not working and
242                  * DLL seems to take extra long time to lock.
243                  * So we will use more safe value 50ms here.
244                  */
245
246                 /* Wait for DLL ready */
247                 DELAY(50000);
248                 val = SYSCON_READ_4(sc->syscon, GRF_EMMCPHY_STATUS);
249                 if ((val & PHYCTRL_DLLRDY) == 0) {
250                         device_printf(dev, "DLL loop failed to lock\n");
251                         return (ENXIO);
252                 }
253         }
254
255         return (0);
256 }
257
258 static int
259 rk_emmcphy_probe(device_t dev)
260 {
261
262         if (!ofw_bus_status_okay(dev))
263                 return (ENXIO);
264
265         if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
266                 return (ENXIO);
267
268         device_set_desc(dev, "Rockchip RK3399 eMMC PHY");
269         return (BUS_PROBE_DEFAULT);
270 }
271
272 static int
273 rk_emmcphy_attach(device_t dev)
274 {
275         struct phynode_init_def phy_init;
276         struct phynode *phynode;
277         struct rk_emmcphy_softc *sc;
278         phandle_t node;
279         phandle_t xnode;
280         pcell_t handle;
281         intptr_t phy;
282
283         sc = device_get_softc(dev);
284         node = ofw_bus_get_node(dev);
285
286         if (OF_getencprop(node, "clocks", (void *)&handle,
287             sizeof(handle)) <= 0) {
288                 device_printf(dev, "cannot get clocks handle\n");
289                 return (ENXIO);
290         }
291         xnode = OF_node_from_xref(handle);
292         if (OF_hasprop(xnode, "arasan,soc-ctl-syscon") &&
293             syscon_get_by_ofw_property(dev, xnode,
294             "arasan,soc-ctl-syscon", &sc->syscon) != 0) {
295                 device_printf(dev, "cannot get grf driver handle\n");
296                 return (ENXIO);
297         }
298
299         if (sc->syscon == NULL) {
300                 device_printf(dev, "failed to get syscon\n");
301                 return (ENXIO);
302         }
303
304         /* Create and register phy */
305         bzero(&phy_init, sizeof(phy_init));
306         phy_init.id = 0;
307         phy_init.ofw_node = ofw_bus_get_node(dev);
308         phynode = phynode_create(dev, &rk_emmcphy_phynode_class, &phy_init);
309         if (phynode == NULL) {
310                 device_printf(dev, "failed to create eMMC PHY\n");
311                 return (ENXIO);
312         }
313         if (phynode_register(phynode) == NULL) {
314                 device_printf(dev, "failed to register eMMC PHY\n");
315                 return (ENXIO);
316         }
317         if (bootverbose) {
318                 phy = phynode_get_id(phynode);
319                 device_printf(dev, "Attached phy id: %ld\n", phy);
320         }
321         return (0);
322 }
323
324 static device_method_t rk_emmcphy_methods[] = {
325         /* Device interface */
326         DEVMETHOD(device_probe,         rk_emmcphy_probe),
327         DEVMETHOD(device_attach,        rk_emmcphy_attach),
328
329         DEVMETHOD_END
330 };
331
332 static driver_t rk_emmcphy_driver = {
333         "rk_emmcphy",
334         rk_emmcphy_methods,
335         sizeof(struct rk_emmcphy_softc)
336 };
337
338 static devclass_t rk_emmcphy_devclass;
339 EARLY_DRIVER_MODULE(rk_emmcphy, simplebus, rk_emmcphy_driver,
340     rk_emmcphy_devclass, 0, 0, BUS_PASS_SUPPORTDEV + BUS_PASS_ORDER_MIDDLE);
341 MODULE_VERSION(rk_emmcphy, 1);