Index: sys/dev/sdhci/sdhci_fdt.c =================================================================== --- sys/dev/sdhci/sdhci_fdt.c +++ sys/dev/sdhci/sdhci_fdt.c @@ -52,6 +52,9 @@ #include #include +#include +#include + #include #include @@ -61,16 +64,30 @@ #include "opt_mmccam.h" +#include "syscon_if.h" + #define MAX_SLOTS 6 #define SDHCI_FDT_ARMADA38X 1 #define SDHCI_FDT_GENERIC 2 #define SDHCI_FDT_XLNX_ZY7 3 #define SDHCI_FDT_QUALCOMM 4 +#define SDHCI_FDT_RK3399 5 +#define RK3399_GRF_EMMCCORE_CON0 0xf000 +#define RK3399_CORECFG_BASECLKFREQ (1 << 15) | (1 << 8) +#define RK3399_CORECFG_TIMEOUTCLKUNIT (1 << 7) +#define RK3399_CORECFG_TUNINGCOUNT (1 << 5) | (1 << 0) +#define RK3399_GRF_EMMCCORE_CON11 0xf02c +#define RK3399_CORECFG_CLOCKMULTIPLIER (1 << 7) | (1 << 0) + +#define LOWEST_SET_BIT(mask) ((((mask) - 1) & (mask)) ^ (mask)) +#define SHIFTIN(x, mask) ((x) * LOWEST_SET_BIT(mask)) + static struct ofw_compat_data compat_data[] = { { "marvell,armada-380-sdhci", SDHCI_FDT_ARMADA38X }, { "sdhci_generic", SDHCI_FDT_GENERIC }, { "qcom,sdhci-msm-v4", SDHCI_FDT_QUALCOMM }, + { "rockchip,rk3399-sdhci-5.1", SDHCI_FDT_RK3399 }, { "xlnx,zy7_sdhci", SDHCI_FDT_XLNX_ZY7 }, { NULL, 0 } }; @@ -90,8 +107,28 @@ bool wp_inverted; /* WP pin is inverted */ bool no_18v; /* No 1.8V support */ + + clk_t clk_xin; + clk_t clk_ahb; }; +static void +sdhc_init_rk3399(struct syscon *grf, phandle_t node, uint64_t freq) +{ + uint32_t mask, val; + + /* Disable clock multiplier */ + mask = RK3399_CORECFG_CLOCKMULTIPLIER; + val = 0; + SYSCON_WRITE_4(grf, RK3399_GRF_EMMCCORE_CON11, (mask << 16) | val); + + /* Set base clock frequency */ + mask = RK3399_CORECFG_BASECLKFREQ; + val = SHIFTIN((freq + (1000000 / 2)) / 1000000, + RK3399_CORECFG_BASECLKFREQ); + SYSCON_WRITE_4(grf, RK3399_GRF_EMMCCORE_CON0, (mask << 16) | val); +} + static uint8_t sdhci_fdt_read_1(device_t dev, struct sdhci_slot *slot, bus_size_t off) { @@ -188,8 +225,11 @@ sdhci_fdt_probe(device_t dev) { struct sdhci_fdt_softc *sc = device_get_softc(dev); + struct syscon *grf = NULL; phandle_t node; pcell_t cid; + uint64_t freq; + int error; sc->quirks = 0; sc->num_slots = 1; @@ -198,6 +238,8 @@ if (!ofw_bus_status_okay(dev)) return (ENXIO); + node = ofw_bus_get_node(dev); + switch (ofw_bus_search_compatible(dev, compat_data)->ocd_data) { case SDHCI_FDT_ARMADA38X: sc->quirks = SDHCI_QUIRK_BROKEN_AUTO_STOP; @@ -212,6 +254,42 @@ sc->sdma_boundary = SDHCI_BLKSZ_SDMA_BNDRY_4K; device_set_desc(dev, "Qualcomm FDT SDHCI controller"); break; + case SDHCI_FDT_RK3399: + /* Get and activate clocks */ + error = clk_get_by_ofw_name(dev, 0, "clk_xin", &sc->clk_xin); + if (error != 0) { + device_printf(dev, "cannot get xin clock\n"); + return (ENXIO); + } + error = clk_enable(sc->clk_xin); + if (error != 0) { + device_printf(dev, "cannot enable xin clock\n"); + return (ENXIO); + } + error = clk_get_freq(sc->clk_xin, &freq); + if (error != 0) { + device_printf(dev, "cannot get xin clock frequency\n"); + return (ENXIO); + } + error = clk_get_by_ofw_name(dev, 0, "clk_ahb", &sc->clk_ahb); + if (error != 0) { + device_printf(dev, "cannot get ahb clock\n"); + return (ENXIO); + } + error = clk_enable(sc->clk_ahb); + if (error != 0) { + device_printf(dev, "cannot enable ahb clock\n"); + return (ENXIO); + } + if (OF_hasprop(node, "arasan,soc-ctl-syscon") && + syscon_get_by_ofw_property(dev, node, + "arasan,soc-ctl-syscon", &grf) != 0) { + device_printf(dev, "cannot get grf driver handle\n"); + return (ENXIO); + } + sdhc_init_rk3399(grf, node, freq); + device_set_desc(dev, "Rockchip RK3399 fdt SDHCI controller"); + break; case SDHCI_FDT_XLNX_ZY7: sc->quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK; device_set_desc(dev, "Zynq-7000 generic fdt SDHCI controller"); @@ -220,8 +298,6 @@ return (ENXIO); } - node = ofw_bus_get_node(dev); - /* Allow dts to patch quirks, slots, and max-frequency. */ if ((OF_getencprop(node, "quirks", &cid, sizeof(cid))) > 0) sc->quirks = cid;