xref: /freebsd/sys/dev/mmc/host/dwmmc_rockchip.c (revision 0f684b5aec50b4766dc2a8f010fd7b9568af5063)
174e0613eSEmmanuel Vadot /*
274e0613eSEmmanuel Vadot  * Copyright 2017 Emmanuel Vadot <manu@freebsd.org>
374e0613eSEmmanuel Vadot  *
474e0613eSEmmanuel Vadot  * Redistribution and use in source and binary forms, with or without
574e0613eSEmmanuel Vadot  * modification, are permitted provided that the following conditions are
674e0613eSEmmanuel Vadot  * met:
774e0613eSEmmanuel Vadot  *
874e0613eSEmmanuel Vadot  *  1. Redistributions of source code must retain the above copyright
974e0613eSEmmanuel Vadot  *     notice, this list of conditions and the following disclaimer.
1074e0613eSEmmanuel Vadot  *  2. Redistributions in binary form must reproduce the above copyright
1174e0613eSEmmanuel Vadot  *     notice, this list of conditions and the following disclaimer in the
1274e0613eSEmmanuel Vadot  *     documentation and/or other materials provided with the distribution.
1374e0613eSEmmanuel Vadot  *
1474e0613eSEmmanuel Vadot  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1574e0613eSEmmanuel Vadot  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1674e0613eSEmmanuel Vadot  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1774e0613eSEmmanuel Vadot  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
1874e0613eSEmmanuel Vadot  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
1974e0613eSEmmanuel Vadot  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2074e0613eSEmmanuel Vadot  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
2174e0613eSEmmanuel Vadot  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
2274e0613eSEmmanuel Vadot  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
2374e0613eSEmmanuel Vadot  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
2474e0613eSEmmanuel Vadot  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2574e0613eSEmmanuel Vadot  */
2674e0613eSEmmanuel Vadot 
2774e0613eSEmmanuel Vadot #include <sys/param.h>
2874e0613eSEmmanuel Vadot #include <sys/kernel.h>
2974e0613eSEmmanuel Vadot #include <sys/bus.h>
3074e0613eSEmmanuel Vadot #include <sys/module.h>
3187d4212bSEmmanuel Vadot #include <sys/queue.h>
3287d4212bSEmmanuel Vadot #include <sys/taskqueue.h>
3374e0613eSEmmanuel Vadot 
3474e0613eSEmmanuel Vadot #include <machine/bus.h>
3574e0613eSEmmanuel Vadot 
3674e0613eSEmmanuel Vadot #include <dev/mmc/bridge.h>
37a1af70e5SEmmanuel Vadot #include <dev/mmc/mmc_fdt_helpers.h>
3874e0613eSEmmanuel Vadot 
3974e0613eSEmmanuel Vadot #include <dev/ofw/ofw_bus_subr.h>
4074e0613eSEmmanuel Vadot 
41be82b3a0SEmmanuel Vadot #include <dev/clk/clk.h>
422f882399SEmmanuel Vadot 
4374e0613eSEmmanuel Vadot #include <dev/mmc/host/dwmmc_var.h>
4474e0613eSEmmanuel Vadot 
45d3a60796SIlya Bakulin #include "opt_mmccam.h"
46d3a60796SIlya Bakulin 
47a5091e03SEmmanuel Vadot enum RKTYPE {
48a5091e03SEmmanuel Vadot 	RK2928 = 1,
49ca28db3cSEmmanuel Vadot 	RK3288,
50a5091e03SEmmanuel Vadot };
51a5091e03SEmmanuel Vadot 
5274e0613eSEmmanuel Vadot static struct ofw_compat_data compat_data[] = {
53a5091e03SEmmanuel Vadot 	{"rockchip,rk2928-dw-mshc",	RK2928},
54ca28db3cSEmmanuel Vadot 	{"rockchip,rk3288-dw-mshc",	RK3288},
5574e0613eSEmmanuel Vadot 	{NULL,				0},
5674e0613eSEmmanuel Vadot };
5774e0613eSEmmanuel Vadot 
58a5091e03SEmmanuel Vadot static int dwmmc_rockchip_update_ios(struct dwmmc_softc *sc, struct mmc_ios *ios);
59a5091e03SEmmanuel Vadot 
6074e0613eSEmmanuel Vadot static int
rockchip_dwmmc_probe(device_t dev)6174e0613eSEmmanuel Vadot rockchip_dwmmc_probe(device_t dev)
6274e0613eSEmmanuel Vadot {
6374e0613eSEmmanuel Vadot 
6474e0613eSEmmanuel Vadot 	if (!ofw_bus_status_okay(dev))
6574e0613eSEmmanuel Vadot 		return (ENXIO);
6674e0613eSEmmanuel Vadot 
6774e0613eSEmmanuel Vadot 	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
6874e0613eSEmmanuel Vadot 		return (ENXIO);
6974e0613eSEmmanuel Vadot 
7074e0613eSEmmanuel Vadot 	device_set_desc(dev, "Synopsys DesignWare Mobile "
7174e0613eSEmmanuel Vadot 	    "Storage Host Controller (RockChip)");
7274e0613eSEmmanuel Vadot 
7374e0613eSEmmanuel Vadot 	return (BUS_PROBE_VENDOR);
7474e0613eSEmmanuel Vadot }
7574e0613eSEmmanuel Vadot 
7674e0613eSEmmanuel Vadot static int
rockchip_dwmmc_attach(device_t dev)7774e0613eSEmmanuel Vadot rockchip_dwmmc_attach(device_t dev)
7874e0613eSEmmanuel Vadot {
7974e0613eSEmmanuel Vadot 	struct dwmmc_softc *sc;
80a5091e03SEmmanuel Vadot 	int type;
81*0f684b5aSStephen Hurd 	int rc;
8274e0613eSEmmanuel Vadot 
8374e0613eSEmmanuel Vadot 	sc = device_get_softc(dev);
8474e0613eSEmmanuel Vadot 	sc->hwtype = HWTYPE_ROCKCHIP;
85a5091e03SEmmanuel Vadot 	type = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
8674e0613eSEmmanuel Vadot 
87a5091e03SEmmanuel Vadot 	switch (type) {
88a5091e03SEmmanuel Vadot 	case RK2928:
8974e0613eSEmmanuel Vadot 		sc->use_pio = 1;
90a5091e03SEmmanuel Vadot 		break;
91a5091e03SEmmanuel Vadot 	}
92a5091e03SEmmanuel Vadot 
93a5091e03SEmmanuel Vadot 	sc->update_ios = &dwmmc_rockchip_update_ios;
94*0f684b5aSStephen Hurd 	rc = dwmmc_attach(dev);
95a5091e03SEmmanuel Vadot 
96*0f684b5aSStephen Hurd 	/*
97*0f684b5aSStephen Hurd 	 * Note: It's not that the controller doesn't support HS200,
98*0f684b5aSStephen Hurd 	 *       it's that FreeBSD doesn't support tuning.
99*0f684b5aSStephen Hurd 	 *       If someone implemented tuning, this could work.
100*0f684b5aSStephen Hurd 	 */
101*0f684b5aSStephen Hurd 	device_printf(dev, "Disabling HS200+ (tuning code not written)\n");
102*0f684b5aSStephen Hurd 	sc->host.caps &= ~(MMC_CAP_MMC_HS200 | MMC_CAP_MMC_HS400);
103*0f684b5aSStephen Hurd 
104*0f684b5aSStephen Hurd 	return (rc);
10574e0613eSEmmanuel Vadot }
10674e0613eSEmmanuel Vadot 
107a5091e03SEmmanuel Vadot static int
dwmmc_rockchip_update_ios(struct dwmmc_softc * sc,struct mmc_ios * ios)108a5091e03SEmmanuel Vadot dwmmc_rockchip_update_ios(struct dwmmc_softc *sc, struct mmc_ios *ios)
109a5091e03SEmmanuel Vadot {
110a5091e03SEmmanuel Vadot 	unsigned int clock;
111a5091e03SEmmanuel Vadot 	int error;
112a5091e03SEmmanuel Vadot 
113a5091e03SEmmanuel Vadot 	if (ios->clock && ios->clock != sc->bus_hz) {
114a5091e03SEmmanuel Vadot 		sc->bus_hz = clock = ios->clock;
115a5091e03SEmmanuel Vadot 		/* Set the MMC clock. */
116a5091e03SEmmanuel Vadot 		if (sc->ciu) {
117a5091e03SEmmanuel Vadot 			/*
118a5091e03SEmmanuel Vadot 			 * Apparently you need to set the ciu clock to
119a5091e03SEmmanuel Vadot 			 * the double of bus_hz
120a5091e03SEmmanuel Vadot 			 */
121a5091e03SEmmanuel Vadot 			error = clk_set_freq(sc->ciu, clock * 2,
122a5091e03SEmmanuel Vadot 			    CLK_SET_ROUND_DOWN);
123a5091e03SEmmanuel Vadot 			if (error != 0) {
124a5091e03SEmmanuel Vadot 				device_printf(sc->dev,
125a5091e03SEmmanuel Vadot 				    "failed to set frequency to %u Hz: %d\n",
126a5091e03SEmmanuel Vadot 				    clock, error);
127a5091e03SEmmanuel Vadot 				return (error);
128a5091e03SEmmanuel Vadot 			}
129a5091e03SEmmanuel Vadot 		}
130a5091e03SEmmanuel Vadot 	}
131a5091e03SEmmanuel Vadot 	return (0);
132a5091e03SEmmanuel Vadot }
133a5091e03SEmmanuel Vadot 
13474e0613eSEmmanuel Vadot static device_method_t rockchip_dwmmc_methods[] = {
13574e0613eSEmmanuel Vadot 	/* bus interface */
13674e0613eSEmmanuel Vadot 	DEVMETHOD(device_probe, rockchip_dwmmc_probe),
13774e0613eSEmmanuel Vadot 	DEVMETHOD(device_attach, rockchip_dwmmc_attach),
13887dc015dSEmmanuel Vadot 	DEVMETHOD(device_detach, dwmmc_detach),
13974e0613eSEmmanuel Vadot 
14074e0613eSEmmanuel Vadot 	DEVMETHOD_END
14174e0613eSEmmanuel Vadot };
14274e0613eSEmmanuel Vadot 
14374e0613eSEmmanuel Vadot DEFINE_CLASS_1(rockchip_dwmmc, rockchip_dwmmc_driver, rockchip_dwmmc_methods,
14474e0613eSEmmanuel Vadot     sizeof(struct dwmmc_softc), dwmmc_driver);
14574e0613eSEmmanuel Vadot 
146b58c5abfSJohn Baldwin DRIVER_MODULE(rockchip_dwmmc, simplebus, rockchip_dwmmc_driver, 0, 0);
147b58c5abfSJohn Baldwin DRIVER_MODULE(rockchip_dwmmc, ofwbus, rockchip_dwmmc_driver, NULL, NULL);
14874e0613eSEmmanuel Vadot #ifndef MMCCAM
14974e0613eSEmmanuel Vadot MMC_DECLARE_BRIDGE(rockchip_dwmmc);
15074e0613eSEmmanuel Vadot #endif
151