Index: sys/dev/sdhci/sdhci_fdt.c =================================================================== --- sys/dev/sdhci/sdhci_fdt.c +++ sys/dev/sdhci/sdhci_fdt.c @@ -52,6 +52,12 @@ #include #include +#ifdef EXT_RESOURCES +#include +#include +#include +#endif + #include #include @@ -61,16 +67,35 @@ #include "opt_mmccam.h" +#ifdef EXT_RESOURCES +#include "syscon_if.h" +#include "phydev_if.h" +#endif + #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 +#ifdef EXT_RESOURCES +#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)) +#endif + 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 +115,33 @@ bool wp_inverted; /* WP pin is inverted */ bool no_18v; /* No 1.8V support */ + +#ifdef EXT_RESOURCES + clk_t clk_xin; + clk_t clk_ahb; + phy_t phy; +#endif }; +#ifdef EXT_RESOURCES +static void +sdhci_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); +} +#endif + static uint8_t sdhci_fdt_read_1(device_t dev, struct sdhci_slot *slot, bus_size_t off) { @@ -212,6 +262,9 @@ sc->sdma_boundary = SDHCI_BLKSZ_SDMA_BNDRY_4K; device_set_desc(dev, "Qualcomm FDT SDHCI controller"); break; + case SDHCI_FDT_RK3399: + 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"); @@ -243,6 +296,12 @@ struct sdhci_fdt_softc *sc = device_get_softc(dev); struct sdhci_slot *slot; int err, slots, rid, i; +#ifdef EXT_RESOURCES + struct syscon *grf = NULL; + phandle_t node; + uint64_t freq; + int error, type; +#endif sc->dev = dev; @@ -255,6 +314,59 @@ return (ENOMEM); } +#ifdef EXT_RESOURCES + type = ofw_bus_search_compatible(dev, compat_data)->ocd_data; + if (type == 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); + } + /* Enable PHY */ + error = phy_get_by_ofw_name(dev, 0, "phy_arasan", &sc->phy); + if (error != 0) { + device_printf(dev, "Could not get phy\n"); + return (ENXIO); + } + error = phy_enable(sc->phy); + if (error != 0) { + device_printf(dev, "Could not enable phy\n"); + return (ENXIO); + } + /* Get syscon */ + node = ofw_bus_get_node(dev); + 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); + } + /* Initialize SDHCI */ + sdhci_init_rk3399(grf, node, freq); + } +#endif + /* Scan all slots. */ slots = sc->num_slots; /* number of slots determined in probe(). */ sc->num_slots = 0;