1 /*
2  * xen/drivers/char/arm-uart.c
3  *
4  * Generic uart retrieved via the device tree or ACPI
5  *
6  * Julien Grall <julien.grall@linaro.org>
7  * Copyright (c) 2013 Linaro Limited.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  */
19 
20 #include <asm/device.h>
21 #include <asm/types.h>
22 #include <xen/console.h>
23 #include <xen/device_tree.h>
24 #include <xen/serial.h>
25 #include <xen/errno.h>
26 #include <xen/acpi.h>
27 
28 /*
29  * Configure UART port with a string:
30  * path:options
31  *
32  * @path: full path used in the device tree for the UART. If the path
33  * doesn't start with '/', we assuming that it's an alias.
34  * @options: UART speficic options (see in each UART driver)
35  */
36 static char __initdata opt_dtuart[256] = "";
37 string_param("dtuart", opt_dtuart);
38 
dt_uart_init(void)39 static void __init dt_uart_init(void)
40 {
41     struct dt_device_node *dev;
42     int ret;
43     const char *devpath = opt_dtuart;
44     char *options;
45 
46     if ( !console_has("dtuart") )
47         return; /* Not for us */
48 
49     if ( !strcmp(opt_dtuart, "") )
50     {
51         const struct dt_device_node *chosen = dt_find_node_by_path("/chosen");
52 
53         if ( chosen )
54         {
55             const char *stdout;
56 
57             ret = dt_property_read_string(chosen, "stdout-path", &stdout);
58             if ( ret >= 0 )
59             {
60                 printk("Taking dtuart configuration from /chosen/stdout-path\n");
61                 if ( strlcpy(opt_dtuart, stdout, sizeof(opt_dtuart))
62                      >= sizeof(opt_dtuart) )
63                     printk("WARNING: /chosen/stdout-path too long, truncated\n");
64             }
65             else if ( ret != -EINVAL /* Not present */ )
66                 printk("Failed to read /chosen/stdout-path (%d)\n", ret);
67         }
68     }
69 
70     if ( !strcmp(opt_dtuart, "") )
71     {
72         printk("No dtuart path configured\n");
73         return;
74     }
75 
76     options = strchr(opt_dtuart, ':');
77     if ( options != NULL )
78         *(options++) = '\0';
79     else
80         options = "";
81 
82     printk("Looking for dtuart at \"%s\", options \"%s\"\n", devpath, options);
83     if ( *devpath == '/' )
84         dev = dt_find_node_by_path(devpath);
85     else
86         dev = dt_find_node_by_alias(devpath);
87 
88     if ( !dev )
89     {
90         printk("Unable to find device \"%s\"\n", devpath);
91         return;
92     }
93 
94     ret = device_init(dev, DEVICE_SERIAL, options);
95 
96     if ( ret )
97         printk("Unable to initialize dtuart: %d\n", ret);
98 }
99 
100 #ifdef CONFIG_ACPI
acpi_uart_init(void)101 static void __init acpi_uart_init(void)
102 {
103     struct acpi_table_spcr *spcr = NULL;
104     int ret;
105 
106     acpi_get_table(ACPI_SIG_SPCR, 0, (struct acpi_table_header **)&spcr);
107 
108     if ( spcr == NULL )
109     {
110         printk("Unable to get spcr table\n");
111     }
112     else
113     {
114         ret = acpi_device_init(DEVICE_SERIAL, NULL, spcr->interface_type);
115 
116         if ( ret )
117             printk("Unable to initialize acpi uart: %d\n", ret);
118     }
119 }
120 #else
acpi_uart_init(void)121 static void __init acpi_uart_init(void) { }
122 #endif
123 
arm_uart_init(void)124 void __init arm_uart_init(void)
125 {
126     if ( acpi_disabled )
127         dt_uart_init();
128     else
129         acpi_uart_init();
130 }
131 
132 /*
133  * Local variables:
134  * mode: C
135  * c-file-style: "BSD"
136  * c-basic-offset: 4
137  * tab-width: 4
138  * indent-tabs-mode: nil
139  * End:
140  */
141