xref: /rk3399_rockchip-uboot/drivers/serial/serial-uclass.c (revision 57d92753d4cada5c314a7d6bcfe7ad79b00c2eb8)
1*57d92753SSimon Glass /*
2*57d92753SSimon Glass  * Copyright (c) 2014 The Chromium OS Authors.
3*57d92753SSimon Glass  *
4*57d92753SSimon Glass  * SPDX-License-Identifier:	GPL-2.0+
5*57d92753SSimon Glass  */
6*57d92753SSimon Glass 
7*57d92753SSimon Glass #include <common.h>
8*57d92753SSimon Glass #include <dm.h>
9*57d92753SSimon Glass #include <errno.h>
10*57d92753SSimon Glass #include <fdtdec.h>
11*57d92753SSimon Glass #include <os.h>
12*57d92753SSimon Glass #include <serial.h>
13*57d92753SSimon Glass #include <stdio_dev.h>
14*57d92753SSimon Glass #include <dm/lists.h>
15*57d92753SSimon Glass #include <dm/device-internal.h>
16*57d92753SSimon Glass 
17*57d92753SSimon Glass DECLARE_GLOBAL_DATA_PTR;
18*57d92753SSimon Glass 
19*57d92753SSimon Glass /* The currently-selected console serial device */
20*57d92753SSimon Glass struct udevice *cur_dev __attribute__ ((section(".data")));
21*57d92753SSimon Glass 
22*57d92753SSimon Glass #ifndef CONFIG_SYS_MALLOC_F_LEN
23*57d92753SSimon Glass #error "Serial is required before relocation - define CONFIG_SYS_MALLOC_F_LEN to make this work"
24*57d92753SSimon Glass #endif
25*57d92753SSimon Glass 
26*57d92753SSimon Glass static void serial_find_console_or_panic(void)
27*57d92753SSimon Glass {
28*57d92753SSimon Glass 	int node;
29*57d92753SSimon Glass 
30*57d92753SSimon Glass 	/* Check for a chosen console */
31*57d92753SSimon Glass 	node = fdtdec_get_chosen_node(gd->fdt_blob, "stdout-path");
32*57d92753SSimon Glass 	if (node < 0)
33*57d92753SSimon Glass 		node = fdtdec_get_alias_node(gd->fdt_blob, "console");
34*57d92753SSimon Glass 	if (!uclass_get_device_by_of_offset(UCLASS_SERIAL, node, &cur_dev))
35*57d92753SSimon Glass 		return;
36*57d92753SSimon Glass 
37*57d92753SSimon Glass 	/*
38*57d92753SSimon Glass 	 * If the console is not marked to be bound before relocation, bind
39*57d92753SSimon Glass 	 * it anyway.
40*57d92753SSimon Glass 	 */
41*57d92753SSimon Glass 	if (node > 0 &&
42*57d92753SSimon Glass 	    !lists_bind_fdt(gd->dm_root, gd->fdt_blob, node, &cur_dev)) {
43*57d92753SSimon Glass 		if (!device_probe(cur_dev))
44*57d92753SSimon Glass 			return;
45*57d92753SSimon Glass 		cur_dev = NULL;
46*57d92753SSimon Glass 	}
47*57d92753SSimon Glass 
48*57d92753SSimon Glass 	/*
49*57d92753SSimon Glass 	 * Failing that, get the device with sequence number 0, or in extremis
50*57d92753SSimon Glass 	 * just the first serial device we can find. But we insist on having
51*57d92753SSimon Glass 	 * a console (even if it is silent).
52*57d92753SSimon Glass 	 */
53*57d92753SSimon Glass 	if (uclass_get_device_by_seq(UCLASS_SERIAL, 0, &cur_dev) &&
54*57d92753SSimon Glass 	    (uclass_first_device(UCLASS_SERIAL, &cur_dev) || !cur_dev))
55*57d92753SSimon Glass 		panic("No serial driver found");
56*57d92753SSimon Glass }
57*57d92753SSimon Glass 
58*57d92753SSimon Glass /* Called prior to relocation */
59*57d92753SSimon Glass int serial_init(void)
60*57d92753SSimon Glass {
61*57d92753SSimon Glass 	serial_find_console_or_panic();
62*57d92753SSimon Glass 	gd->flags |= GD_FLG_SERIAL_READY;
63*57d92753SSimon Glass 
64*57d92753SSimon Glass 	return 0;
65*57d92753SSimon Glass }
66*57d92753SSimon Glass 
67*57d92753SSimon Glass /* Called after relocation */
68*57d92753SSimon Glass void serial_initialize(void)
69*57d92753SSimon Glass {
70*57d92753SSimon Glass 	serial_find_console_or_panic();
71*57d92753SSimon Glass }
72*57d92753SSimon Glass 
73*57d92753SSimon Glass void serial_putc(char ch)
74*57d92753SSimon Glass {
75*57d92753SSimon Glass 	struct dm_serial_ops *ops = serial_get_ops(cur_dev);
76*57d92753SSimon Glass 	int err;
77*57d92753SSimon Glass 
78*57d92753SSimon Glass 	do {
79*57d92753SSimon Glass 		err = ops->putc(cur_dev, ch);
80*57d92753SSimon Glass 	} while (err == -EAGAIN);
81*57d92753SSimon Glass 	if (ch == '\n')
82*57d92753SSimon Glass 		serial_putc('\r');
83*57d92753SSimon Glass }
84*57d92753SSimon Glass 
85*57d92753SSimon Glass void serial_setbrg(void)
86*57d92753SSimon Glass {
87*57d92753SSimon Glass 	struct dm_serial_ops *ops = serial_get_ops(cur_dev);
88*57d92753SSimon Glass 
89*57d92753SSimon Glass 	if (ops->setbrg)
90*57d92753SSimon Glass 		ops->setbrg(cur_dev, gd->baudrate);
91*57d92753SSimon Glass }
92*57d92753SSimon Glass 
93*57d92753SSimon Glass void serial_puts(const char *str)
94*57d92753SSimon Glass {
95*57d92753SSimon Glass 	while (*str)
96*57d92753SSimon Glass 		serial_putc(*str++);
97*57d92753SSimon Glass }
98*57d92753SSimon Glass 
99*57d92753SSimon Glass int serial_tstc(void)
100*57d92753SSimon Glass {
101*57d92753SSimon Glass 	struct dm_serial_ops *ops = serial_get_ops(cur_dev);
102*57d92753SSimon Glass 
103*57d92753SSimon Glass 	if (ops->pending)
104*57d92753SSimon Glass 		return ops->pending(cur_dev, true);
105*57d92753SSimon Glass 
106*57d92753SSimon Glass 	return 1;
107*57d92753SSimon Glass }
108*57d92753SSimon Glass 
109*57d92753SSimon Glass int serial_getc(void)
110*57d92753SSimon Glass {
111*57d92753SSimon Glass 	struct dm_serial_ops *ops = serial_get_ops(cur_dev);
112*57d92753SSimon Glass 	int err;
113*57d92753SSimon Glass 
114*57d92753SSimon Glass 	do {
115*57d92753SSimon Glass 		err = ops->getc(cur_dev);
116*57d92753SSimon Glass 	} while (err == -EAGAIN);
117*57d92753SSimon Glass 
118*57d92753SSimon Glass 	return err >= 0 ? err : 0;
119*57d92753SSimon Glass }
120*57d92753SSimon Glass 
121*57d92753SSimon Glass void serial_stdio_init(void)
122*57d92753SSimon Glass {
123*57d92753SSimon Glass }
124*57d92753SSimon Glass 
125*57d92753SSimon Glass void serial_stub_putc(struct stdio_dev *sdev, const char ch)
126*57d92753SSimon Glass {
127*57d92753SSimon Glass 	struct udevice *dev = sdev->priv;
128*57d92753SSimon Glass 	struct dm_serial_ops *ops = serial_get_ops(dev);
129*57d92753SSimon Glass 
130*57d92753SSimon Glass 	ops->putc(dev, ch);
131*57d92753SSimon Glass }
132*57d92753SSimon Glass 
133*57d92753SSimon Glass void serial_stub_puts(struct stdio_dev *sdev, const char *str)
134*57d92753SSimon Glass {
135*57d92753SSimon Glass 	while (*str)
136*57d92753SSimon Glass 		serial_stub_putc(sdev, *str++);
137*57d92753SSimon Glass }
138*57d92753SSimon Glass 
139*57d92753SSimon Glass int serial_stub_getc(struct stdio_dev *sdev)
140*57d92753SSimon Glass {
141*57d92753SSimon Glass 	struct udevice *dev = sdev->priv;
142*57d92753SSimon Glass 	struct dm_serial_ops *ops = serial_get_ops(dev);
143*57d92753SSimon Glass 
144*57d92753SSimon Glass 	int err;
145*57d92753SSimon Glass 
146*57d92753SSimon Glass 	do {
147*57d92753SSimon Glass 		err = ops->getc(dev);
148*57d92753SSimon Glass 	} while (err == -EAGAIN);
149*57d92753SSimon Glass 
150*57d92753SSimon Glass 	return err >= 0 ? err : 0;
151*57d92753SSimon Glass }
152*57d92753SSimon Glass 
153*57d92753SSimon Glass int serial_stub_tstc(struct stdio_dev *sdev)
154*57d92753SSimon Glass {
155*57d92753SSimon Glass 	struct udevice *dev = sdev->priv;
156*57d92753SSimon Glass 	struct dm_serial_ops *ops = serial_get_ops(dev);
157*57d92753SSimon Glass 
158*57d92753SSimon Glass 	if (ops->pending)
159*57d92753SSimon Glass 		return ops->pending(dev, true);
160*57d92753SSimon Glass 
161*57d92753SSimon Glass 	return 1;
162*57d92753SSimon Glass }
163*57d92753SSimon Glass 
164*57d92753SSimon Glass static int serial_post_probe(struct udevice *dev)
165*57d92753SSimon Glass {
166*57d92753SSimon Glass 	struct stdio_dev sdev;
167*57d92753SSimon Glass 	struct dm_serial_ops *ops = serial_get_ops(dev);
168*57d92753SSimon Glass 	struct serial_dev_priv *upriv = dev->uclass_priv;
169*57d92753SSimon Glass 	int ret;
170*57d92753SSimon Glass 
171*57d92753SSimon Glass 	/* Set the baud rate */
172*57d92753SSimon Glass 	if (ops->setbrg) {
173*57d92753SSimon Glass 		ret = ops->setbrg(dev, gd->baudrate);
174*57d92753SSimon Glass 		if (ret)
175*57d92753SSimon Glass 			return ret;
176*57d92753SSimon Glass 	}
177*57d92753SSimon Glass 
178*57d92753SSimon Glass 	if (!(gd->flags & GD_FLG_RELOC))
179*57d92753SSimon Glass 		return 0;
180*57d92753SSimon Glass 
181*57d92753SSimon Glass 	memset(&sdev, '\0', sizeof(sdev));
182*57d92753SSimon Glass 
183*57d92753SSimon Glass 	strncpy(sdev.name, dev->name, sizeof(sdev.name));
184*57d92753SSimon Glass 	sdev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT;
185*57d92753SSimon Glass 	sdev.priv = dev;
186*57d92753SSimon Glass 	sdev.putc = serial_stub_putc;
187*57d92753SSimon Glass 	sdev.puts = serial_stub_puts;
188*57d92753SSimon Glass 	sdev.getc = serial_stub_getc;
189*57d92753SSimon Glass 	sdev.tstc = serial_stub_tstc;
190*57d92753SSimon Glass 	stdio_register_dev(&sdev, &upriv->sdev);
191*57d92753SSimon Glass 
192*57d92753SSimon Glass 	return 0;
193*57d92753SSimon Glass }
194*57d92753SSimon Glass 
195*57d92753SSimon Glass static int serial_pre_remove(struct udevice *dev)
196*57d92753SSimon Glass {
197*57d92753SSimon Glass #ifdef CONFIG_SYS_STDIO_DEREGISTER
198*57d92753SSimon Glass 	struct serial_dev_priv *upriv = dev->uclass_priv;
199*57d92753SSimon Glass 
200*57d92753SSimon Glass 	if (stdio_deregister_dev(upriv->sdev))
201*57d92753SSimon Glass 		return -EPERM;
202*57d92753SSimon Glass #endif
203*57d92753SSimon Glass 
204*57d92753SSimon Glass 	return 0;
205*57d92753SSimon Glass }
206*57d92753SSimon Glass 
207*57d92753SSimon Glass UCLASS_DRIVER(serial) = {
208*57d92753SSimon Glass 	.id		= UCLASS_SERIAL,
209*57d92753SSimon Glass 	.name		= "serial",
210*57d92753SSimon Glass 	.post_probe	= serial_post_probe,
211*57d92753SSimon Glass 	.pre_remove	= serial_pre_remove,
212*57d92753SSimon Glass 	.per_device_auto_alloc_size = sizeof(struct serial_dev_priv),
213*57d92753SSimon Glass };
214