diff options
author | Patrick Wildt <patrick@cvs.openbsd.org> | 2019-11-29 22:02:17 +0000 |
---|---|---|
committer | Patrick Wildt <patrick@cvs.openbsd.org> | 2019-11-29 22:02:17 +0000 |
commit | cf66b7202fabc8010eff67ee11302d10839df1be (patch) | |
tree | 884243c92e9b250f6dbd979f6b5004ff8a77136d | |
parent | a4b7bd080eb75e947c3e40f8adcdcf7b8a5c9ff3 (diff) |
Improve support for the RK3399's eMMC in sdhc(4). Fix the compatible
check for the quirk that makes sure we don't try to change the voltage
to anything else. Configure the eMMC Core's clock, register ourselves
as clock driver for rkemmcphy(4) to use, and enable the PHY.
Tested by kurt@
ok kettenis@
-rw-r--r-- | sys/dev/fdt/sdhc_fdt.c | 59 |
1 files changed, 54 insertions, 5 deletions
diff --git a/sys/dev/fdt/sdhc_fdt.c b/sys/dev/fdt/sdhc_fdt.c index 6eef5a3d61d..090aaa3580d 100644 --- a/sys/dev/fdt/sdhc_fdt.c +++ b/sys/dev/fdt/sdhc_fdt.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sdhc_fdt.c,v 1.3 2018/08/06 10:52:30 patrick Exp $ */ +/* $OpenBSD: sdhc_fdt.c,v 1.4 2019/11/29 22:02:16 patrick Exp $ */ /* * Copyright (c) 2017 Mark Kettenis * @@ -25,6 +25,7 @@ #include <dev/ofw/openfirm.h> #include <dev/ofw/ofw_clock.h> +#include <dev/ofw/ofw_misc.h> #include <dev/ofw/ofw_pinctrl.h> #include <dev/ofw/fdt.h> @@ -32,6 +33,14 @@ #include <dev/sdmmc/sdhcvar.h> #include <dev/sdmmc/sdmmcvar.h> +/* RK3399 */ +#define GRF_EMMCCORE_CON0_BASECLOCK 0xf000 +#define GRF_EMMCCORE_CON0_BASECLOCK_CLR (0xff << 24) +#define GRF_EMMCCORE_CON0_BASECLOCK_VAL(x) (((x) & 0xff) << 8) +#define GRF_EMMCCORE_CON11 0xf02c +#define GRF_EMMCCORE_CON11_CLOCKMULT_CLR (0xff << 16) +#define GRF_EMMCCORE_CON11_CLOCKMULT_VAL(x) (((x) & 0xff) << 0) + struct sdhc_fdt_softc { struct sdhc_softc sc; bus_space_tag_t sc_iot; @@ -40,6 +49,7 @@ struct sdhc_fdt_softc { void *sc_ih; struct sdhc_host *sc_host; + struct clock_device sc_cd; }; int sdhc_fdt_match(struct device *, void *, void *); @@ -50,6 +60,7 @@ struct cfattach sdhc_fdt_ca = { }; int sdhc_fdt_signal_voltage(struct sdhc_softc *, int); +uint32_t sdhc_fdt_get_frequency(void *, uint32_t *); int sdhc_fdt_match(struct device *parent, void *match, void *aux) @@ -64,6 +75,8 @@ sdhc_fdt_attach(struct device *parent, struct device *self, void *aux) { struct sdhc_fdt_softc *sc = (struct sdhc_fdt_softc *)self; struct fdt_attach_args *faa = aux; + struct regmap *rm = NULL; + uint32_t phandle, freq; if (faa->fa_nreg < 1) { printf(": no registers\n"); @@ -99,17 +112,46 @@ sdhc_fdt_attach(struct device *parent, struct device *self, void *aux) /* * Arasan controller always uses 1.8V and doesn't like an * explicit switch. - * */ - if (OF_is_compatible(faa->fa_node, "arasan,shdc-5,1")) + if (OF_is_compatible(faa->fa_node, "arasan,sdhci-5.1")) sc->sc.sc_signal_voltage = sdhc_fdt_signal_voltage; /* * Rockchip RK3399 PHY doesn't like being powered down at low - * clock speeds. + * clock speeds and needs to be powered up explicitly. */ - if (OF_is_compatible(faa->fa_node, "rockchip,rk3399-sdhci-5.1")) + if (OF_is_compatible(faa->fa_node, "rockchip,rk3399-sdhci-5.1")) { + /* + * The eMMC core's clock multiplier is of no use, so we just + * clear it. Also make sure to set the base clock frequency. + */ + freq = clock_get_frequency(faa->fa_node, "clk_xin"); + freq /= 1000 * 1000; /* in MHz */ + phandle = OF_getpropint(faa->fa_node, + "arasan,soc-ctl-syscon", 0); + if (phandle) + rm = regmap_byphandle(phandle); + if (rm) { + regmap_write_4(rm, GRF_EMMCCORE_CON11, + GRF_EMMCCORE_CON11_CLOCKMULT_CLR | + GRF_EMMCCORE_CON11_CLOCKMULT_VAL(0)); + regmap_write_4(rm, GRF_EMMCCORE_CON0_BASECLOCK, + GRF_EMMCCORE_CON0_BASECLOCK_CLR | + GRF_EMMCCORE_CON0_BASECLOCK_VAL(freq)); + } + /* Provide base clock frequency for the PHY driver. */ + sc->sc_cd.cd_node = faa->fa_node; + sc->sc_cd.cd_cookie = sc; + sc->sc_cd.cd_get_frequency = sdhc_fdt_get_frequency; + clock_register(&sc->sc_cd); + /* + * Enable the PHY. The PHY should be powered on/off in + * the bus_clock function, but it's good enough to just + * enable it here right away and to keep it powered on. + */ + phy_enable(faa->fa_node, "phy_arasan"); sc->sc.sc_flags |= SDHC_F_NOPWR0; + } /* XXX Doesn't work on Rockchip RK3399. */ sc->sc.sc_flags |= SDHC_F_NODDR50; @@ -131,3 +173,10 @@ sdhc_fdt_signal_voltage(struct sdhc_softc *sc, int signal_voltage) return EINVAL; } } + +uint32_t +sdhc_fdt_get_frequency(void *cookie, uint32_t *cells) +{ + struct sdhc_fdt_softc *sc = cookie; + return clock_get_frequency(sc->sc_cd.cd_node, "clk_xin"); +} |