1/*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2012 Thomas Skibo
5 * Copyright (c) 2008 Alexander Motin <mav@FreeBSD.org>
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/* Generic driver to attach sdhci controllers on simplebus.
30 * Derived mainly from sdhci_pci.c
31 */
32
33#include <sys/param.h>
34#include <sys/systm.h>
35#include <sys/bus.h>
36#include <sys/kernel.h>
37#include <sys/lock.h>
38#include <sys/module.h>
39#include <sys/mutex.h>
40#include <sys/resource.h>
41#include <sys/rman.h>
42#include <sys/sysctl.h>
43#include <sys/taskqueue.h>
44
45#include <machine/bus.h>
46#include <machine/resource.h>
47
48#include <dev/fdt/fdt_common.h>
49#include <dev/ofw/ofw_bus.h>
50#include <dev/ofw/ofw_bus_subr.h>
51
52#include <dev/ofw/ofw_subr.h>
53#include <dev/clk/clk.h>
54#include <dev/clk/clk_fixed.h>
55#include <dev/syscon/syscon.h>
56#include <dev/phy/phy.h>
57
58#include <dev/mmc/bridge.h>
59
60#include <dev/sdhci/sdhci.h>
61
62#include "mmcbr_if.h"
63#include "sdhci_if.h"
64
65#include "opt_mmccam.h"
66
67#include "clkdev_if.h"
68#include "syscon_if.h"
69
70#define	MAX_SLOTS		6
71#define	SDHCI_FDT_ARMADA38X	1
72#define	SDHCI_FDT_XLNX_ZY7	2
73#define	SDHCI_FDT_QUALCOMM	3
74#define	SDHCI_FDT_RK3399	4
75#define	SDHCI_FDT_RK3568	5
76#define	SDHCI_FDT_XLNX_ZMP	6
77
78#define	RK3399_GRF_EMMCCORE_CON0		0xf000
79#define	 RK3399_CORECFG_BASECLKFREQ		0xff00
80#define	 RK3399_CORECFG_TIMEOUTCLKUNIT		(1 << 7)
81#define	 RK3399_CORECFG_TUNINGCOUNT		0x3f
82#define	RK3399_GRF_EMMCCORE_CON11		0xf02c
83#define	 RK3399_CORECFG_CLOCKMULTIPLIER		0xff
84
85#define	RK3568_EMMC_HOST_CTRL			0x0508
86#define	RK3568_EMMC_EMMC_CTRL			0x052c
87#define	RK3568_EMMC_ATCTRL			0x0540
88#define	RK3568_EMMC_DLL_CTRL			0x0800
89#define	 DLL_CTRL_SRST				0x00000001
90#define	 DLL_CTRL_START				0x00000002
91#define	 DLL_CTRL_START_POINT_DEFAULT		0x00050000
92#define	 DLL_CTRL_INCREMENT_DEFAULT		0x00000200
93
94#define	RK3568_EMMC_DLL_RXCLK			0x0804
95#define	 DLL_RXCLK_DELAY_ENABLE			0x08000000
96#define	 DLL_RXCLK_NO_INV			0x20000000
97
98#define	RK3568_EMMC_DLL_TXCLK			0x0808
99#define	 DLL_TXCLK_DELAY_ENABLE			0x08000000
100#define	 DLL_TXCLK_TAPNUM_DEFAULT		0x00000008
101#define	 DLL_TXCLK_TAPNUM_FROM_SW		0x01000000
102
103#define	RK3568_EMMC_DLL_STRBIN			0x080c
104#define	 DLL_STRBIN_DELAY_ENABLE		0x08000000
105#define	 DLL_STRBIN_TAPNUM_DEFAULT		0x00000008
106#define	DLL_STRBIN_TAPNUM_FROM_SW		0x01000000
107
108#define	RK3568_EMMC_DLL_STATUS0			0x0840
109#define	 DLL_STATUS0_DLL_LOCK			0x00000100
110#define	 DLL_STATUS0_DLL_TIMEOUT		0x00000200
111
112#define	LOWEST_SET_BIT(mask)	((((mask) - 1) & (mask)) ^ (mask))
113#define	SHIFTIN(x, mask)	((x) * LOWEST_SET_BIT(mask))
114
115static struct ofw_compat_data compat_data[] = {
116	{ "marvell,armada-380-sdhci",	SDHCI_FDT_ARMADA38X },
117	{ "qcom,sdhci-msm-v4",		SDHCI_FDT_QUALCOMM },
118	{ "rockchip,rk3399-sdhci-5.1",	SDHCI_FDT_RK3399 },
119	{ "xlnx,zy7_sdhci",		SDHCI_FDT_XLNX_ZY7 },
120	{ "rockchip,rk3568-dwcmshc",	SDHCI_FDT_RK3568 },
121	{ "xlnx,zynqmp-8.9a",		SDHCI_FDT_XLNX_ZMP },
122	{ NULL, 0 }
123};
124
125struct sdhci_fdt_softc {
126	device_t	dev;		/* Controller device */
127	u_int		quirks;		/* Chip specific quirks */
128	u_int		caps;		/* If we override SDHCI_CAPABILITIES */
129	uint32_t	max_clk;	/* Max possible freq */
130	uint8_t		sdma_boundary;	/* If we override the SDMA boundary */
131	struct resource *irq_res;	/* IRQ resource */
132	void		*intrhand;	/* Interrupt handle */
133
134	int		num_slots;	/* Number of slots on this controller*/
135	struct sdhci_slot slots[MAX_SLOTS];
136	struct resource	*mem_res[MAX_SLOTS];	/* Memory resource */
137
138	bool		wp_inverted;	/* WP pin is inverted */
139	bool		wp_disabled;	/* WP pin is not supported */
140	bool		no_18v;		/* No 1.8V support */
141
142	clk_t		clk_xin;	/* xin24m fixed clock */
143	clk_t		clk_ahb;	/* ahb clock */
144	clk_t		clk_core;	/* core clock */
145	phy_t		phy;		/* phy to be used */
146
147	struct syscon	*syscon;	/* Handle to the syscon */
148};
149
150struct sdhci_exported_clocks_sc {
151	device_t	clkdev;
152};
153
154static int
155sdhci_exported_clocks_init(struct clknode *clk, device_t dev)
156{
157
158	clknode_init_parent_idx(clk, 0);
159	return (0);
160}
161
162static clknode_method_t sdhci_exported_clocks_clknode_methods[] = {
163	/* Device interface */
164	CLKNODEMETHOD(clknode_init,	sdhci_exported_clocks_init),
165	CLKNODEMETHOD_END
166};
167DEFINE_CLASS_1(sdhci_exported_clocks_clknode, sdhci_exported_clocks_clknode_class,
168    sdhci_exported_clocks_clknode_methods, sizeof(struct sdhci_exported_clocks_sc),
169    clknode_class);
170
171static int
172sdhci_clock_ofw_map(struct clkdom *clkdom, uint32_t ncells,
173    phandle_t *cells, struct clknode **clk)
174{
175	int id = 1; /* Our clock id starts at 1 */
176
177	if (ncells != 0)
178		id = cells[1];
179	*clk = clknode_find_by_id(clkdom, id);
180
181	if (*clk == NULL)
182		return (ENXIO);
183	return (0);
184}
185
186static void
187sdhci_export_clocks(struct sdhci_fdt_softc *sc)
188{
189	struct clknode_init_def def;
190	struct sdhci_exported_clocks_sc *clksc;
191	struct clkdom *clkdom;
192	struct clknode *clk;
193	bus_addr_t paddr;
194	bus_size_t psize;
195	const char **clknames;
196	phandle_t node;
197	int i, nclocks, ncells, error;
198
199	node = ofw_bus_get_node(sc->dev);
200
201	if (ofw_reg_to_paddr(node, 0, &paddr, &psize, NULL) != 0) {
202		device_printf(sc->dev, "cannot parse 'reg' property\n");
203		return;
204	}
205
206	error = ofw_bus_parse_xref_list_get_length(node, "clocks",
207	    "#clock-cells", &ncells);
208	if (error != 0 || ncells != 2) {
209		device_printf(sc->dev, "couldn't find parent clocks\n");
210		return;
211	}
212
213	nclocks = ofw_bus_string_list_to_array(node, "clock-output-names",
214	    &clknames);
215	/* No clocks to export */
216	if (nclocks <= 0)
217		return;
218
219	clkdom = clkdom_create(sc->dev);
220	clkdom_set_ofw_mapper(clkdom, sdhci_clock_ofw_map);
221
222	for (i = 0; i < nclocks; i++) {
223		memset(&def, 0, sizeof(def));
224		def.id = i + 1; /* Exported clock IDs starts at 1 */
225		def.name = clknames[i];
226		def.parent_names = malloc(sizeof(char *) * 1, M_OFWPROP, M_WAITOK);
227		def.parent_names[0] = clk_get_name(sc->clk_xin);
228		def.parent_cnt = 1;
229
230		clk = clknode_create(clkdom, &sdhci_exported_clocks_clknode_class, &def);
231		if (clk == NULL) {
232			device_printf(sc->dev, "cannot create clknode\n");
233			return;
234		}
235
236		clksc = clknode_get_softc(clk);
237		clksc->clkdev = device_get_parent(sc->dev);
238
239		clknode_register(clkdom, clk);
240	}
241
242	if (clkdom_finit(clkdom) != 0) {
243		device_printf(sc->dev, "cannot finalize clkdom initialization\n");
244		return;
245	}
246
247	if (bootverbose)
248		clkdom_dump(clkdom);
249}
250
251static int
252sdhci_init_clocks(device_t dev)
253{
254	struct sdhci_fdt_softc *sc = device_get_softc(dev);
255	int error;
256
257	/* Get and activate clocks */
258	error = clk_get_by_ofw_name(dev, 0, "clk_xin", &sc->clk_xin);
259	if (error != 0) {
260		device_printf(dev, "cannot get xin clock\n");
261		return (ENXIO);
262	}
263	error = clk_enable(sc->clk_xin);
264	if (error != 0) {
265		device_printf(dev, "cannot enable xin clock\n");
266		return (ENXIO);
267	}
268	error = clk_get_by_ofw_name(dev, 0, "clk_ahb", &sc->clk_ahb);
269	if (error != 0) {
270		device_printf(dev, "cannot get ahb clock\n");
271		return (ENXIO);
272	}
273	error = clk_enable(sc->clk_ahb);
274	if (error != 0) {
275		device_printf(dev, "cannot enable ahb clock\n");
276		return (ENXIO);
277	}
278
279	return (0);
280}
281
282static int
283sdhci_init_phy(struct sdhci_fdt_softc *sc)
284{
285	int error;
286
287	/* Enable PHY */
288	error = phy_get_by_ofw_name(sc->dev, 0, "phy_arasan", &sc->phy);
289	if (error == ENOENT)
290		return (0);
291	if (error != 0) {
292		device_printf(sc->dev, "Could not get phy\n");
293		return (ENXIO);
294	}
295	error = phy_enable(sc->phy);
296	if (error != 0) {
297		device_printf(sc->dev, "Could not enable phy\n");
298		return (ENXIO);
299	}
300
301	return (0);
302}
303
304static int
305sdhci_get_syscon(struct sdhci_fdt_softc *sc)
306{
307	phandle_t node;
308
309	/* Get syscon */
310	node = ofw_bus_get_node(sc->dev);
311	if (OF_hasprop(node, "arasan,soc-ctl-syscon") &&
312	    syscon_get_by_ofw_property(sc->dev, node,
313	    "arasan,soc-ctl-syscon", &sc->syscon) != 0) {
314		device_printf(sc->dev, "cannot get syscon handle\n");
315		return (ENXIO);
316	}
317
318	return (0);
319}
320
321static int
322sdhci_init_rk3399(device_t dev)
323{
324	struct sdhci_fdt_softc *sc = device_get_softc(dev);
325	uint64_t freq;
326	uint32_t mask, val;
327	int error;
328
329	error = clk_get_freq(sc->clk_xin, &freq);
330	if (error != 0) {
331		device_printf(dev, "cannot get xin clock frequency\n");
332		return (ENXIO);
333	}
334
335	/* Disable clock multiplier */
336	mask = RK3399_CORECFG_CLOCKMULTIPLIER;
337	val = 0;
338	SYSCON_WRITE_4(sc->syscon, RK3399_GRF_EMMCCORE_CON11, (mask << 16) | val);
339
340	/* Set base clock frequency */
341	mask = RK3399_CORECFG_BASECLKFREQ;
342	val = SHIFTIN((freq + (1000000 / 2)) / 1000000,
343	    RK3399_CORECFG_BASECLKFREQ);
344	SYSCON_WRITE_4(sc->syscon, RK3399_GRF_EMMCCORE_CON0, (mask << 16) | val);
345
346	return (0);
347}
348
349static uint8_t
350sdhci_fdt_read_1(device_t dev, struct sdhci_slot *slot, bus_size_t off)
351{
352	struct sdhci_fdt_softc *sc = device_get_softc(dev);
353
354	return (bus_read_1(sc->mem_res[slot->num], off));
355}
356
357static void
358sdhci_fdt_write_1(device_t dev, struct sdhci_slot *slot, bus_size_t off,
359    uint8_t val)
360{
361	struct sdhci_fdt_softc *sc = device_get_softc(dev);
362
363	bus_write_1(sc->mem_res[slot->num], off, val);
364}
365
366static uint16_t
367sdhci_fdt_read_2(device_t dev, struct sdhci_slot *slot, bus_size_t off)
368{
369	struct sdhci_fdt_softc *sc = device_get_softc(dev);
370
371	return (bus_read_2(sc->mem_res[slot->num], off));
372}
373
374static void
375sdhci_fdt_write_2(device_t dev, struct sdhci_slot *slot, bus_size_t off,
376    uint16_t val)
377{
378	struct sdhci_fdt_softc *sc = device_get_softc(dev);
379
380	bus_write_2(sc->mem_res[slot->num], off, val);
381}
382
383static uint32_t
384sdhci_fdt_read_4(device_t dev, struct sdhci_slot *slot, bus_size_t off)
385{
386	struct sdhci_fdt_softc *sc = device_get_softc(dev);
387	uint32_t val32;
388
389	val32 = bus_read_4(sc->mem_res[slot->num], off);
390	if (off == SDHCI_CAPABILITIES && sc->no_18v)
391		val32 &= ~SDHCI_CAN_VDD_180;
392
393	return (val32);
394}
395
396static void
397sdhci_fdt_write_4(device_t dev, struct sdhci_slot *slot, bus_size_t off,
398    uint32_t val)
399{
400	struct sdhci_fdt_softc *sc = device_get_softc(dev);
401
402	bus_write_4(sc->mem_res[slot->num], off, val);
403}
404
405static void
406sdhci_fdt_read_multi_4(device_t dev, struct sdhci_slot *slot,
407    bus_size_t off, uint32_t *data, bus_size_t count)
408{
409	struct sdhci_fdt_softc *sc = device_get_softc(dev);
410
411	bus_read_multi_4(sc->mem_res[slot->num], off, data, count);
412}
413
414static void
415sdhci_fdt_write_multi_4(device_t dev, struct sdhci_slot *slot,
416    bus_size_t off, uint32_t *data, bus_size_t count)
417{
418	struct sdhci_fdt_softc *sc = device_get_softc(dev);
419
420	bus_write_multi_4(sc->mem_res[slot->num], off, data, count);
421}
422
423static void
424sdhci_fdt_intr(void *arg)
425{
426	struct sdhci_fdt_softc *sc = (struct sdhci_fdt_softc *)arg;
427	int i;
428
429	for (i = 0; i < sc->num_slots; i++)
430		sdhci_generic_intr(&sc->slots[i]);
431}
432
433static int
434sdhci_fdt_get_ro(device_t bus, device_t dev)
435{
436	struct sdhci_fdt_softc *sc = device_get_softc(bus);
437
438	if (sc->wp_disabled)
439		return (false);
440	return (sdhci_generic_get_ro(bus, dev) ^ sc->wp_inverted);
441}
442
443static int
444sdhci_fdt_set_clock(device_t dev, struct sdhci_slot *slot, int clock)
445{
446	struct sdhci_fdt_softc *sc = device_get_softc(dev);
447	int32_t val;
448	int i;
449
450	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data ==
451	    SDHCI_FDT_RK3568) {
452		if (clock == 400000)
453			clock = 375000;
454
455		if (clock) {
456			clk_set_freq(sc->clk_core, clock, 0);
457
458			if (clock <= 52000000) {
459				bus_write_4(sc->mem_res[slot->num],
460				    RK3568_EMMC_DLL_CTRL, 0x0);
461				bus_write_4(sc->mem_res[slot->num],
462				    RK3568_EMMC_DLL_RXCLK, DLL_RXCLK_NO_INV);
463				bus_write_4(sc->mem_res[slot->num],
464				    RK3568_EMMC_DLL_TXCLK, 0x0);
465				bus_write_4(sc->mem_res[slot->num],
466				    RK3568_EMMC_DLL_STRBIN, 0x0);
467				return (clock);
468			}
469
470			bus_write_4(sc->mem_res[slot->num],
471			    RK3568_EMMC_DLL_CTRL, DLL_CTRL_START);
472			DELAY(1000);
473			bus_write_4(sc->mem_res[slot->num],
474			    RK3568_EMMC_DLL_CTRL, 0);
475			bus_write_4(sc->mem_res[slot->num],
476			    RK3568_EMMC_DLL_CTRL, DLL_CTRL_START_POINT_DEFAULT |
477			    DLL_CTRL_INCREMENT_DEFAULT | DLL_CTRL_START);
478			for (i = 0; i < 500; i++) {
479				val = bus_read_4(sc->mem_res[slot->num],
480				    RK3568_EMMC_DLL_STATUS0);
481				if (val & DLL_STATUS0_DLL_LOCK &&
482				    !(val & DLL_STATUS0_DLL_TIMEOUT))
483					break;
484				DELAY(1000);
485			}
486			bus_write_4(sc->mem_res[slot->num], RK3568_EMMC_ATCTRL,
487			    (0x1 << 16 | 0x2 << 17 | 0x3 << 19));
488			bus_write_4(sc->mem_res[slot->num],
489			    RK3568_EMMC_DLL_RXCLK,
490			    DLL_RXCLK_DELAY_ENABLE | DLL_RXCLK_NO_INV);
491			bus_write_4(sc->mem_res[slot->num],
492			    RK3568_EMMC_DLL_TXCLK, DLL_TXCLK_DELAY_ENABLE |
493			    DLL_TXCLK_TAPNUM_DEFAULT|DLL_TXCLK_TAPNUM_FROM_SW);
494			bus_write_4(sc->mem_res[slot->num],
495			    RK3568_EMMC_DLL_STRBIN, DLL_STRBIN_DELAY_ENABLE |
496			    DLL_STRBIN_TAPNUM_DEFAULT |
497			    DLL_STRBIN_TAPNUM_FROM_SW);
498		}
499	}
500	return (clock);
501}
502
503static int
504sdhci_fdt_probe(device_t dev)
505{
506	struct sdhci_fdt_softc *sc = device_get_softc(dev);
507	phandle_t node;
508	pcell_t cid;
509
510	sc->quirks = 0;
511	sc->num_slots = 1;
512	sc->max_clk = 0;
513
514	if (!ofw_bus_status_okay(dev))
515		return (ENXIO);
516
517	switch (ofw_bus_search_compatible(dev, compat_data)->ocd_data) {
518	case SDHCI_FDT_ARMADA38X:
519		sc->quirks = SDHCI_QUIRK_BROKEN_AUTO_STOP;
520		device_set_desc(dev, "ARMADA38X SDHCI controller");
521		break;
522	case SDHCI_FDT_QUALCOMM:
523		sc->quirks = SDHCI_QUIRK_ALL_SLOTS_NON_REMOVABLE |
524		    SDHCI_QUIRK_BROKEN_SDMA_BOUNDARY;
525		sc->sdma_boundary = SDHCI_BLKSZ_SDMA_BNDRY_4K;
526		device_set_desc(dev, "Qualcomm FDT SDHCI controller");
527		break;
528	case SDHCI_FDT_RK3399:
529		device_set_desc(dev, "Rockchip RK3399 fdt SDHCI controller");
530		break;
531	case SDHCI_FDT_XLNX_ZY7:
532		sc->quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK;
533		device_set_desc(dev, "Zynq-7000 generic fdt SDHCI controller");
534		break;
535	case SDHCI_FDT_RK3568:
536		device_set_desc(dev, "Rockchip RK3568 fdt SDHCI controller");
537		break;
538	case SDHCI_FDT_XLNX_ZMP:
539		device_set_desc(dev, "ZynqMP generic fdt SDHCI controller");
540		break;
541	default:
542		return (ENXIO);
543	}
544
545	node = ofw_bus_get_node(dev);
546
547	/* Allow dts to patch quirks, slots, and max-frequency. */
548	if ((OF_getencprop(node, "quirks", &cid, sizeof(cid))) > 0)
549		sc->quirks = cid;
550	if ((OF_getencprop(node, "num-slots", &cid, sizeof(cid))) > 0)
551		sc->num_slots = cid;
552	if ((OF_getencprop(node, "max-frequency", &cid, sizeof(cid))) > 0)
553		sc->max_clk = cid;
554	if (OF_hasprop(node, "no-1-8-v"))
555		sc->no_18v = true;
556	if (OF_hasprop(node, "wp-inverted"))
557		sc->wp_inverted = true;
558	if (OF_hasprop(node, "disable-wp"))
559		sc->wp_disabled = true;
560
561	return (0);
562}
563
564static int
565sdhci_fdt_attach(device_t dev)
566{
567	struct sdhci_fdt_softc *sc = device_get_softc(dev);
568	struct sdhci_slot *slot;
569	int err, slots, rid, i, compat;
570
571	sc->dev = dev;
572
573	/* Allocate IRQ. */
574	rid = 0;
575	sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
576	    RF_ACTIVE);
577	if (sc->irq_res == NULL) {
578		device_printf(dev, "Can't allocate IRQ\n");
579		return (ENOMEM);
580	}
581
582	compat = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
583	switch (compat) {
584	case SDHCI_FDT_RK3399:
585	case SDHCI_FDT_XLNX_ZMP:
586		err = sdhci_init_clocks(dev);
587		if (err != 0) {
588			device_printf(dev, "Cannot init clocks\n");
589			return (err);
590		}
591		sdhci_export_clocks(sc);
592		if ((err = sdhci_init_phy(sc)) != 0) {
593			device_printf(dev, "Cannot init phy\n");
594			return (err);
595		}
596		if ((err = sdhci_get_syscon(sc)) != 0) {
597			device_printf(dev, "Cannot get syscon handle\n");
598			return (err);
599		}
600		if (compat == SDHCI_FDT_RK3399) {
601			err = sdhci_init_rk3399(dev);
602			if (err != 0) {
603				device_printf(dev, "Cannot init RK3399 SDHCI\n");
604				return (err);
605			}
606		}
607		break;
608	case SDHCI_FDT_RK3568:
609		/* setup & enable clocks */
610		if (clk_get_by_ofw_name(dev, 0, "core", &sc->clk_core)) {
611			device_printf(dev, "cannot get core clock\n");
612			return (ENXIO);
613		}
614		clk_enable(sc->clk_core);
615		break;
616	default:
617		break;
618	}
619
620	/* Scan all slots. */
621	slots = sc->num_slots;	/* number of slots determined in probe(). */
622	sc->num_slots = 0;
623	for (i = 0; i < slots; i++) {
624		slot = &sc->slots[sc->num_slots];
625
626		/* Allocate memory. */
627		rid = 0;
628		sc->mem_res[i] = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
629							&rid, RF_ACTIVE);
630		if (sc->mem_res[i] == NULL) {
631			device_printf(dev,
632			    "Can't allocate memory for slot %d\n", i);
633			continue;
634		}
635
636		slot->quirks = sc->quirks;
637		slot->caps = sc->caps;
638		slot->max_clk = sc->max_clk;
639		slot->sdma_boundary = sc->sdma_boundary;
640
641		if (sdhci_init_slot(dev, slot, i) != 0)
642			continue;
643
644		sc->num_slots++;
645	}
646	device_printf(dev, "%d slot(s) allocated\n", sc->num_slots);
647
648	/* Activate the interrupt */
649	err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
650	    NULL, sdhci_fdt_intr, sc, &sc->intrhand);
651	if (err) {
652		device_printf(dev, "Cannot setup IRQ\n");
653		return (err);
654	}
655
656	/* Process cards detection. */
657	for (i = 0; i < sc->num_slots; i++)
658		sdhci_start_slot(&sc->slots[i]);
659
660	return (0);
661}
662
663static int
664sdhci_fdt_detach(device_t dev)
665{
666	struct sdhci_fdt_softc *sc = device_get_softc(dev);
667	int i;
668
669	bus_generic_detach(dev);
670	bus_teardown_intr(dev, sc->irq_res, sc->intrhand);
671	bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(sc->irq_res),
672	    sc->irq_res);
673
674	for (i = 0; i < sc->num_slots; i++) {
675		sdhci_cleanup_slot(&sc->slots[i]);
676		bus_release_resource(dev, SYS_RES_MEMORY,
677		    rman_get_rid(sc->mem_res[i]), sc->mem_res[i]);
678	}
679
680	return (0);
681}
682
683static device_method_t sdhci_fdt_methods[] = {
684	/* device_if */
685	DEVMETHOD(device_probe,		sdhci_fdt_probe),
686	DEVMETHOD(device_attach,	sdhci_fdt_attach),
687	DEVMETHOD(device_detach,	sdhci_fdt_detach),
688
689	/* Bus interface */
690	DEVMETHOD(bus_read_ivar,	sdhci_generic_read_ivar),
691	DEVMETHOD(bus_write_ivar,	sdhci_generic_write_ivar),
692
693	/* mmcbr_if */
694	DEVMETHOD(mmcbr_update_ios,	sdhci_generic_update_ios),
695	DEVMETHOD(mmcbr_request,	sdhci_generic_request),
696	DEVMETHOD(mmcbr_get_ro,		sdhci_fdt_get_ro),
697	DEVMETHOD(mmcbr_acquire_host,	sdhci_generic_acquire_host),
698	DEVMETHOD(mmcbr_release_host,	sdhci_generic_release_host),
699
700	/* SDHCI registers accessors */
701	DEVMETHOD(sdhci_read_1,		sdhci_fdt_read_1),
702	DEVMETHOD(sdhci_read_2,		sdhci_fdt_read_2),
703	DEVMETHOD(sdhci_read_4,		sdhci_fdt_read_4),
704	DEVMETHOD(sdhci_read_multi_4,	sdhci_fdt_read_multi_4),
705	DEVMETHOD(sdhci_write_1,	sdhci_fdt_write_1),
706	DEVMETHOD(sdhci_write_2,	sdhci_fdt_write_2),
707	DEVMETHOD(sdhci_write_4,	sdhci_fdt_write_4),
708	DEVMETHOD(sdhci_write_multi_4,	sdhci_fdt_write_multi_4),
709	DEVMETHOD(sdhci_set_clock,	sdhci_fdt_set_clock),
710
711	DEVMETHOD_END
712};
713
714static driver_t sdhci_fdt_driver = {
715	"sdhci_fdt",
716	sdhci_fdt_methods,
717	sizeof(struct sdhci_fdt_softc),
718};
719
720DRIVER_MODULE(sdhci_fdt, simplebus, sdhci_fdt_driver, NULL, NULL);
721SDHCI_DEPEND(sdhci_fdt);
722#ifndef MMCCAM
723MMC_DECLARE_BRIDGE(sdhci_fdt);
724#endif
725