xref: /openbsd-src/sys/dev/fdt/sdhc_fdt.c (revision 99fd087599a8791921855f21bd7e36130f39aadc)
1 /*	$OpenBSD: sdhc_fdt.c,v 1.4 2019/11/29 22:02:16 patrick Exp $	*/
2 /*
3  * Copyright (c) 2017 Mark Kettenis
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/param.h>
19 #include <sys/malloc.h>
20 #include <sys/systm.h>
21 
22 #include <machine/bus.h>
23 #include <machine/fdt.h>
24 #include <machine/intr.h>
25 
26 #include <dev/ofw/openfirm.h>
27 #include <dev/ofw/ofw_clock.h>
28 #include <dev/ofw/ofw_misc.h>
29 #include <dev/ofw/ofw_pinctrl.h>
30 #include <dev/ofw/fdt.h>
31 
32 #include <dev/sdmmc/sdhcreg.h>
33 #include <dev/sdmmc/sdhcvar.h>
34 #include <dev/sdmmc/sdmmcvar.h>
35 
36 /* RK3399 */
37 #define GRF_EMMCCORE_CON0_BASECLOCK		0xf000
38 #define  GRF_EMMCCORE_CON0_BASECLOCK_CLR		(0xff << 24)
39 #define  GRF_EMMCCORE_CON0_BASECLOCK_VAL(x)		(((x) & 0xff) << 8)
40 #define GRF_EMMCCORE_CON11			0xf02c
41 #define  GRF_EMMCCORE_CON11_CLOCKMULT_CLR		(0xff << 16)
42 #define  GRF_EMMCCORE_CON11_CLOCKMULT_VAL(x)		(((x) & 0xff) << 0)
43 
44 struct sdhc_fdt_softc {
45 	struct sdhc_softc 	sc;
46 	bus_space_tag_t		sc_iot;
47 	bus_space_handle_t	sc_ioh;
48 	bus_size_t		sc_size;
49 	void			*sc_ih;
50 
51 	struct sdhc_host 	*sc_host;
52 	struct clock_device	sc_cd;
53 };
54 
55 int	sdhc_fdt_match(struct device *, void *, void *);
56 void	sdhc_fdt_attach(struct device *, struct device *, void *);
57 
58 struct cfattach sdhc_fdt_ca = {
59 	sizeof(struct sdhc_fdt_softc), sdhc_fdt_match, sdhc_fdt_attach
60 };
61 
62 int	sdhc_fdt_signal_voltage(struct sdhc_softc *, int);
63 uint32_t sdhc_fdt_get_frequency(void *, uint32_t *);
64 
65 int
66 sdhc_fdt_match(struct device *parent, void *match, void *aux)
67 {
68 	struct fdt_attach_args *faa = aux;
69 
70 	return OF_is_compatible(faa->fa_node, "arasan,sdhci-5.1");
71 }
72 
73 void
74 sdhc_fdt_attach(struct device *parent, struct device *self, void *aux)
75 {
76 	struct sdhc_fdt_softc *sc = (struct sdhc_fdt_softc *)self;
77 	struct fdt_attach_args *faa = aux;
78 	struct regmap *rm = NULL;
79 	uint32_t phandle, freq;
80 
81 	if (faa->fa_nreg < 1) {
82 		printf(": no registers\n");
83 		return;
84 	}
85 
86 	sc->sc_iot = faa->fa_iot;
87 	sc->sc_size = faa->fa_reg[0].size;
88 
89 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
90 	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
91 		printf(": can't map registers\n");
92 		return;
93 	}
94 
95 	pinctrl_byname(faa->fa_node, "default");
96 
97 	clock_enable_all(faa->fa_node);
98 	reset_deassert_all(faa->fa_node);
99 
100 	sc->sc_ih = fdt_intr_establish(faa->fa_node, IPL_BIO,
101 	    sdhc_intr, sc, sc->sc.sc_dev.dv_xname);
102 	if (sc->sc_ih == NULL) {
103 		printf(": can't establish interrupt\n");
104 		goto unmap;
105 	}
106 
107 	printf("\n");
108 
109 	sc->sc.sc_host = &sc->sc_host;
110 	sc->sc.sc_dmat = faa->fa_dmat;
111 
112 	/*
113 	 * Arasan controller always uses 1.8V and doesn't like an
114 	 * explicit switch.
115 	 */
116 	if (OF_is_compatible(faa->fa_node, "arasan,sdhci-5.1"))
117 		sc->sc.sc_signal_voltage = sdhc_fdt_signal_voltage;
118 
119 	/*
120 	 * Rockchip RK3399 PHY doesn't like being powered down at low
121 	 * clock speeds and needs to be powered up explicitly.
122 	 */
123 	if (OF_is_compatible(faa->fa_node, "rockchip,rk3399-sdhci-5.1")) {
124 		/*
125 		 * The eMMC core's clock multiplier is of no use, so we just
126 		 * clear it.  Also make sure to set the base clock frequency.
127 		 */
128 		freq = clock_get_frequency(faa->fa_node, "clk_xin");
129 		freq /= 1000 * 1000; /* in MHz */
130 		phandle = OF_getpropint(faa->fa_node,
131 		    "arasan,soc-ctl-syscon", 0);
132 		if (phandle)
133 			rm = regmap_byphandle(phandle);
134 		if (rm) {
135 			regmap_write_4(rm, GRF_EMMCCORE_CON11,
136 			    GRF_EMMCCORE_CON11_CLOCKMULT_CLR |
137 			    GRF_EMMCCORE_CON11_CLOCKMULT_VAL(0));
138 			regmap_write_4(rm, GRF_EMMCCORE_CON0_BASECLOCK,
139 			    GRF_EMMCCORE_CON0_BASECLOCK_CLR |
140 			    GRF_EMMCCORE_CON0_BASECLOCK_VAL(freq));
141 		}
142 		/* Provide base clock frequency for the PHY driver. */
143 		sc->sc_cd.cd_node = faa->fa_node;
144 		sc->sc_cd.cd_cookie = sc;
145 		sc->sc_cd.cd_get_frequency = sdhc_fdt_get_frequency;
146 		clock_register(&sc->sc_cd);
147 		/*
148 		 * Enable the PHY.  The PHY should be powered on/off in
149 		 * the bus_clock function, but it's good enough to just
150 		 * enable it here right away and to keep it powered on.
151 		 */
152 		phy_enable(faa->fa_node, "phy_arasan");
153 		sc->sc.sc_flags |= SDHC_F_NOPWR0;
154 	}
155 
156 	/* XXX Doesn't work on Rockchip RK3399. */
157 	sc->sc.sc_flags |= SDHC_F_NODDR50;
158 
159 	sdhc_host_found(&sc->sc, sc->sc_iot, sc->sc_ioh, sc->sc_size, 1, 0);
160 	return;
161 
162 unmap:
163 	bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_size);
164 }
165 
166 int
167 sdhc_fdt_signal_voltage(struct sdhc_softc *sc, int signal_voltage)
168 {
169 	switch (signal_voltage) {
170 	case SDMMC_SIGNAL_VOLTAGE_180:
171 		return 0;
172 	default:
173 		return EINVAL;
174 	}
175 }
176 
177 uint32_t
178 sdhc_fdt_get_frequency(void *cookie, uint32_t *cells)
179 {
180 	struct sdhc_fdt_softc *sc = cookie;
181 	return clock_get_frequency(sc->sc_cd.cd_node, "clk_xin");
182 }
183