xref: /openbsd-src/sys/dev/fdt/dwmshc.c (revision bdb9ce82483cfe07a1aff08d728c26115e111ce7)
1*bdb9ce82Spatrick /*	$OpenBSD: dwmshc.c,v 1.8 2024/07/15 09:56:30 patrick Exp $ */
27d57b1b5Sdlg 
37d57b1b5Sdlg /*
47d57b1b5Sdlg  * Copyright (c) 2023 David Gwynne <dlg@openbsd.org>
57d57b1b5Sdlg  *
67d57b1b5Sdlg  * Permission to use, copy, modify, and distribute this software for any
77d57b1b5Sdlg  * purpose with or without fee is hereby granted, provided that the above
87d57b1b5Sdlg  * copyright notice and this permission notice appear in all copies.
97d57b1b5Sdlg  *
107d57b1b5Sdlg  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
117d57b1b5Sdlg  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
127d57b1b5Sdlg  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
137d57b1b5Sdlg  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
147d57b1b5Sdlg  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
157d57b1b5Sdlg  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
167d57b1b5Sdlg  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
177d57b1b5Sdlg  */
187d57b1b5Sdlg 
197d57b1b5Sdlg #include <sys/param.h>
207d57b1b5Sdlg #include <sys/malloc.h>
217d57b1b5Sdlg #include <sys/systm.h>
227d57b1b5Sdlg 
237d57b1b5Sdlg #include <machine/bus.h>
247d57b1b5Sdlg #include <machine/fdt.h>
257d57b1b5Sdlg #include <machine/intr.h>
267d57b1b5Sdlg 
277d57b1b5Sdlg #include <dev/ofw/openfirm.h>
287d57b1b5Sdlg #include <dev/ofw/ofw_clock.h>
297d57b1b5Sdlg #include <dev/ofw/ofw_gpio.h>
307d57b1b5Sdlg #include <dev/ofw/ofw_misc.h>
317d57b1b5Sdlg #include <dev/ofw/ofw_pinctrl.h>
327d57b1b5Sdlg #include <dev/ofw/ofw_regulator.h>
337d57b1b5Sdlg #include <dev/ofw/fdt.h>
347d57b1b5Sdlg 
357d57b1b5Sdlg #include <dev/sdmmc/sdhcreg.h>
367d57b1b5Sdlg #include <dev/sdmmc/sdhcvar.h>
377d57b1b5Sdlg #include <dev/sdmmc/sdmmcvar.h>
387d57b1b5Sdlg 
397d57b1b5Sdlg #define EMMC_VER_ID			0x500
407d57b1b5Sdlg #define EMMC_VER_TYPE			0x504
417d57b1b5Sdlg #define EMMC_HOST_CTRL3			0x508 /* B */
427d57b1b5Sdlg #define  EMMC_HOST_CTRL3_CMD_CONFLICT_CHECK	(1U << 0)
437d57b1b5Sdlg #define  EMMC_HOST_CTRL3_SW_CG_DIS		(1U << 4)
447d57b1b5Sdlg #define EMMC_EMMC_CTRL			0x52c /* HW */
457d57b1b5Sdlg #define  EMMC_EMMC_CTRL_CARD_IS_EMMC		(1U << 0)
467d57b1b5Sdlg #define  EMMC_EMMC_CTRL_DISABLE_DATA_CRC_CHK	(1U << 1)
477d57b1b5Sdlg #define  EMMC_EMMC_CTRL_EMMC_RST_N		(1U << 2)
487d57b1b5Sdlg #define  EMMC_EMMC_CTRL_EMMC_RST_N_OE		(1U << 3)
497d57b1b5Sdlg #define  EMMC_EMMC_CTRL_ENH_STROBE_ENABLE	(1U << 8)
507d57b1b5Sdlg #define  EMMC_EMMC_CTRL_CQE_ALGO_SEL		(1U << 9)
517d57b1b5Sdlg #define  EMMC_EMMC_CTRL_CQE_PREFETCH_DISABLE	(1U << 10)
527d57b1b5Sdlg #define EMMC_BOOT_CTRL			0x52e /* HW */
537d57b1b5Sdlg #define  EMMC_BOOT_CTRL_MAN_BOOT_EN		(1U << 0)
547d57b1b5Sdlg #define  EMMC_BOOT_CTRL_VALIDATE_BOOT		(1U << 1)
557d57b1b5Sdlg #define  EMMC_BOOT_CTRL_BOOT_ACK_ENABLE		(1U << 8)
567d57b1b5Sdlg #define  EMMC_BOOT_CTRL_BOOT_TOUT_CNT_SHIFT	12
577d57b1b5Sdlg #define  EMMC_BOOT_CTRL_BOOT_TOUT_CNT_MASK	0xf
587d57b1b5Sdlg #define EMMC_AT_CTRL			0x540
597d57b1b5Sdlg #define  EMMC_AT_CTRL_SWIN_TH_EN		(1U << 2)
607d57b1b5Sdlg #define  EMMC_AT_CTRL_RPT_TUNE_ERR		(1U << 3)
617d57b1b5Sdlg #define  EMMC_AT_CTRL_SW_TUNE_EN		(1U << 4)
627d57b1b5Sdlg #define  EMMC_AT_CTRL_TUNE_CLK_STOP_EN		(1U << 16)
637d57b1b5Sdlg #define  EMMC_AT_CTRL_PRE_CHANGE_DLY_MASK	(0x3 << 17)
647d57b1b5Sdlg #define  EMMC_AT_CTRL_PRE_CHANGE_DLY_LT1	(0x0 << 17)
657d57b1b5Sdlg #define  EMMC_AT_CTRL_PRE_CHANGE_DLY_LT2	(0x1 << 17)
667d57b1b5Sdlg #define  EMMC_AT_CTRL_PRE_CHANGE_DLY_LT3	(0x2 << 17)
677d57b1b5Sdlg #define  EMMC_AT_CTRL_PRE_CHANGE_DLY_LT4	(0x3 << 17)
687d57b1b5Sdlg #define  EMMC_AT_CTRL_POST_CHANGE_DLY_MASK	(0x3 << 19)
697d57b1b5Sdlg #define  EMMC_AT_CTRL_POST_CHANGE_DLY_LT1	(0x0 << 19)
707d57b1b5Sdlg #define  EMMC_AT_CTRL_POST_CHANGE_DLY_LT2	(0x1 << 19)
717d57b1b5Sdlg #define  EMMC_AT_CTRL_POST_CHANGE_DLY_LT3	(0x2 << 19)
727d57b1b5Sdlg #define  EMMC_AT_CTRL_POST_CHANGE_DLY_LT4	(0x3 << 19)
737d57b1b5Sdlg #define EMMC_AT_STAT			0x544
747d57b1b5Sdlg #define  EMMC_AT_STAT_CENTER_PH_CODE_SHIFT	0
757d57b1b5Sdlg #define  EMMC_AT_STAT_CENTER_PH_CODE_MASK	0xff
767d57b1b5Sdlg #define  EMMC_AT_STAT_R_EDGE_PH_CODE_SHIFT	8
777d57b1b5Sdlg #define  EMMC_AT_STAT_R_EDGE_PH_CODE_MASK	0xff
787d57b1b5Sdlg #define  EMMC_AT_STAT_L_EDGE_PH_CODE_SHIFT	16
797d57b1b5Sdlg #define  EMMC_AT_STAT_L_EDGE_PH_CODE_MASK	0xff
807d57b1b5Sdlg #define EMMC_DLL_CTRL			0x800
817d57b1b5Sdlg #define  EMMC_DLL_CTRL_DLL_START		(1U << 0)
827d57b1b5Sdlg #define  EMMC_DLL_CTRL_DLL_SRST			(1U << 1)
837d57b1b5Sdlg #define  EMMC_DLL_CTRL_DLL_INCREMENT_SHIFT	8
847d57b1b5Sdlg #define  EMMC_DLL_CTRL_DLL_INCREMENT_MASK	0xff
857d57b1b5Sdlg #define  EMMC_DLL_CTRL_DLL_START_POINT_SHIFT	16
867d57b1b5Sdlg #define  EMMC_DLL_CTRL_DLL_START_POINT_MASK	0xff
877d57b1b5Sdlg #define  EMMC_DLL_CTRL_DLL_BYPASS_MODE		(1U << 24)
887d57b1b5Sdlg #define EMMC_DLL_RXCLK			0x804
897d57b1b5Sdlg #define  EMMC_DLL_RXCLK_RX_TAP_NUM_SHIFT	0
907d57b1b5Sdlg #define  EMMC_DLL_RXCLK_RX_TAP_NUM_MASK		0x1f
917d57b1b5Sdlg #define  EMMC_DLL_RXCLK_RX_TAP_VALUE_SHIFT	8
927d57b1b5Sdlg #define  EMMC_DLL_RXCLK_RX_TAP_VALUE_MASK	0xff
937d57b1b5Sdlg #define  EMMC_DLL_RXCLK_RX_DELAY_NUM_SHIFT	16
947d57b1b5Sdlg #define  EMMC_DLL_RXCLK_RX_DELAY_NUM_MASK	0xff
957d57b1b5Sdlg #define  EMMC_DLL_RXCLK_RX_TAP_NUM_SEL		(1U << 24)
967d57b1b5Sdlg #define  EMMC_DLL_RXCLK_RX_TAP_VALUE_SEL	(1U << 25)
977d57b1b5Sdlg #define  EMMC_DLL_RXCLK_RX_DELAY_NUM_SEL	(1U << 26)
987d57b1b5Sdlg #define  EMMC_DLL_RXCLK_RX_CLK_OUT_SEL		(1U << 27)
997d57b1b5Sdlg #define  EMMC_DLL_RXCLK_RX_CLK_CHANGE_WINDOW	(1U << 28)
1007d57b1b5Sdlg #define  EMMC_DLL_RXCLK_RX_CLK_SRC_SEL		(1U << 29)
1012779d271Skettenis #define EMMC_DLL_TXCLK			0x808
1027d57b1b5Sdlg #define  EMMC_DLL_TXCLK_TX_TAP_NUM_SHIFT	0
1037d57b1b5Sdlg #define  EMMC_DLL_TXCLK_TX_TAP_NUM_MASK		0x1f
104*bdb9ce82Spatrick #define  EMMC_DLL_TXCLK_TX_TAP_NUM_90_DEG	0x8
105*bdb9ce82Spatrick #define  EMMC_DLL_TXCLK_TX_TAP_NUM_DEFAULT	0x10
1067d57b1b5Sdlg #define  EMMC_DLL_TXCLK_TX_TAP_VALUE_SHIFT	8
1077d57b1b5Sdlg #define  EMMC_DLL_TXCLK_TX_TAP_VALUE_MASK	0xff
1087d57b1b5Sdlg #define  EMMC_DLL_TXCLK_TX_DELAY_SHIFT		16
1097d57b1b5Sdlg #define  EMMC_DLL_TXCLK_TX_DELAY_MASK		0xff
1107d57b1b5Sdlg #define  EMMC_DLL_TXCLK_TX_TAP_NUM_SEL		(1U << 24)
1117d57b1b5Sdlg #define  EMMC_DLL_TXCLK_TX_TAP_VALUE_SEL	(1U << 25)
1127d57b1b5Sdlg #define  EMMC_DLL_TXCLK_TX_DELAY_SEL		(1U << 26)
1137d57b1b5Sdlg #define  EMMC_DLL_TXCLK_TX_CLK_OUT_SEL		(1U << 27)
1147d57b1b5Sdlg #define EMMC_DLL_STRBIN			0x80c
1157d57b1b5Sdlg #define  EMMC_DLL_STRBIN_TAP_NUM_SHIFT		0
1167d57b1b5Sdlg #define  EMMC_DLL_STRBIN_TAP_NUM_MASK		0x1f
117*bdb9ce82Spatrick #define  EMMC_DLL_STRBIN_TAP_NUM_90_DEG		0x8
1187d57b1b5Sdlg #define  EMMC_DLL_STRBIN_TAP_VALUE_SHIFT	8
1197d57b1b5Sdlg #define  EMMC_DLL_STRBIN_TAP_VALUE_MASK		0xff
1207d57b1b5Sdlg #define  EMMC_DLL_STRBIN_DELAY_NUM_SHIFT	16
1217d57b1b5Sdlg #define  EMMC_DLL_STRBIN_DELAY_NUM_MASK		0xff
1227d57b1b5Sdlg #define  EMMC_DLL_STRBIN_DELAY_NUM_DEFAULT	0x16
1237d57b1b5Sdlg #define  EMMC_DLL_STRBIN_TAP_NUM_SEL		(1U << 24)
1247d57b1b5Sdlg #define  EMMC_DLL_STRBIN_TAP_VALUE_SEL		(1U << 25)
1257d57b1b5Sdlg #define  EMMC_DLL_STRBIN_DELAY_NUM_SEL		(1U << 26)
1267d57b1b5Sdlg #define  EMMC_DLL_STRBIN_DELAY_ENA		(1U << 27)
127*bdb9ce82Spatrick #define EMMC_DLL_CMDOUT			0x810
128*bdb9ce82Spatrick #define  EMMC_DLL_CMDOUT_TAP_NUM_SHIFT		0
129*bdb9ce82Spatrick #define  EMMC_DLL_CMDOUT_TAP_NUM_MASK		0x1f
130*bdb9ce82Spatrick #define  EMMC_DLL_CMDOUT_TAP_NUM_90_DEG	0x8
131*bdb9ce82Spatrick #define  EMMC_DLL_CMDOUT_TAP_VALUE_SHIFT	8
132*bdb9ce82Spatrick #define  EMMC_DLL_CMDOUT_TAP_VALUE_MASK		0xff
133*bdb9ce82Spatrick #define  EMMC_DLL_CMDOUT_DELAY_NUM_SHIFT	16
134*bdb9ce82Spatrick #define  EMMC_DLL_CMDOUT_DELAY_NUM_MASK		0xff
135*bdb9ce82Spatrick #define  EMMC_DLL_CMDOUT_TAP_NUM_SEL		(1U << 24)
136*bdb9ce82Spatrick #define  EMMC_DLL_CMDOUT_TAP_VALUE_SEL		(1U << 25)
137*bdb9ce82Spatrick #define  EMMC_DLL_CMDOUT_DELAY_NUM_SEL		(1U << 26)
138*bdb9ce82Spatrick #define  EMMC_DLL_CMDOUT_DELAY_ENA		(1U << 27)
139*bdb9ce82Spatrick #define  EMMC_DLL_CMDOUT_SRC_SEL		(1U << 28)
140*bdb9ce82Spatrick #define  EMMC_DLL_CMDOUT_EN_SRC_SEL		(1U << 29)
1417d57b1b5Sdlg #define EMMC_DLL_STATUS0		0x840
1427d57b1b5Sdlg #define  EMMC_DLL_STATUS0_DLL_LOCK_VALUE_SHIFT	0
1437d57b1b5Sdlg #define  EMMC_DLL_STATUS0_DLL_LOCK_VALUE_MASK	0xff
1447d57b1b5Sdlg #define  EMMC_DLL_STATUS0_DLL_LOCK		(1U << 8)
1457d57b1b5Sdlg #define  EMMC_DLL_STATUS0_DLL_LOCK_TIMEOUT	(1U << 9)
1467d57b1b5Sdlg #define EMMC_DLL_STATUS1		0x844
1477d57b1b5Sdlg #define  EMMC_DLL_STATUS1_DLL_TXCLK_DELAY_VALUE_SHIFT \
1487d57b1b5Sdlg 						0
1497d57b1b5Sdlg #define  EMMC_DLL_STATUS1_DLL_TXCLK_DELAY_VALUE_MASK \
1507d57b1b5Sdlg 						0xff
1517d57b1b5Sdlg #define  EMMC_DLL_STATUS1_DLL_RXCLK_DELAY_VALUE_SHIFT \
1527d57b1b5Sdlg 						8
1537d57b1b5Sdlg #define  EMMC_DLL_STATUS1_DLL_RXCLK_DELAY_VALUE_MASK \
1547d57b1b5Sdlg 						0xff
1557d57b1b5Sdlg #define  EMMC_DLL_STATUS1_DLL_STRBIN_DELAY_VALUE_SHIFT \
1567d57b1b5Sdlg 						16
1577d57b1b5Sdlg #define  EMMC_DLL_STATUS1_DLL_STRBIN_DELAY_VALUE_MASK \
1587d57b1b5Sdlg 						0xff
1597d57b1b5Sdlg 
1607d57b1b5Sdlg struct dwmshc_softc {
1617d57b1b5Sdlg 	struct sdhc_softc	 sc_sdhc;
1627d57b1b5Sdlg 
1637d57b1b5Sdlg 	int			 sc_node;
1647d57b1b5Sdlg 
1657d57b1b5Sdlg 	bus_space_tag_t		 sc_iot;
1667d57b1b5Sdlg 	bus_space_handle_t	 sc_ioh;
1677d57b1b5Sdlg 	bus_size_t		 sc_ios;
1687d57b1b5Sdlg 	bus_dma_tag_t		 sc_dmat;
1697d57b1b5Sdlg 	void			*sc_ih;
1707d57b1b5Sdlg 
1717d57b1b5Sdlg 	struct sdhc_host	*sc_host;
1727d57b1b5Sdlg };
1737d57b1b5Sdlg 
1747d57b1b5Sdlg static int		 dwmshc_match(struct device *, void *, void *);
1757d57b1b5Sdlg static void		 dwmshc_attach(struct device *, struct device *,
1767d57b1b5Sdlg 			     void *);
1777d57b1b5Sdlg 
1787d57b1b5Sdlg static inline void	 dwmshc_wr1(struct dwmshc_softc *,
1797d57b1b5Sdlg 			     bus_size_t, uint8_t);
1807d57b1b5Sdlg static inline void	 dwmshc_wr4(struct dwmshc_softc *,
1817d57b1b5Sdlg 			     bus_size_t, uint32_t);
1827d57b1b5Sdlg static inline uint32_t	 dwmshc_rd4(struct dwmshc_softc *, bus_size_t);
1837d57b1b5Sdlg 
1847d57b1b5Sdlg static void		 dwmshc_clock_pre(struct sdhc_softc *, int, int);
1857d57b1b5Sdlg static void		 dwmshc_clock_post(struct sdhc_softc *, int, int);
1867d57b1b5Sdlg static int		 dwmshc_non_removable(struct sdhc_softc *);
1877d57b1b5Sdlg 
1887d57b1b5Sdlg const struct cfattach dwmshc_ca = {
1897d57b1b5Sdlg 	sizeof(struct dwmshc_softc), dwmshc_match, dwmshc_attach
1907d57b1b5Sdlg };
1917d57b1b5Sdlg 
1927d57b1b5Sdlg struct cfdriver dwmshc_cd = {
1937d57b1b5Sdlg 	NULL, "dwmshc", DV_DULL
1947d57b1b5Sdlg };
1957d57b1b5Sdlg 
1967d57b1b5Sdlg int
dwmshc_match(struct device * parent,void * match,void * aux)1977d57b1b5Sdlg dwmshc_match(struct device *parent, void *match, void *aux)
1987d57b1b5Sdlg {
1997d57b1b5Sdlg 	struct fdt_attach_args *faa = aux;
2007d57b1b5Sdlg 
201*bdb9ce82Spatrick 	return (OF_is_compatible(faa->fa_node, "rockchip,rk3568-dwcmshc") ||
202*bdb9ce82Spatrick 	    OF_is_compatible(faa->fa_node, "rockchip,rk3588-dwcmshc"));
2037d57b1b5Sdlg }
2047d57b1b5Sdlg static void
dwmshc_attach(struct device * parent,struct device * self,void * aux)2057d57b1b5Sdlg dwmshc_attach(struct device *parent, struct device *self, void *aux)
2067d57b1b5Sdlg {
2077d57b1b5Sdlg 	struct dwmshc_softc *sc = (struct dwmshc_softc *)self;
2087d57b1b5Sdlg 	struct sdhc_softc *sdhc = &sc->sc_sdhc;
2097d57b1b5Sdlg 	struct fdt_attach_args *faa = aux;
2107d57b1b5Sdlg 	uint64_t capmask = 0;
2117d57b1b5Sdlg 	uint16_t capset = 0;
2127d57b1b5Sdlg 	int bus_width;
2137d57b1b5Sdlg 	uint32_t freq;
2147d57b1b5Sdlg 
2157d57b1b5Sdlg 	sc->sc_node = faa->fa_node;
2167d57b1b5Sdlg 	sc->sc_iot = faa->fa_iot;
2177d57b1b5Sdlg 	sc->sc_ios = faa->fa_reg[0].size;
2187d57b1b5Sdlg 	sc->sc_dmat = faa->fa_dmat;
2197d57b1b5Sdlg 
2207d57b1b5Sdlg 	if (faa->fa_nreg < 1) {
2217d57b1b5Sdlg 		printf(": no registers\n");
2227d57b1b5Sdlg 		return;
2237d57b1b5Sdlg 	}
2247d57b1b5Sdlg 
2257d57b1b5Sdlg 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
2267d57b1b5Sdlg 	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
2277d57b1b5Sdlg 		printf(": can't map registers\n");
2287d57b1b5Sdlg 		return;
2297d57b1b5Sdlg 	}
2307d57b1b5Sdlg 
2317d57b1b5Sdlg 	pinctrl_byname(sc->sc_node, "default");
2327d57b1b5Sdlg 
2337d57b1b5Sdlg 	clock_set_assigned(sc->sc_node);
2347d57b1b5Sdlg 	clock_enable_all(sc->sc_node);
2357d57b1b5Sdlg 	reset_deassert_all(sc->sc_node);
2367d57b1b5Sdlg 
2377d57b1b5Sdlg 	sc->sc_ih = fdt_intr_establish(faa->fa_node, IPL_BIO,
2387d57b1b5Sdlg 	    sdhc_intr, sdhc, DEVNAME(sdhc));
2397d57b1b5Sdlg 	if (sc->sc_ih == NULL) {
2407d57b1b5Sdlg 		printf(": can't establish interrupt\n");
2417d57b1b5Sdlg 		return;
2427d57b1b5Sdlg 	}
2437d57b1b5Sdlg 
2447d57b1b5Sdlg 	printf("\n");
2457d57b1b5Sdlg 
2467d57b1b5Sdlg 	/* Disable Command Conflict Check */
2477d57b1b5Sdlg 	dwmshc_wr1(sc, EMMC_HOST_CTRL3, 0);
2487d57b1b5Sdlg 
2497d57b1b5Sdlg 	sdhc->sc_host = &sc->sc_host;
2507d57b1b5Sdlg 	sdhc->sc_dmat = faa->fa_dmat;
251834ff46cSdlg 	sdhc->sc_dma_boundary = 128 * 1024 * 1024;
2527d57b1b5Sdlg 
2537d57b1b5Sdlg 	sdhc->sc_bus_clock_pre = dwmshc_clock_pre;
2547d57b1b5Sdlg 	sdhc->sc_bus_clock_post = dwmshc_clock_post;
2557d57b1b5Sdlg 
256fff34f16Sdlg 	if (OF_getpropbool(sc->sc_node, "non-removable")) {
257fff34f16Sdlg 		SET(sdhc->sc_flags, SDHC_F_NONREMOVABLE);
2587d57b1b5Sdlg 		sdhc->sc_card_detect = dwmshc_non_removable;
259fff34f16Sdlg 	}
2607d57b1b5Sdlg 
2617d57b1b5Sdlg 	bus_width = OF_getpropint(faa->fa_node, "bus-width", 1);
2627d57b1b5Sdlg 	if (bus_width < 8)
2637d57b1b5Sdlg 		SET(capmask, SDHC_8BIT_MODE_SUPP);
2647d57b1b5Sdlg 
2657d57b1b5Sdlg 	freq = clock_get_frequency(faa->fa_node, "block");
2667d57b1b5Sdlg 	sdhc->sc_clkbase = freq / 1000;
2677d57b1b5Sdlg 
2687d57b1b5Sdlg 	SET(sdhc->sc_flags, SDHC_F_NOPWR0);
2697d57b1b5Sdlg 	SET(capmask, (uint64_t)SDHC_DDR50_SUPP << 32);
2707d57b1b5Sdlg 
2717d57b1b5Sdlg 	sdhc_host_found(sdhc, sc->sc_iot, sc->sc_ioh, sc->sc_ios, 1,
2727d57b1b5Sdlg 	    capmask, capset);
2737d57b1b5Sdlg }
2747d57b1b5Sdlg 
2757d57b1b5Sdlg static void
dwmshc_clock_pre(struct sdhc_softc * sdhc,int freq,int timing)2767d57b1b5Sdlg dwmshc_clock_pre(struct sdhc_softc *sdhc, int freq, int timing)
2777d57b1b5Sdlg {
2787d57b1b5Sdlg #if 0
2797d57b1b5Sdlg 	struct dwmshc_softc *sc = (struct dwmshc_softc *)sdhc;
2807d57b1b5Sdlg 
2817d57b1b5Sdlg 	/*
2827d57b1b5Sdlg 	 * before switching to hs400es the driver needs to enable
2837d57b1b5Sdlg 	 * enhanced strobe. i think this is the right place to do
2847d57b1b5Sdlg 	 * that.
2857d57b1b5Sdlg 	 */
2867d57b1b5Sdlg 	if (timing == hs400es) {
2877d57b1b5Sdlg 		dwmshc_wr4(sc, EMMC_DLL_STRBIN, EMMC_DLL_STRBIN_DELAY_ENA |
2887d57b1b5Sdlg 		    EMMC_DLL_STRBIN_DELAY_NUM_SEL |
2897d57b1b5Sdlg 		    (EMMC_DLL_STRBIN_DELAY_NUM_DEFAULT <<
2907d57b1b5Sdlg 		     EMMC_DLL_STRBIN_DELAY_NUM_SHIFT));
2917d57b1b5Sdlg 	}
2927d57b1b5Sdlg #endif
2937d57b1b5Sdlg }
2947d57b1b5Sdlg 
2957d57b1b5Sdlg static int
dwmshc_dll_wait(struct dwmshc_softc * sc)2967d57b1b5Sdlg dwmshc_dll_wait(struct dwmshc_softc *sc)
2977d57b1b5Sdlg {
2987d57b1b5Sdlg 	uint32_t status0;
2997d57b1b5Sdlg 	int i;
3007d57b1b5Sdlg 
3017d57b1b5Sdlg 	for (i = 0; i < 500 * 1000; i++) {
3027d57b1b5Sdlg 		delay(1);
3037d57b1b5Sdlg 
3047d57b1b5Sdlg 		status0 = dwmshc_rd4(sc, EMMC_DLL_STATUS0);
3057d57b1b5Sdlg 		if (ISSET(status0, EMMC_DLL_STATUS0_DLL_LOCK)) {
3067d57b1b5Sdlg 			if (ISSET(status0, EMMC_DLL_STATUS0_DLL_LOCK_TIMEOUT)) {
3077d57b1b5Sdlg 				printf("%s: lock timeout\n",
3087d57b1b5Sdlg 				    DEVNAME(&sc->sc_sdhc));
3097d57b1b5Sdlg 				return (EIO);
3107d57b1b5Sdlg 			}
3117d57b1b5Sdlg 			return (0);
3127d57b1b5Sdlg 		}
3137d57b1b5Sdlg 	}
3147d57b1b5Sdlg 
3157d57b1b5Sdlg 	printf("%s: poll timeout\n", DEVNAME(&sc->sc_sdhc));
3167d57b1b5Sdlg 	return (ETIMEDOUT);
3177d57b1b5Sdlg }
3187d57b1b5Sdlg 
3197d57b1b5Sdlg static void
dwmshc_clock_post(struct sdhc_softc * sdhc,int freq,int timing)3207d57b1b5Sdlg dwmshc_clock_post(struct sdhc_softc *sdhc, int freq, int timing)
3217d57b1b5Sdlg {
3227d57b1b5Sdlg 	struct dwmshc_softc *sc = (struct dwmshc_softc *)sdhc;
323*bdb9ce82Spatrick 	uint32_t txclk_tapnum = EMMC_DLL_TXCLK_TX_TAP_NUM_DEFAULT;
3247d57b1b5Sdlg 
3257d57b1b5Sdlg 	clock_set_frequency(sc->sc_node, 0, freq * 1000);
3267d57b1b5Sdlg 
3277d57b1b5Sdlg 	if (timing == SDMMC_TIMING_LEGACY) { /* disable dll */
3287d57b1b5Sdlg 		/*
3297d57b1b5Sdlg                  * the bypass and start bits need to be set if dll
3307d57b1b5Sdlg 		 * is not locked.
3317d57b1b5Sdlg 		 */
3327d57b1b5Sdlg 		dwmshc_wr4(sc, EMMC_DLL_CTRL,
3337d57b1b5Sdlg 		    EMMC_DLL_CTRL_DLL_START | EMMC_DLL_CTRL_DLL_BYPASS_MODE);
3347d57b1b5Sdlg 		dwmshc_wr4(sc, EMMC_DLL_RXCLK, 0);
3357d57b1b5Sdlg 		dwmshc_wr4(sc, EMMC_DLL_TXCLK, 0);
3367d57b1b5Sdlg 		dwmshc_wr4(sc, EMMC_DLL_STRBIN, 0);
3377d57b1b5Sdlg 		return;
3387d57b1b5Sdlg 	}
3397d57b1b5Sdlg 
3407d57b1b5Sdlg 	dwmshc_wr4(sc, EMMC_DLL_CTRL, EMMC_DLL_CTRL_DLL_SRST);
3417d57b1b5Sdlg 	delay(1);
3427d57b1b5Sdlg 	dwmshc_wr4(sc, EMMC_DLL_CTRL, 0);
3437d57b1b5Sdlg 
344*bdb9ce82Spatrick 	if (OF_is_compatible(sc->sc_node, "rockchip,rk3568-dwcmshc"))
3457d57b1b5Sdlg 		dwmshc_wr4(sc, EMMC_DLL_RXCLK, EMMC_DLL_RXCLK_RX_CLK_OUT_SEL |
346*bdb9ce82Spatrick 		    EMMC_DLL_RXCLK_RX_CLK_SRC_SEL);
347*bdb9ce82Spatrick 	else
348*bdb9ce82Spatrick 		dwmshc_wr4(sc, EMMC_DLL_RXCLK, EMMC_DLL_RXCLK_RX_CLK_OUT_SEL);
3497d57b1b5Sdlg 	dwmshc_wr4(sc, EMMC_DLL_CTRL, EMMC_DLL_CTRL_DLL_START |
3507d57b1b5Sdlg 	    0x5 << EMMC_DLL_CTRL_DLL_START_POINT_SHIFT |
3517d57b1b5Sdlg 	    0x2 << EMMC_DLL_CTRL_DLL_INCREMENT_SHIFT);
3527d57b1b5Sdlg 
3537d57b1b5Sdlg 	if (dwmshc_dll_wait(sc) != 0)
3547d57b1b5Sdlg 		return;
3557d57b1b5Sdlg 
3567d57b1b5Sdlg 	dwmshc_wr4(sc, EMMC_AT_CTRL, EMMC_AT_CTRL_TUNE_CLK_STOP_EN |
3577d57b1b5Sdlg 	    EMMC_AT_CTRL_PRE_CHANGE_DLY_LT4 |
3587d57b1b5Sdlg 	    EMMC_AT_CTRL_POST_CHANGE_DLY_LT4);
3597d57b1b5Sdlg 
3607d57b1b5Sdlg 	if (timing >= SDMMC_TIMING_MMC_HS200) {
3617d57b1b5Sdlg 		txclk_tapnum = OF_getpropint(sc->sc_node,
3627d57b1b5Sdlg 		    "rockchip,txclk-tapnum", txclk_tapnum);
3637d57b1b5Sdlg 
364*bdb9ce82Spatrick #ifdef notyet
365*bdb9ce82Spatrick 		if (OF_is_compatible(sc->sc_node, "rockchip,rk3588-dwcmshc") &&
366*bdb9ce82Spatrick 		    timing == SDMMC_TIMING_MMC_HS400) {
367*bdb9ce82Spatrick 			txclk_tapnum = EMMC_DLL_TXCLK_TX_TAP_NUM_90_DEG;
368*bdb9ce82Spatrick 			dwmshc_wr4(sc, EMMC_DLL_CMDOUT,
369*bdb9ce82Spatrick 			    EMMC_DLL_CMDOUT_TAP_NUM_90_DEG |
370*bdb9ce82Spatrick 			    EMMC_DLL_CMDOUT_TAP_NUM_SEL |
371*bdb9ce82Spatrick 			    EMMC_DLL_CMDOUT_DELAY_ENA |
372*bdb9ce82Spatrick 			    EMMC_DLL_CMDOUT_SRC_SEL |
373*bdb9ce82Spatrick 			    EMMC_DLL_CMDOUT_EN_SRC_SEL);
374*bdb9ce82Spatrick 		}
375*bdb9ce82Spatrick #endif
3767d57b1b5Sdlg 	}
3777d57b1b5Sdlg 
3787d57b1b5Sdlg 	dwmshc_wr4(sc, EMMC_DLL_TXCLK, EMMC_DLL_TXCLK_TX_CLK_OUT_SEL |
3797d57b1b5Sdlg 	    EMMC_DLL_TXCLK_TX_TAP_NUM_SEL |
3807d57b1b5Sdlg 	    txclk_tapnum << EMMC_DLL_TXCLK_TX_TAP_NUM_SHIFT);
3817d57b1b5Sdlg 	dwmshc_wr4(sc, EMMC_DLL_STRBIN, EMMC_DLL_STRBIN_DELAY_ENA |
3827d57b1b5Sdlg 	    EMMC_DLL_STRBIN_TAP_NUM_SEL |
383*bdb9ce82Spatrick 	    (EMMC_DLL_STRBIN_TAP_NUM_90_DEG <<
3847d57b1b5Sdlg 	     EMMC_DLL_STRBIN_TAP_NUM_SHIFT));
3857d57b1b5Sdlg }
3867d57b1b5Sdlg 
3877d57b1b5Sdlg static int
dwmshc_non_removable(struct sdhc_softc * sdhc)3887d57b1b5Sdlg dwmshc_non_removable(struct sdhc_softc *sdhc)
3897d57b1b5Sdlg {
3907d57b1b5Sdlg 	return (1);
3917d57b1b5Sdlg }
3927d57b1b5Sdlg 
3937d57b1b5Sdlg static inline void
dwmshc_wr1(struct dwmshc_softc * sc,bus_size_t off,uint8_t v)3947d57b1b5Sdlg dwmshc_wr1(struct dwmshc_softc *sc, bus_size_t off, uint8_t v)
3957d57b1b5Sdlg {
3967d57b1b5Sdlg 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, off, v);
3977d57b1b5Sdlg }
3987d57b1b5Sdlg 
3997d57b1b5Sdlg static inline void
dwmshc_wr4(struct dwmshc_softc * sc,bus_size_t off,uint32_t v)4007d57b1b5Sdlg dwmshc_wr4(struct dwmshc_softc *sc, bus_size_t off, uint32_t v)
4017d57b1b5Sdlg {
4027d57b1b5Sdlg 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, off, v);
4037d57b1b5Sdlg }
4047d57b1b5Sdlg 
4057d57b1b5Sdlg static inline uint32_t
dwmshc_rd4(struct dwmshc_softc * sc,bus_size_t off)4067d57b1b5Sdlg dwmshc_rd4(struct dwmshc_softc *sc, bus_size_t off)
4077d57b1b5Sdlg {
4087d57b1b5Sdlg 	return (bus_space_read_4(sc->sc_iot, sc->sc_ioh, off));
4097d57b1b5Sdlg }
410