xref: /freebsd/sys/dev/mmc/mmc_helpers.c (revision 8a8166e5bcfb50e2b7280581b600d098fa6c9fc7)
1*8a8166e5SBartlomiej Grzesik /*
2*8a8166e5SBartlomiej Grzesik  * Copyright 2019 Emmanuel Vadot <manu@freebsd.org>
3*8a8166e5SBartlomiej Grzesik  * Copyright (c) 2017 Ian Lepore <ian@freebsd.org> All rights reserved.
4*8a8166e5SBartlomiej Grzesik  *
5*8a8166e5SBartlomiej Grzesik  * Redistribution and use in source and binary forms, with or without
6*8a8166e5SBartlomiej Grzesik  * modification, are permitted provided that the following conditions are
7*8a8166e5SBartlomiej Grzesik  * met:
8*8a8166e5SBartlomiej Grzesik  *
9*8a8166e5SBartlomiej Grzesik  *  1. Redistributions of source code must retain the above copyright
10*8a8166e5SBartlomiej Grzesik  *     notice, this list of conditions and the following disclaimer.
11*8a8166e5SBartlomiej Grzesik  *  2. Redistributions in binary form must reproduce the above copyright
12*8a8166e5SBartlomiej Grzesik  *     notice, this list of conditions and the following disclaimer in the
13*8a8166e5SBartlomiej Grzesik  *     documentation and/or other materials provided with the distribution.
14*8a8166e5SBartlomiej Grzesik  *
15*8a8166e5SBartlomiej Grzesik  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16*8a8166e5SBartlomiej Grzesik  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17*8a8166e5SBartlomiej Grzesik  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18*8a8166e5SBartlomiej Grzesik  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
19*8a8166e5SBartlomiej Grzesik  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20*8a8166e5SBartlomiej Grzesik  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21*8a8166e5SBartlomiej Grzesik  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
22*8a8166e5SBartlomiej Grzesik  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23*8a8166e5SBartlomiej Grzesik  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24*8a8166e5SBartlomiej Grzesik  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25*8a8166e5SBartlomiej Grzesik  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*8a8166e5SBartlomiej Grzesik  */
27*8a8166e5SBartlomiej Grzesik 
28*8a8166e5SBartlomiej Grzesik #include <sys/cdefs.h>
29*8a8166e5SBartlomiej Grzesik __FBSDID("$FreeBSD$");
30*8a8166e5SBartlomiej Grzesik 
31*8a8166e5SBartlomiej Grzesik #include <sys/param.h>
32*8a8166e5SBartlomiej Grzesik #include <sys/bus.h>
33*8a8166e5SBartlomiej Grzesik #include <sys/kernel.h>
34*8a8166e5SBartlomiej Grzesik #include <sys/gpio.h>
35*8a8166e5SBartlomiej Grzesik #include <sys/taskqueue.h>
36*8a8166e5SBartlomiej Grzesik 
37*8a8166e5SBartlomiej Grzesik #include <dev/mmc/bridge.h>
38*8a8166e5SBartlomiej Grzesik #include <dev/mmc/mmc_helpers.h>
39*8a8166e5SBartlomiej Grzesik 
40*8a8166e5SBartlomiej Grzesik static inline void
41*8a8166e5SBartlomiej Grzesik mmc_parse_sd_speed(device_t dev, struct mmc_host *host)
42*8a8166e5SBartlomiej Grzesik {
43*8a8166e5SBartlomiej Grzesik 	bool no_18v = false;
44*8a8166e5SBartlomiej Grzesik 
45*8a8166e5SBartlomiej Grzesik 	/*
46*8a8166e5SBartlomiej Grzesik 	 * Parse SD supported modes
47*8a8166e5SBartlomiej Grzesik 	 * All UHS-I modes requires 1.8V signaling.
48*8a8166e5SBartlomiej Grzesik 	 */
49*8a8166e5SBartlomiej Grzesik 	if (device_has_property(dev, "no-1-8-v"))
50*8a8166e5SBartlomiej Grzesik 		no_18v = true;
51*8a8166e5SBartlomiej Grzesik 	if (device_has_property(dev, "cap-sd-highspeed"))
52*8a8166e5SBartlomiej Grzesik 		host->caps |= MMC_CAP_HSPEED;
53*8a8166e5SBartlomiej Grzesik 	if (device_has_property(dev, "sd-uhs-sdr12") && !no_18v)
54*8a8166e5SBartlomiej Grzesik 		host->caps |= MMC_CAP_UHS_SDR12 | MMC_CAP_SIGNALING_180;
55*8a8166e5SBartlomiej Grzesik 	if (device_has_property(dev, "sd-uhs-sdr25") && !no_18v)
56*8a8166e5SBartlomiej Grzesik 		host->caps |= MMC_CAP_UHS_SDR25 | MMC_CAP_SIGNALING_180;
57*8a8166e5SBartlomiej Grzesik 	if (device_has_property(dev, "sd-uhs-sdr50") && !no_18v)
58*8a8166e5SBartlomiej Grzesik 		host->caps |= MMC_CAP_UHS_SDR50 | MMC_CAP_SIGNALING_180;
59*8a8166e5SBartlomiej Grzesik 	if (device_has_property(dev, "sd-uhs-sdr104") && !no_18v)
60*8a8166e5SBartlomiej Grzesik 		host->caps |= MMC_CAP_UHS_SDR104 | MMC_CAP_SIGNALING_180;
61*8a8166e5SBartlomiej Grzesik 	if (device_has_property(dev, "sd-uhs-ddr50") && !no_18v)
62*8a8166e5SBartlomiej Grzesik 		host->caps |= MMC_CAP_UHS_DDR50 | MMC_CAP_SIGNALING_180;
63*8a8166e5SBartlomiej Grzesik }
64*8a8166e5SBartlomiej Grzesik 
65*8a8166e5SBartlomiej Grzesik static inline void
66*8a8166e5SBartlomiej Grzesik mmc_parse_mmc_speed(device_t dev, struct mmc_host *host)
67*8a8166e5SBartlomiej Grzesik {
68*8a8166e5SBartlomiej Grzesik 	/* Parse eMMC supported modes */
69*8a8166e5SBartlomiej Grzesik 	if (device_has_property(dev, "cap-mmc-highspeed"))
70*8a8166e5SBartlomiej Grzesik 		host->caps |= MMC_CAP_HSPEED;
71*8a8166e5SBartlomiej Grzesik 	if (device_has_property(dev, "mmc-ddr-1_2v"))
72*8a8166e5SBartlomiej Grzesik 		host->caps |= MMC_CAP_MMC_DDR52_120 | MMC_CAP_SIGNALING_120;
73*8a8166e5SBartlomiej Grzesik 	if (device_has_property(dev, "mmc-ddr-1_8v"))
74*8a8166e5SBartlomiej Grzesik 		host->caps |= MMC_CAP_MMC_DDR52_180 | MMC_CAP_SIGNALING_180;
75*8a8166e5SBartlomiej Grzesik 	if (device_has_property(dev, "mmc-ddr-3_3v"))
76*8a8166e5SBartlomiej Grzesik 		host->caps |= MMC_CAP_SIGNALING_330;
77*8a8166e5SBartlomiej Grzesik 	if (device_has_property(dev, "mmc-hs200-1_2v"))
78*8a8166e5SBartlomiej Grzesik 		host->caps |= MMC_CAP_MMC_HS200_120 | MMC_CAP_SIGNALING_120;
79*8a8166e5SBartlomiej Grzesik 	if (device_has_property(dev, "mmc-hs200-1_8v"))
80*8a8166e5SBartlomiej Grzesik 		host->caps |= MMC_CAP_MMC_HS200_180 | MMC_CAP_SIGNALING_180;
81*8a8166e5SBartlomiej Grzesik 	if (device_has_property(dev, "mmc-hs400-1_2v"))
82*8a8166e5SBartlomiej Grzesik 		host->caps |= MMC_CAP_MMC_HS400_120 | MMC_CAP_SIGNALING_120;
83*8a8166e5SBartlomiej Grzesik 	if (device_has_property(dev, "mmc-hs400-1_8v"))
84*8a8166e5SBartlomiej Grzesik 		host->caps |= MMC_CAP_MMC_HS400_180 | MMC_CAP_SIGNALING_180;
85*8a8166e5SBartlomiej Grzesik 	if (device_has_property(dev, "mmc-hs400-enhanced-strobe"))
86*8a8166e5SBartlomiej Grzesik 		host->caps |= MMC_CAP_MMC_ENH_STROBE;
87*8a8166e5SBartlomiej Grzesik }
88*8a8166e5SBartlomiej Grzesik 
89*8a8166e5SBartlomiej Grzesik int
90*8a8166e5SBartlomiej Grzesik mmc_parse(device_t dev, struct mmc_helper *helper, struct mmc_host *host)
91*8a8166e5SBartlomiej Grzesik {
92*8a8166e5SBartlomiej Grzesik 	uint64_t bus_width, max_freq;
93*8a8166e5SBartlomiej Grzesik 
94*8a8166e5SBartlomiej Grzesik 	bus_width = 0;
95*8a8166e5SBartlomiej Grzesik 	if (device_get_property(dev, "bus-width", &bus_width, sizeof(uint64_t)) <= 0)
96*8a8166e5SBartlomiej Grzesik 		bus_width = 1;
97*8a8166e5SBartlomiej Grzesik 
98*8a8166e5SBartlomiej Grzesik 	if (bus_width >= 4)
99*8a8166e5SBartlomiej Grzesik 		host->caps |= MMC_CAP_4_BIT_DATA;
100*8a8166e5SBartlomiej Grzesik 	if (bus_width >= 8)
101*8a8166e5SBartlomiej Grzesik 		host->caps |= MMC_CAP_8_BIT_DATA;
102*8a8166e5SBartlomiej Grzesik 
103*8a8166e5SBartlomiej Grzesik 	/*
104*8a8166e5SBartlomiej Grzesik 	 * max-frequency is optional, drivers should tweak this value
105*8a8166e5SBartlomiej Grzesik 	 * if it's not present based on the clock that the mmc controller
106*8a8166e5SBartlomiej Grzesik 	 * operates on
107*8a8166e5SBartlomiej Grzesik 	 */
108*8a8166e5SBartlomiej Grzesik 	max_freq = 0;
109*8a8166e5SBartlomiej Grzesik 	device_get_property(dev, "max-frequency", &max_freq, sizeof(uint64_t));
110*8a8166e5SBartlomiej Grzesik 	host->f_max = max_freq;
111*8a8166e5SBartlomiej Grzesik 
112*8a8166e5SBartlomiej Grzesik 	if (device_has_property(dev, "broken-cd"))
113*8a8166e5SBartlomiej Grzesik 		helper->props |= MMC_PROP_BROKEN_CD;
114*8a8166e5SBartlomiej Grzesik 	if (device_has_property(dev, "non-removable"))
115*8a8166e5SBartlomiej Grzesik 		helper->props |= MMC_PROP_NON_REMOVABLE;
116*8a8166e5SBartlomiej Grzesik 	if (device_has_property(dev, "wp-inverted"))
117*8a8166e5SBartlomiej Grzesik 		helper->props |= MMC_PROP_WP_INVERTED;
118*8a8166e5SBartlomiej Grzesik 	if (device_has_property(dev, "cd-inverted"))
119*8a8166e5SBartlomiej Grzesik 		helper->props |= MMC_PROP_CD_INVERTED;
120*8a8166e5SBartlomiej Grzesik 	if (device_has_property(dev, "no-sdio"))
121*8a8166e5SBartlomiej Grzesik 		helper->props |= MMC_PROP_NO_SDIO;
122*8a8166e5SBartlomiej Grzesik 	if (device_has_property(dev, "no-sd"))
123*8a8166e5SBartlomiej Grzesik 		helper->props |= MMC_PROP_NO_SD;
124*8a8166e5SBartlomiej Grzesik 	if (device_has_property(dev, "no-mmc"))
125*8a8166e5SBartlomiej Grzesik 		helper->props |= MMC_PROP_NO_MMC;
126*8a8166e5SBartlomiej Grzesik 
127*8a8166e5SBartlomiej Grzesik 	if (!(helper->props & MMC_PROP_NO_SD))
128*8a8166e5SBartlomiej Grzesik 		mmc_parse_sd_speed(dev, host);
129*8a8166e5SBartlomiej Grzesik 
130*8a8166e5SBartlomiej Grzesik 	if (!(helper->props & MMC_PROP_NO_MMC))
131*8a8166e5SBartlomiej Grzesik 		mmc_parse_mmc_speed(dev, host);
132*8a8166e5SBartlomiej Grzesik 
133*8a8166e5SBartlomiej Grzesik 	return (0);
134*8a8166e5SBartlomiej Grzesik }
135