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