xref: /freebsd/sys/dev/mmc/mmc_fdt_helpers.c (revision 16038816)
1 /*
2  * Copyright 2019 Emmanuel Vadot <manu@freebsd.org>
3  * Copyright (c) 2017 Ian Lepore <ian@freebsd.org> All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *  1. Redistributions of source code must retain the above copyright
10  *     notice, this list of conditions and the following disclaimer.
11  *  2. Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
19  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
22  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30 
31 #include <sys/param.h>
32 #include <sys/bus.h>
33 #include <sys/kernel.h>
34 #include <sys/gpio.h>
35 #include <sys/taskqueue.h>
36 
37 #include <dev/mmc/bridge.h>
38 #include <dev/mmc/mmc_fdt_helpers.h>
39 
40 #include <dev/gpio/gpiobusvar.h>
41 #include <dev/ofw/ofw_bus.h>
42 #include <dev/ofw/ofw_bus_subr.h>
43 
44 #ifdef EXT_RESOURCES
45 #include <dev/extres/regulator/regulator.h>
46 #endif
47 
48 #include "mmc_pwrseq_if.h"
49 
50 static inline void
51 mmc_fdt_parse_sd_speed(phandle_t node, struct mmc_host *host)
52 {
53 	bool no_18v = false;
54 
55 	/*
56 	 * Parse SD supported modes
57 	 * All UHS-I modes requires 1.8V signaling.
58 	 */
59 	if (OF_hasprop(node, "no1-8-v"))
60 		no_18v = true;
61 	if (OF_hasprop(node, "cap-sd-highspeed"))
62 		host->caps |= MMC_CAP_HSPEED;
63 	if (OF_hasprop(node, "sd-uhs-sdr12") && no_18v == false)
64 		host->caps |= MMC_CAP_UHS_SDR12 | MMC_CAP_SIGNALING_180;
65 	if (OF_hasprop(node, "sd-uhs-sdr25") && no_18v == false)
66 		host->caps |= MMC_CAP_UHS_SDR25 | MMC_CAP_SIGNALING_180;
67 	if (OF_hasprop(node, "sd-uhs-sdr50") && no_18v == false)
68 		host->caps |= MMC_CAP_UHS_SDR50 | MMC_CAP_SIGNALING_180;
69 	if (OF_hasprop(node, "sd-uhs-sdr104") && no_18v == false)
70 		host->caps |= MMC_CAP_UHS_SDR104 | MMC_CAP_SIGNALING_180;
71 	if (OF_hasprop(node, "sd-uhs-ddr50") && no_18v == false)
72 		host->caps |= MMC_CAP_UHS_DDR50 | MMC_CAP_SIGNALING_180;
73 }
74 
75 static inline void
76 mmc_fdt_parse_mmc_speed(phandle_t node, struct mmc_host *host)
77 {
78 
79 	/* Parse eMMC supported modes */
80 	if (OF_hasprop(node, "cap-mmc-highspeed"))
81 		host->caps |= MMC_CAP_HSPEED;
82 	if (OF_hasprop(node, "mmc-ddr-1_2v"))
83 		host->caps |= MMC_CAP_MMC_DDR52_120 | MMC_CAP_SIGNALING_120;
84 	if (OF_hasprop(node, "mmc-ddr-1_8v"))
85 		host->caps |= MMC_CAP_MMC_DDR52_180 | MMC_CAP_SIGNALING_180;
86 	if (OF_hasprop(node, "mmc-ddr-3_3v"))
87 		host->caps |= MMC_CAP_SIGNALING_330;
88 	if (OF_hasprop(node, "mmc-hs200-1_2v"))
89 		host->caps |= MMC_CAP_MMC_HS200_120 | MMC_CAP_SIGNALING_120;
90 	if (OF_hasprop(node, "mmc-hs200-1_8v"))
91 		host->caps |= MMC_CAP_MMC_HS200_180 | MMC_CAP_SIGNALING_180;
92 	if (OF_hasprop(node, "mmc-hs400-1_2v"))
93 		host->caps |= MMC_CAP_MMC_HS400_120 | MMC_CAP_SIGNALING_120;
94 	if (OF_hasprop(node, "mmc-hs400-1_8v"))
95 		host->caps |= MMC_CAP_MMC_HS400_180 | MMC_CAP_SIGNALING_180;
96 	if (OF_hasprop(node, "mmc-hs400-enhanced-strobe"))
97 		host->caps |= MMC_CAP_MMC_ENH_STROBE;
98 }
99 
100 int
101 mmc_fdt_parse(device_t dev, phandle_t node, struct mmc_fdt_helper *helper,
102     struct mmc_host *host)
103 {
104 	uint32_t bus_width;
105 	phandle_t pwrseq_xref;
106 
107 	if (node <= 0)
108 		node = ofw_bus_get_node(dev);
109 	if (node <= 0)
110 		return (ENXIO);
111 
112 	if (OF_getencprop(node, "bus-width", &bus_width, sizeof(uint32_t)) <= 0)
113 		bus_width = 1;
114 
115 	if (bus_width >= 4)
116 		host->caps |= MMC_CAP_4_BIT_DATA;
117 	if (bus_width >= 8)
118 		host->caps |= MMC_CAP_8_BIT_DATA;
119 
120 	/*
121 	 * max-frequency is optional, drivers should tweak this value
122 	 * if it's not present based on the clock that the mmc controller
123 	 * operates on
124 	 */
125 	OF_getencprop(node, "max-frequency", &host->f_max, sizeof(uint32_t));
126 
127 	if (OF_hasprop(node, "broken-cd"))
128 		helper->props |= MMC_PROP_BROKEN_CD;
129 	if (OF_hasprop(node, "non-removable"))
130 		helper->props |= MMC_PROP_NON_REMOVABLE;
131 	if (OF_hasprop(node, "wp-inverted"))
132 		helper->props |= MMC_PROP_WP_INVERTED;
133 	if (OF_hasprop(node, "cd-inverted"))
134 		helper->props |= MMC_PROP_CD_INVERTED;
135 	if (OF_hasprop(node, "no-sdio"))
136 		helper->props |= MMC_PROP_NO_SDIO;
137 	if (OF_hasprop(node, "no-sd"))
138 		helper->props |= MMC_PROP_NO_SD;
139 	if (OF_hasprop(node, "no-mmc"))
140 		helper->props |= MMC_PROP_NO_MMC;
141 
142 	if (!(helper->props & MMC_PROP_NO_SD))
143 		mmc_fdt_parse_sd_speed(node, host);
144 
145 	if (!(helper->props & MMC_PROP_NO_MMC))
146 		mmc_fdt_parse_mmc_speed(node, host);
147 
148 #ifdef EXT_RESOURCES
149 	/*
150 	 * Get the regulators if they are supported and
151 	 * clean the non supported modes based on the available voltages.
152 	 */
153 	if (regulator_get_by_ofw_property(dev, 0, "vmmc-supply",
154 	    &helper->vmmc_supply) == 0) {
155 		if (bootverbose)
156 			device_printf(dev, "vmmc-supply regulator found\n");
157 	}
158 	if (regulator_get_by_ofw_property(dev, 0, "vqmmc-supply",
159 	    &helper->vqmmc_supply) == 0 && bootverbose) {
160 		if (bootverbose)
161 			device_printf(dev, "vqmmc-supply regulator found\n");
162 	}
163 
164 	if (helper->vqmmc_supply != NULL) {
165 		if (regulator_check_voltage(helper->vqmmc_supply, 1200000) == 0)
166 			host->caps |= MMC_CAP_SIGNALING_120;
167 		else
168 			host->caps &= ~( MMC_CAP_MMC_HS400_120 |
169 			    MMC_CAP_MMC_HS200_120 |
170 			    MMC_CAP_MMC_DDR52_120);
171 		if (regulator_check_voltage(helper->vqmmc_supply, 1800000) == 0)
172 			host->caps |= MMC_CAP_SIGNALING_180;
173 		else
174 			host->caps &= ~(MMC_CAP_MMC_HS400_180 |
175 			    MMC_CAP_MMC_HS200_180 |
176 			    MMC_CAP_MMC_DDR52_180 |
177 			    MMC_CAP_UHS_DDR50 |
178 			    MMC_CAP_UHS_SDR104 |
179 			    MMC_CAP_UHS_SDR50 |
180 			    MMC_CAP_UHS_SDR25);
181 		if (regulator_check_voltage(helper->vqmmc_supply, 3300000) == 0)
182 			host->caps |= MMC_CAP_SIGNALING_330;
183 	} else
184 		host->caps |= MMC_CAP_SIGNALING_330;
185 #endif
186 
187 	if (OF_hasprop(node, "mmc-pwrseq")) {
188 		if (OF_getencprop(node, "mmc-pwrseq", &pwrseq_xref, sizeof(pwrseq_xref)) == -1) {
189 			device_printf(dev, "Cannot get the pwrseq_xref property\n");
190 			return (ENXIO);
191 		}
192 		helper->mmc_pwrseq = OF_device_from_xref(pwrseq_xref);
193 	}
194 	return (0);
195 }
196 
197 /*
198  * Card detect interrupt handler.
199  */
200 static void
201 cd_intr(void *arg)
202 {
203 	struct mmc_fdt_helper *helper = arg;
204 
205 	taskqueue_enqueue_timeout(taskqueue_swi_giant,
206 	    &helper->cd_delayed_task, -(hz / 2));
207 }
208 
209 static void
210 cd_card_task(void *arg, int pending __unused)
211 {
212 	struct mmc_fdt_helper *helper = arg;
213 	bool cd_present;
214 
215 	cd_present = mmc_fdt_gpio_get_present(helper);
216 	if(helper->cd_handler && cd_present != helper->cd_present)
217 		helper->cd_handler(helper->dev,
218 		    cd_present);
219 	helper->cd_present = cd_present;
220 
221 	/* If we're polling re-schedule the task */
222 	if (helper->cd_ihandler == NULL)
223 		taskqueue_enqueue_timeout_sbt(taskqueue_swi_giant,
224 		    &helper->cd_delayed_task, mstosbt(500), 0, C_PREL(2));
225 }
226 
227 /*
228  * Card detect setup.
229  */
230 static void
231 cd_setup(struct mmc_fdt_helper *helper, phandle_t node)
232 {
233 	int pincaps;
234 	device_t dev;
235 	const char *cd_mode_str;
236 
237 	dev = helper->dev;
238 
239 	TIMEOUT_TASK_INIT(taskqueue_swi_giant, &helper->cd_delayed_task, 0,
240 	    cd_card_task, helper);
241 
242 	/*
243 	 * If the device is flagged as non-removable, set that slot option, and
244 	 * set a flag to make sdhci_fdt_gpio_get_present() always return true.
245 	 */
246 	if (helper->props & MMC_PROP_NON_REMOVABLE) {
247 		helper->cd_disabled = true;
248 		if (bootverbose)
249 			device_printf(dev, "Non-removable media\n");
250 		return;
251 	}
252 
253 	/*
254 	 * If there is no cd-gpios property, then presumably the hardware
255 	 * PRESENT_STATE register and interrupts will reflect card state
256 	 * properly, and there's nothing more for us to do.  Our get_present()
257 	 * will return sdhci_generic_get_card_present() because cd_pin is NULL.
258 	 *
259 	 * If there is a property, make sure we can read the pin.
260 	 */
261 	if (gpio_pin_get_by_ofw_property(dev, node, "cd-gpios",
262 	    &helper->cd_pin))
263 		return;
264 
265 	if (gpio_pin_getcaps(helper->cd_pin, &pincaps) != 0 ||
266 	    !(pincaps & GPIO_PIN_INPUT)) {
267 		device_printf(dev, "Cannot read card-detect gpio pin; "
268 		    "setting card-always-present flag.\n");
269 		helper->cd_disabled = true;
270 		return;
271 	}
272 
273 	/*
274 	 * If the pin can trigger an interrupt on both rising and falling edges,
275 	 * we can use it to detect card presence changes.  If not, we'll request
276 	 * card presence polling instead of using interrupts.
277 	 */
278 	if (!(pincaps & GPIO_INTR_EDGE_BOTH)) {
279 		if (bootverbose)
280 			device_printf(dev, "Cannot configure "
281 			    "GPIO_INTR_EDGE_BOTH for card detect\n");
282 		goto without_interrupts;
283 	}
284 
285 	if (helper->cd_handler == NULL) {
286 		if (bootverbose)
287 			device_printf(dev, "Cannot configure "
288 			    "interrupts as no cd_handler is set\n");
289 		goto without_interrupts;
290 	}
291 
292 	/*
293 	 * Create an interrupt resource from the pin and set up the interrupt.
294 	 */
295 	if ((helper->cd_ires = gpio_alloc_intr_resource(dev, &helper->cd_irid,
296 	    RF_ACTIVE, helper->cd_pin, GPIO_INTR_EDGE_BOTH)) == NULL) {
297 		if (bootverbose)
298 			device_printf(dev, "Cannot allocate an IRQ for card "
299 			    "detect GPIO\n");
300 		goto without_interrupts;
301 	}
302 
303 	if (bus_setup_intr(dev, helper->cd_ires, INTR_TYPE_BIO | INTR_MPSAFE,
304 	    NULL, cd_intr, helper, &helper->cd_ihandler) != 0) {
305 		device_printf(dev, "Unable to setup card-detect irq handler\n");
306 		helper->cd_ihandler = NULL;
307 		goto without_interrupts;
308 	}
309 
310 without_interrupts:
311 	/*
312 	 * If we have a readable gpio pin, but didn't successfully configure
313 	 * gpio interrupts, setup a timeout task to poll the pin
314 	 */
315 	if (helper->cd_ihandler == NULL) {
316 		cd_mode_str = "polling";
317 	} else {
318 		cd_mode_str = "interrupts";
319 	}
320 
321 	if (bootverbose) {
322 		device_printf(dev, "Card presence detect on %s pin %u, "
323 		    "configured for %s.\n",
324 		    device_get_nameunit(helper->cd_pin->dev), helper->cd_pin->pin,
325 		    cd_mode_str);
326 	}
327 }
328 
329 /*
330  * Write protect setup.
331  */
332 static void
333 wp_setup(struct mmc_fdt_helper *helper, phandle_t node)
334 {
335 	device_t dev;
336 
337 	dev = helper->dev;
338 
339 	if (OF_hasprop(node, "disable-wp")) {
340 		helper->wp_disabled = true;
341 		if (bootverbose)
342 			device_printf(dev, "Write protect disabled\n");
343 		return;
344 	}
345 
346 	if (gpio_pin_get_by_ofw_property(dev, node, "wp-gpios", &helper->wp_pin))
347 		return;
348 
349 	if (bootverbose)
350 		device_printf(dev, "Write protect switch on %s pin %u\n",
351 		    device_get_nameunit(helper->wp_pin->dev), helper->wp_pin->pin);
352 }
353 
354 int
355 mmc_fdt_gpio_setup(device_t dev, phandle_t node, struct mmc_fdt_helper *helper,
356     mmc_fdt_cd_handler handler)
357 {
358 
359 	if (node <= 0)
360 		node = ofw_bus_get_node(dev);
361 	if (node <= 0) {
362 		device_printf(dev, "Cannot get node for device\n");
363 		return (ENXIO);
364 	}
365 
366 	helper->dev = dev;
367 	helper->cd_handler = handler;
368 	cd_setup(helper, node);
369 	wp_setup(helper, node);
370 
371 	/*
372 	 * Schedule a card detection
373 	 */
374 	taskqueue_enqueue_timeout_sbt(taskqueue_swi_giant,
375 	    &helper->cd_delayed_task, mstosbt(500), 0, C_PREL(2));
376 	return (0);
377 }
378 
379 void
380 mmc_fdt_gpio_teardown(struct mmc_fdt_helper *helper)
381 {
382 
383 	if (helper == NULL)
384 		return;
385 
386 	if (helper->cd_ihandler != NULL)
387 		bus_teardown_intr(helper->dev, helper->cd_ires, helper->cd_ihandler);
388 	if (helper->wp_pin != NULL)
389 		gpio_pin_release(helper->wp_pin);
390 	if (helper->cd_pin != NULL)
391 		gpio_pin_release(helper->cd_pin);
392 	if (helper->cd_ires != NULL)
393 		bus_release_resource(helper->dev, SYS_RES_IRQ, 0, helper->cd_ires);
394 
395 	taskqueue_drain_timeout(taskqueue_swi_giant, &helper->cd_delayed_task);
396 }
397 
398 bool
399 mmc_fdt_gpio_get_present(struct mmc_fdt_helper *helper)
400 {
401 	bool pinstate;
402 
403 	if (helper->cd_disabled)
404 		return (true);
405 	if (helper->cd_pin == NULL)
406 		return (false);
407 
408 	gpio_pin_is_active(helper->cd_pin, &pinstate);
409 
410 	return (pinstate ^ (bool)(helper->props & MMC_PROP_CD_INVERTED));
411 }
412 
413 bool
414 mmc_fdt_gpio_get_readonly(struct mmc_fdt_helper *helper)
415 {
416 	bool pinstate;
417 
418 	if (helper->wp_disabled)
419 		return (false);
420 
421 	if (helper->wp_pin == NULL)
422 		return (false);
423 
424 	gpio_pin_is_active(helper->wp_pin, &pinstate);
425 
426 	return (pinstate ^ (bool)(helper->props & MMC_PROP_WP_INVERTED));
427 }
428 
429 void
430 mmc_fdt_set_power(struct mmc_fdt_helper *helper, enum mmc_power_mode power_mode)
431 {
432 	int reg_status;
433 	int rv;
434 
435 	switch (power_mode) {
436 	case power_on:
437 		break;
438 	case power_off:
439 		if (helper->vmmc_supply) {
440 			rv = regulator_status(helper->vmmc_supply, &reg_status);
441 			if (rv == 0 && reg_status == REGULATOR_STATUS_ENABLED)
442 				regulator_disable(helper->vmmc_supply);
443 		}
444 		if (helper->vqmmc_supply) {
445 			rv = regulator_status(helper->vqmmc_supply, &reg_status);
446 			if (rv == 0 && reg_status == REGULATOR_STATUS_ENABLED)
447 				regulator_disable(helper->vqmmc_supply);
448 		}
449 		if (helper->mmc_pwrseq)
450 			MMC_PWRSEQ_SET_POWER(helper->mmc_pwrseq, false);
451 		break;
452 	case power_up:
453 		if (helper->vmmc_supply) {
454 			rv = regulator_status(helper->vmmc_supply, &reg_status);
455 			if (rv == 0 && reg_status != REGULATOR_STATUS_ENABLED)
456 				regulator_enable(helper->vmmc_supply);
457 		}
458 		if (helper->vqmmc_supply) {
459 			rv = regulator_status(helper->vqmmc_supply, &reg_status);
460 			if (rv == 0 && reg_status != REGULATOR_STATUS_ENABLED)
461 				regulator_enable(helper->vqmmc_supply);
462 		}
463 		if (helper->mmc_pwrseq)
464 			MMC_PWRSEQ_SET_POWER(helper->mmc_pwrseq, true);
465 		break;
466 	}
467 }
468