xref: /freebsd/sys/dev/mmc/host/dwmmc_starfive.c (revision c8b472aa)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright 2017 Emmanuel Vadot <manu@freebsd.org>
5  * Copyright (c) 2024 The FreeBSD Foundation
6  *
7  * Portions of this software were developed by Mitchell Horne
8  * <mhorne@FreeBSD.org> under sponsorship from the FreeBSD Foundation.
9  */
10 
11 #include <sys/param.h>
12 #include <sys/kernel.h>
13 #include <sys/bus.h>
14 #include <sys/module.h>
15 #include <sys/queue.h>
16 #include <sys/taskqueue.h>
17 
18 #include <machine/bus.h>
19 
20 #include <dev/mmc/bridge.h>
21 #include <dev/mmc/mmc_fdt_helpers.h>
22 
23 #include <dev/mmc/host/dwmmc_var.h>
24 
25 #include <dev/ofw/ofw_bus_subr.h>
26 
27 #include "opt_mmccam.h"
28 
29 enum dwmmc_type {
30 	DWMMC_GENERIC = 1,
31 	DWMMC_JH7110
32 };
33 
34 static struct ofw_compat_data compat_data[] = {
35 	{"snps,dw-mshc",	DWMMC_GENERIC},
36 	{"starfive,jh7110-mmc",	DWMMC_JH7110},
37 	{NULL,			0}
38 };
39 
dwmmc_starfive_update_ios(struct dwmmc_softc * sc,struct mmc_ios * ios)40 static int dwmmc_starfive_update_ios(struct dwmmc_softc *sc,
41     struct mmc_ios *ios)
42 {
43 	int err;
44 
45 	if (ios->clock != 0 && ios->clock != sc->bus_hz) {
46 		err = clk_set_freq(sc->ciu, ios->clock, CLK_SET_ROUND_DOWN);
47 		if (err != 0) {
48 			printf("%s, Failed to set freq for ciu clock\n",
49 			    __func__);
50 			return (err);
51 		}
52 		sc->bus_hz = ios->clock;
53 	}
54 
55 	return (0);
56 }
57 
58 static int
starfive_dwmmc_probe(device_t dev)59 starfive_dwmmc_probe(device_t dev)
60 {
61 	phandle_t node;
62 	int type;
63 
64 	if (!ofw_bus_status_okay(dev))
65 		return (ENXIO);
66 
67 	type = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
68 	if (type == 0)
69 		return (ENXIO);
70 
71 	/*
72 	 * If we matched the generic compat string, check the top-level board
73 	 * compatible, to ensure we should actually use the starfive driver.
74 	 */
75 	if (type == DWMMC_GENERIC) {
76 		node = OF_finddevice("/");
77 		if (!ofw_bus_node_is_compatible(node, "starfive,jh7110"))
78 			return (ENXIO);
79 	}
80 
81 	device_set_desc(dev, "Synopsys DesignWare Mobile Storage "
82 	    "Host Controller (StarFive)");
83 
84 	return (BUS_PROBE_VENDOR);
85 }
86 
87 static int
starfive_dwmmc_attach(device_t dev)88 starfive_dwmmc_attach(device_t dev)
89 {
90 	struct dwmmc_softc *sc;
91 
92 	sc = device_get_softc(dev);
93 	sc->update_ios = &dwmmc_starfive_update_ios;
94 
95 	return (dwmmc_attach(dev));
96 }
97 
98 static device_method_t starfive_dwmmc_methods[] = {
99 	/* bus interface */
100 	DEVMETHOD(device_probe,		starfive_dwmmc_probe),
101 	DEVMETHOD(device_attach,	starfive_dwmmc_attach),
102 	DEVMETHOD(device_detach,	dwmmc_detach),
103 
104 	DEVMETHOD_END
105 };
106 
107 DEFINE_CLASS_1(starfive_dwmmc, starfive_dwmmc_driver, starfive_dwmmc_methods,
108     sizeof(struct dwmmc_softc), dwmmc_driver);
109 
110 DRIVER_MODULE(starfive_dwmmc, simplebus, starfive_dwmmc_driver, 0, 0);
111 
112 #ifndef MMCCAM
113 MMC_DECLARE_BRIDGE(starfive_dwmmc);
114 #endif
115