1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2019 Ganbold Tsagaankhuu <ganbold@freebsd.org> 5 * Copyright (c) 2022 Søren Schmidt <sos@FreeBSD.org> 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 ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include <sys/param.h> 29 #include <sys/systm.h> 30 #include <sys/bus.h> 31 #include <sys/kernel.h> 32 #include <sys/lock.h> 33 #include <sys/module.h> 34 #include <sys/mutex.h> 35 #include <sys/resource.h> 36 #include <sys/rman.h> 37 #include <sys/sysctl.h> 38 #include <sys/taskqueue.h> 39 40 #include <machine/bus.h> 41 #include <machine/resource.h> 42 43 #include <dev/fdt/fdt_common.h> 44 #include <dev/ofw/ofw_bus.h> 45 #include <dev/ofw/ofw_bus_subr.h> 46 47 #include <dev/ofw/ofw_subr.h> 48 #include <dev/clk/clk.h> 49 #include <dev/clk/clk_fixed.h> 50 #include <dev/ofw/openfirm.h> 51 #include <dev/syscon/syscon.h> 52 #include <dev/phy/phy.h> 53 54 #include <dev/mmc/bridge.h> 55 56 #include <dev/sdhci/sdhci.h> 57 #include <dev/sdhci/sdhci_fdt.h> 58 59 #include "mmcbr_if.h" 60 #include "sdhci_if.h" 61 62 #include "opt_mmccam.h" 63 64 #include "clkdev_if.h" 65 #include "syscon_if.h" 66 67 #define SDHCI_FDT_RK3399 1 68 #define SDHCI_FDT_RK3568 2 69 70 #define RK3399_GRF_EMMCCORE_CON0 0xf000 71 #define RK3399_CORECFG_BASECLKFREQ 0xff00 72 #define RK3399_CORECFG_TIMEOUTCLKUNIT (1 << 7) 73 #define RK3399_CORECFG_TUNINGCOUNT 0x3f 74 #define RK3399_GRF_EMMCCORE_CON11 0xf02c 75 #define RK3399_CORECFG_CLOCKMULTIPLIER 0xff 76 77 #define RK3568_EMMC_HOST_CTRL 0x0508 78 #define RK3568_EMMC_EMMC_CTRL 0x052c 79 #define RK3568_EMMC_ATCTRL 0x0540 80 #define RK3568_EMMC_DLL_CTRL 0x0800 81 #define DLL_CTRL_SRST 0x00000001 82 #define DLL_CTRL_START 0x00000002 83 #define DLL_CTRL_START_POINT_DEFAULT 0x00050000 84 #define DLL_CTRL_INCREMENT_DEFAULT 0x00000200 85 86 #define RK3568_EMMC_DLL_RXCLK 0x0804 87 #define DLL_RXCLK_DELAY_ENABLE 0x08000000 88 #define DLL_RXCLK_NO_INV 0x20000000 89 90 #define RK3568_EMMC_DLL_TXCLK 0x0808 91 #define DLL_TXCLK_DELAY_ENABLE 0x08000000 92 #define DLL_TXCLK_TAPNUM_DEFAULT 0x00000008 93 #define DLL_TXCLK_TAPNUM_FROM_SW 0x01000000 94 95 #define RK3568_EMMC_DLL_STRBIN 0x080c 96 #define DLL_STRBIN_DELAY_ENABLE 0x08000000 97 #define DLL_STRBIN_TAPNUM_DEFAULT 0x00000008 98 #define DLL_STRBIN_TAPNUM_FROM_SW 0x01000000 99 100 #define RK3568_EMMC_DLL_STATUS0 0x0840 101 #define DLL_STATUS0_DLL_LOCK 0x00000100 102 #define DLL_STATUS0_DLL_TIMEOUT 0x00000200 103 104 #define LOWEST_SET_BIT(mask) ((((mask) - 1) & (mask)) ^ (mask)) 105 #define SHIFTIN(x, mask) ((x) * LOWEST_SET_BIT(mask)) 106 107 static struct ofw_compat_data compat_data[] = { 108 { "rockchip,rk3399-sdhci-5.1", SDHCI_FDT_RK3399 }, 109 { "rockchip,rk3568-dwcmshc", SDHCI_FDT_RK3568 }, 110 { NULL, 0 } 111 }; 112 113 static int 114 sdhci_fdt_rockchip_probe(device_t dev) 115 { 116 struct sdhci_fdt_softc *sc = device_get_softc(dev); 117 118 sc->quirks = 0; 119 switch (ofw_bus_search_compatible(dev, compat_data)->ocd_data) { 120 if (!ofw_bus_status_okay(dev)) 121 return (ENXIO); 122 case SDHCI_FDT_RK3399: 123 device_set_desc(dev, "Rockchip RK3399 fdt SDHCI controller"); 124 break; 125 case SDHCI_FDT_RK3568: 126 device_set_desc(dev, "Rockchip RK3568 fdt SDHCI controller"); 127 break; 128 default: 129 return (ENXIO); 130 } 131 132 return (0); 133 } 134 135 static int 136 sdhci_init_rk3399(device_t dev) 137 { 138 struct sdhci_fdt_softc *sc = device_get_softc(dev); 139 uint64_t freq; 140 uint32_t mask, val; 141 int error; 142 143 error = clk_get_freq(sc->clk_xin, &freq); 144 if (error != 0) { 145 device_printf(dev, "cannot get xin clock frequency\n"); 146 return (ENXIO); 147 } 148 149 /* Disable clock multiplier */ 150 mask = RK3399_CORECFG_CLOCKMULTIPLIER; 151 val = 0; 152 SYSCON_WRITE_4(sc->syscon, RK3399_GRF_EMMCCORE_CON11, (mask << 16) | val); 153 154 /* Set base clock frequency */ 155 mask = RK3399_CORECFG_BASECLKFREQ; 156 val = SHIFTIN((freq + (1000000 / 2)) / 1000000, 157 RK3399_CORECFG_BASECLKFREQ); 158 SYSCON_WRITE_4(sc->syscon, RK3399_GRF_EMMCCORE_CON0, (mask << 16) | val); 159 160 return (0); 161 } 162 163 static int 164 sdhci_fdt_rockchip_set_clock(device_t dev, struct sdhci_slot *slot, int clock) 165 { 166 struct sdhci_fdt_softc *sc = device_get_softc(dev); 167 int32_t val; 168 int i; 169 170 if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 171 SDHCI_FDT_RK3568) { 172 if (clock == 400000) 173 clock = 375000; 174 175 if (clock) { 176 clk_set_freq(sc->clk_core, clock, 0); 177 178 if (clock <= 52000000) { 179 bus_write_4(sc->mem_res[slot->num], 180 RK3568_EMMC_DLL_CTRL, 0x0); 181 bus_write_4(sc->mem_res[slot->num], 182 RK3568_EMMC_DLL_RXCLK, DLL_RXCLK_NO_INV); 183 bus_write_4(sc->mem_res[slot->num], 184 RK3568_EMMC_DLL_TXCLK, 0x0); 185 bus_write_4(sc->mem_res[slot->num], 186 RK3568_EMMC_DLL_STRBIN, 0x0); 187 return (clock); 188 } 189 190 bus_write_4(sc->mem_res[slot->num], 191 RK3568_EMMC_DLL_CTRL, DLL_CTRL_START); 192 DELAY(1000); 193 bus_write_4(sc->mem_res[slot->num], 194 RK3568_EMMC_DLL_CTRL, 0); 195 bus_write_4(sc->mem_res[slot->num], 196 RK3568_EMMC_DLL_CTRL, DLL_CTRL_START_POINT_DEFAULT | 197 DLL_CTRL_INCREMENT_DEFAULT | DLL_CTRL_START); 198 for (i = 0; i < 500; i++) { 199 val = bus_read_4(sc->mem_res[slot->num], 200 RK3568_EMMC_DLL_STATUS0); 201 if (val & DLL_STATUS0_DLL_LOCK && 202 !(val & DLL_STATUS0_DLL_TIMEOUT)) 203 break; 204 DELAY(1000); 205 } 206 bus_write_4(sc->mem_res[slot->num], RK3568_EMMC_ATCTRL, 207 (0x1 << 16 | 0x2 << 17 | 0x3 << 19)); 208 bus_write_4(sc->mem_res[slot->num], 209 RK3568_EMMC_DLL_RXCLK, 210 DLL_RXCLK_DELAY_ENABLE | DLL_RXCLK_NO_INV); 211 bus_write_4(sc->mem_res[slot->num], 212 RK3568_EMMC_DLL_TXCLK, DLL_TXCLK_DELAY_ENABLE | 213 DLL_TXCLK_TAPNUM_DEFAULT|DLL_TXCLK_TAPNUM_FROM_SW); 214 bus_write_4(sc->mem_res[slot->num], 215 RK3568_EMMC_DLL_STRBIN, DLL_STRBIN_DELAY_ENABLE | 216 DLL_STRBIN_TAPNUM_DEFAULT | 217 DLL_STRBIN_TAPNUM_FROM_SW); 218 } 219 } 220 return (sdhci_fdt_set_clock(dev, slot, clock)); 221 } 222 223 static int 224 sdhci_fdt_rockchip_attach(device_t dev) 225 { 226 struct sdhci_fdt_softc *sc = device_get_softc(dev); 227 int err, compat; 228 229 sc->dev = dev; 230 compat = ofw_bus_search_compatible(dev, compat_data)->ocd_data; 231 switch (compat) { 232 case SDHCI_FDT_RK3399: 233 err = sdhci_init_clocks(dev); 234 if (err != 0) { 235 device_printf(dev, "Cannot init clocks\n"); 236 return (err); 237 } 238 sdhci_export_clocks(sc); 239 if ((err = sdhci_init_phy(sc)) != 0) { 240 device_printf(dev, "Cannot init phy\n"); 241 return (err); 242 } 243 if ((err = sdhci_get_syscon(sc)) != 0) { 244 device_printf(dev, "Cannot get syscon handle\n"); 245 return (err); 246 } 247 err = sdhci_init_rk3399(dev); 248 if (err != 0) { 249 device_printf(dev, "Cannot init RK3399 SDHCI\n"); 250 return (err); 251 } 252 break; 253 case SDHCI_FDT_RK3568: 254 /* setup & enable clocks */ 255 if (clk_get_by_ofw_name(dev, 0, "core", &sc->clk_core)) { 256 device_printf(dev, "cannot get core clock\n"); 257 return (ENXIO); 258 } 259 clk_enable(sc->clk_core); 260 break; 261 default: 262 break; 263 } 264 265 return (sdhci_fdt_attach(dev)); 266 } 267 268 static device_method_t sdhci_fdt_rockchip_methods[] = { 269 /* device_if */ 270 DEVMETHOD(device_probe, sdhci_fdt_rockchip_probe), 271 DEVMETHOD(device_attach, sdhci_fdt_rockchip_attach), 272 273 /* SDHCI methods */ 274 DEVMETHOD(sdhci_set_clock, sdhci_fdt_rockchip_set_clock), 275 276 DEVMETHOD_END 277 }; 278 extern driver_t sdhci_fdt_driver; 279 280 DEFINE_CLASS_1(sdhci_rockchip, sdhci_fdt_rockchip_driver, sdhci_fdt_rockchip_methods, 281 sizeof(struct sdhci_fdt_softc), sdhci_fdt_driver); 282 DRIVER_MODULE(sdhci_rockchip, simplebus, sdhci_fdt_rockchip_driver, NULL, NULL); 283