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/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 EARLY_DRIVER_MODULE(rk_emmcphy, simplebus, rk_emmcphy_driver, 0, 0, 339 BUS_PASS_SUPPORTDEV + BUS_PASS_ORDER_MIDDLE); 340 MODULE_VERSION(rk_emmcphy, 1); 341