1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2018 Alexander Graf <agraf@suse.de>
4  */
5 
6 #include <common.h>
7 #include <dm.h>
8 #include <asm/gpio.h>
9 #include <dm/pinctrl.h>
10 #include <dm/platform_data/serial_pl01x.h>
11 #include <serial.h>
12 #include "serial_pl01x_internal.h"
13 
14 /*
15  * Check if this serial device is muxed
16  *
17  * The serial device will only work properly if it has been muxed to the serial
18  * pins by firmware. Check whether that happened here.
19  *
20  * Return: true if serial device is muxed, false if not
21  */
bcm283x_is_serial_muxed(void)22 static bool bcm283x_is_serial_muxed(void)
23 {
24 	int serial_gpio = 15;
25 	struct udevice *dev;
26 
27 	if (uclass_first_device_err(UCLASS_PINCTRL, &dev))
28 		return false;
29 
30 	if (pinctrl_get_gpio_mux(dev, 0, serial_gpio) != BCM2835_GPIO_ALT0)
31 		return false;
32 
33 	return true;
34 }
35 
bcm283x_pl011_serial_probe(struct udevice * dev)36 static int bcm283x_pl011_serial_probe(struct udevice *dev)
37 {
38 	struct pl01x_serial_plat *plat = dev_get_plat(dev);
39 	int ret;
40 
41 	/* Don't spawn the device if it's not muxed */
42 	if (!bcm283x_is_serial_muxed())
43 		return -ENODEV;
44 
45 	/*
46 	 * Read the ofdata here rather than in an of_to_plat() method
47 	 * since we need the soc simple-bus to be probed so that the 'ranges'
48 	 * property is used.
49 	 */
50 	ret = pl01x_serial_of_to_plat(dev);
51 	if (ret)
52 		return ret;
53 
54 	/*
55 	 * TODO: Reinitialization doesn't always work for now, just skip
56 	 *       init always - we know we're already initialized
57 	 */
58 	plat->skip_init = true;
59 
60 	return pl01x_serial_probe(dev);
61 }
62 
bcm283x_pl011_serial_setbrg(struct udevice * dev,int baudrate)63 static int bcm283x_pl011_serial_setbrg(struct udevice *dev, int baudrate)
64 {
65 	int r;
66 
67 	r = pl01x_serial_setbrg(dev, baudrate);
68 
69 	/*
70 	 * We may have been muxed to a bogus line before. Drain the RX
71 	 * queue so we start at a clean slate.
72 	 */
73 	while (pl01x_serial_getc(dev) != -EAGAIN) ;
74 
75 	return r;
76 }
77 
78 static const struct dm_serial_ops bcm283x_pl011_serial_ops = {
79 	.putc = pl01x_serial_putc,
80 	.pending = pl01x_serial_pending,
81 	.getc = pl01x_serial_getc,
82 	.setbrg = bcm283x_pl011_serial_setbrg,
83 };
84 
85 static const struct udevice_id bcm283x_pl011_serial_id[] = {
86 	{.compatible = "brcm,bcm2835-pl011", .data = TYPE_PL011},
87 	{}
88 };
89 
90 U_BOOT_DRIVER(bcm283x_pl011_uart) = {
91 	.name	= "bcm283x_pl011",
92 	.id	= UCLASS_SERIAL,
93 	.of_match = of_match_ptr(bcm283x_pl011_serial_id),
94 	.probe	= bcm283x_pl011_serial_probe,
95 	.plat_auto	= sizeof(struct pl01x_serial_plat),
96 	.ops	= &bcm283x_pl011_serial_ops,
97 #if !CONFIG_IS_ENABLED(OF_CONTROL) || IS_ENABLED(CONFIG_OF_BOARD)
98 	.flags	= DM_FLAG_PRE_RELOC,
99 #endif
100 	.priv_auto	= sizeof(struct pl01x_priv),
101 };
102