Annotation of src/sys/dev/fdt/arasan_sdhc_fdt.c, Revision 1.1.4.3
1.1.4.3 ! martin 1: /* $NetBSD$ */
1.1.4.2 christos 2:
3: /*-
4: * Copyright (c) 2019 Jared McNeill <jmcneill@invisible.ca>
5: * All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: *
16: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21: * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23: * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26: * SUCH DAMAGE.
27: */
28:
29: #include <sys/cdefs.h>
1.1.4.3 ! martin 30: __KERNEL_RCSID(0, "$NetBSD$");
1.1.4.2 christos 31:
32: #include <sys/param.h>
33: #include <sys/bus.h>
34: #include <sys/device.h>
35: #include <sys/systm.h>
36: #include <sys/sysctl.h>
37: #include <sys/kmem.h>
38:
39: #include <dev/sdmmc/sdhcreg.h>
40: #include <dev/sdmmc/sdhcvar.h>
41: #include <dev/sdmmc/sdmmcvar.h>
42:
43: #include <dev/clk/clk_backend.h>
44:
45: #include <dev/fdt/fdtvar.h>
46: #include <dev/fdt/syscon.h>
47:
48: #define RK3399_GRF_EMMCCORE_CON0 0xf000
49: #define RK3399_CORECFG_BASECLKFREQ __BITS(15,8)
50: #define RK3399_CORECFG_TIMEOUTCLKUNIT __BIT(7)
51: #define RK3399_CORECFG_TUNINGCOUNT __BITS(5,0)
52: #define RK3399_GRF_EMMCCORE_CON11 0xf02c
53: #define RK3399_CORECFG_CLOCKMULTIPLIER __BITS(7,0)
54:
55: enum arasan_sdhc_type {
56: AS_TYPE_RK3399 = 1,
57: };
58:
59: struct arasan_sdhc_softc {
60: struct sdhc_softc sc_base;
61: struct sdhc_host *sc_host[1];
62: bus_space_tag_t sc_bst;
63: bus_space_handle_t sc_bsh;
64: bus_size_t sc_bsz;
65: int sc_phandle;
66: struct fdtbus_phy *sc_phy;
67: struct syscon *sc_syscon;
68: struct clk *sc_clk_xin;
69: struct clk *sc_clk_ahb;
70: enum arasan_sdhc_type sc_type;
71: struct clk_domain sc_clkdom;
72: struct clk sc_clk_card;
73: };
74:
75: static const struct of_compat_data compat_data[] = {
76: { "rockchip,rk3399-sdhci-5.1", AS_TYPE_RK3399 },
77: { NULL }
78: };
79:
80: static struct clk *
81: arasan_sdhc_clk_decode(device_t dev, int cc_phandle, const void *data, size_t len)
82: {
83: struct arasan_sdhc_softc * const sc = device_private(dev);
84:
85: if (len != 0)
86: return NULL;
87:
88: return &sc->sc_clk_card;
89: }
90:
91: static const struct fdtbus_clock_controller_func arasan_sdhc_fdt_clk_funcs = {
92: .decode = arasan_sdhc_clk_decode,
93: };
94:
95: static struct clk *
96: arasan_sdhc_clk_get(void *priv, const char *name)
97: {
98: struct arasan_sdhc_softc * const sc = priv;
99:
100: if (strcmp(name, sc->sc_clk_card.name) != 0)
101: return NULL;
102:
103: return &sc->sc_clk_card;
104: }
105:
106: static u_int
107: arasan_sdhc_clk_get_rate(void *priv, struct clk *clk)
108: {
109: struct arasan_sdhc_softc * const sc = priv;
110:
111: return clk_get_rate(sc->sc_clk_xin);
112: }
113:
114: static const struct clk_funcs arasan_sdhc_clk_funcs = {
115: .get = arasan_sdhc_clk_get,
116: .get_rate = arasan_sdhc_clk_get_rate,
117: };
118:
119: static int
120: arasan_sdhc_signal_voltage(struct sdhc_softc *sdhc, int signal_voltage)
121: {
122: if (signal_voltage == SDMMC_SIGNAL_VOLTAGE_180)
123: return 0;
124:
125: return EINVAL;
126: }
127:
128: static int
129: arasan_sdhc_bus_clock_pre(struct sdhc_softc *sdhc, int freq)
130: {
131: struct arasan_sdhc_softc * const sc = device_private(sdhc->sc_dev);
132: int error;
133:
134: if (sc->sc_phy != NULL) {
135: error = fdtbus_phy_enable(sc->sc_phy, false);
136: if (error != 0)
137: return error;
138: }
139:
140: return 0;
141: }
142:
143: static int
144: arasan_sdhc_bus_clock_post(struct sdhc_softc *sdhc, int freq)
145: {
146: struct arasan_sdhc_softc * const sc = device_private(sdhc->sc_dev);
147: int error;
148:
149: if (sc->sc_phy != NULL) {
150: error = fdtbus_phy_enable(sc->sc_phy, true);
151: if (error != 0)
152: return error;
153: }
154:
155: return 0;
156: }
157:
158: static void
159: arasan_sdhc_init_rk3399(struct arasan_sdhc_softc *sc)
160: {
161: uint32_t mask, val;
162:
163: if (sc->sc_syscon == NULL)
164: return;
165:
166: syscon_lock(sc->sc_syscon);
167:
168: /* Disable clock multiplier */
169: mask = RK3399_CORECFG_CLOCKMULTIPLIER;
170: val = 0;
171: syscon_write_4(sc->sc_syscon, RK3399_GRF_EMMCCORE_CON11, (mask << 16) | val);
172:
173: /* Set base clock frequency */
174: const u_int xin_rate = clk_get_rate(sc->sc_clk_xin);
175: mask = RK3399_CORECFG_BASECLKFREQ;
176: val = __SHIFTIN((xin_rate + (1000000 / 2)) / 1000000, RK3399_CORECFG_BASECLKFREQ);
177: syscon_write_4(sc->sc_syscon, RK3399_GRF_EMMCCORE_CON0, (mask << 16) | val);
178:
179: syscon_unlock(sc->sc_syscon);
180: }
181:
182: static void
183: arasan_sdhc_init(device_t dev)
184: {
185: struct arasan_sdhc_softc * const sc = device_private(dev);
186: const char * sdhci_5_1_compat[] = { "arasan,sdhci-5.1", NULL };
187: int error;
188:
189: if (sc->sc_type == AS_TYPE_RK3399)
190: arasan_sdhc_init_rk3399(sc);
191:
192: if (of_match_compatible(sc->sc_phandle, sdhci_5_1_compat)) {
193: sc->sc_phy = fdtbus_phy_get(sc->sc_phandle, "phy_arasan");
194: if (sc->sc_phy == NULL) {
195: aprint_error_dev(dev, "couldn't get PHY\n");
196: return;
197: }
198: sc->sc_base.sc_vendor_signal_voltage = arasan_sdhc_signal_voltage;
199: }
200:
201: error = sdhc_host_found(&sc->sc_base, sc->sc_bst, sc->sc_bsh, sc->sc_bsz);
202: if (error != 0) {
203: aprint_error_dev(dev, "couldn't initialize host, error = %d\n", error);
204: return;
205: }
206: }
207:
208: static int
209: arasan_sdhc_match(device_t parent, cfdata_t cf, void *aux)
210: {
211: struct fdt_attach_args * const faa = aux;
212:
213: return of_match_compat_data(faa->faa_phandle, compat_data);
214: }
215:
216: static void
217: arasan_sdhc_attach(device_t parent, device_t self, void *aux)
218: {
219: struct arasan_sdhc_softc * const sc = device_private(self);
220: struct fdt_attach_args * const faa = aux;
221: const int phandle = faa->faa_phandle;
222: char intrstr[128];
223: const char *clkname;
224: bus_addr_t addr;
225: bus_size_t size;
226: u_int bus_width;
1.1.4.3 ! martin 227: int error;
1.1.4.2 christos 228: void *ih;
229:
230: fdtbus_clock_assign(phandle);
231:
232: if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
233: aprint_error(": couldn't get registers\n");
234: return;
235: }
236:
237: if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
238: aprint_error(": couldn't decode interrupt\n");
239: return;
240: }
241:
242: sc->sc_clk_xin = fdtbus_clock_get(phandle, "clk_xin");
243: sc->sc_clk_ahb = fdtbus_clock_get(phandle, "clk_ahb");
244: if (sc->sc_clk_xin == NULL || sc->sc_clk_ahb == NULL) {
245: aprint_error(": couldn't get clocks\n");
246: return;
247: }
248: if (clk_enable(sc->sc_clk_xin) != 0 || clk_enable(sc->sc_clk_ahb) != 0) {
249: aprint_error(": couldn't enable clocks\n");
250: return;
251: }
252:
253: sc->sc_syscon = fdtbus_syscon_acquire(phandle, "arasan,soc-ctl-syscon");
254:
255: if (of_getprop_uint32(phandle, "bus-width", &bus_width) != 0)
256: bus_width = 4;
257:
258: sc->sc_phandle = phandle;
259: sc->sc_bst = faa->faa_bst;
260: if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) {
261: aprint_error(": couldn't map registers\n");
262: return;
263: }
264: sc->sc_bsz = size;
265: sc->sc_type = of_search_compatible(phandle, compat_data)->data;
266:
1.1.4.3 ! martin 267: const uint32_t caps = bus_space_read_4(sc->sc_bst, sc->sc_bsh, SDHC_CAPABILITIES);
! 268: if ((caps & (SDHC_ADMA2_SUPP|SDHC_64BIT_SYS_BUS)) == SDHC_ADMA2_SUPP) {
! 269: error = bus_dmatag_subregion(faa->faa_dmat, 0, 0xffffffff,
! 270: &sc->sc_base.sc_dmat, BUS_DMA_WAITOK);
! 271: if (error != 0) {
! 272: aprint_error(": couldn't create DMA tag: %d\n", error);
! 273: return;
! 274: }
! 275: } else {
! 276: sc->sc_base.sc_dmat = faa->faa_dmat;
! 277: }
! 278:
1.1.4.2 christos 279: sc->sc_base.sc_dev = self;
280: sc->sc_base.sc_host = sc->sc_host;
281: sc->sc_base.sc_flags = SDHC_FLAG_NO_CLKBASE |
1.1.4.3 ! martin 282: SDHC_FLAG_SINGLE_POWER_WRITE |
! 283: SDHC_FLAG_32BIT_ACCESS |
1.1.4.2 christos 284: SDHC_FLAG_USE_DMA |
285: SDHC_FLAG_USE_ADMA2 |
286: SDHC_FLAG_STOP_WITH_TC;
287: if (bus_width == 8)
288: sc->sc_base.sc_flags |= SDHC_FLAG_8BIT_MODE;
289: sc->sc_base.sc_clkbase = clk_get_rate(sc->sc_clk_xin) / 1000;
290: sc->sc_base.sc_vendor_bus_clock = arasan_sdhc_bus_clock_pre;
291: sc->sc_base.sc_vendor_bus_clock_post = arasan_sdhc_bus_clock_post;
292:
293: aprint_naive("\n");
294: aprint_normal(": Arasan SDHCI controller\n");
295:
296: clkname = fdtbus_get_string(phandle, "clock-output-names");
297: if (clkname == NULL)
298: clkname = faa->faa_name;
299:
300: sc->sc_clkdom.name = device_xname(self);
301: sc->sc_clkdom.funcs = &arasan_sdhc_clk_funcs;
302: sc->sc_clkdom.priv = sc;
303: sc->sc_clk_card.domain = &sc->sc_clkdom;
304: sc->sc_clk_card.name = kmem_asprintf("%s", clkname);
305: clk_attach(&sc->sc_clk_card);
306:
307: fdtbus_register_clock_controller(self, phandle, &arasan_sdhc_fdt_clk_funcs);
308:
309: ih = fdtbus_intr_establish(phandle, 0, IPL_SDMMC, 0, sdhc_intr, &sc->sc_base);
310: if (ih == NULL) {
311: aprint_error_dev(self, "couldn't establish interrupt on %s\n", intrstr);
312: return;
313: }
314: aprint_normal_dev(self, "interrupting on %s\n", intrstr);
315:
316: arasan_sdhc_init(self);
317: }
318:
319: CFATTACH_DECL_NEW(arasan_sdhc_fdt, sizeof(struct arasan_sdhc_softc),
320: arasan_sdhc_match, arasan_sdhc_attach, NULL, NULL);
CVSweb <webmaster@jp.NetBSD.org>