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 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 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 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