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