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/param.h>
25 #include <xen/serial.h>
26 #include <xen/errno.h>
27 #include <xen/acpi.h>
28 
29 /*
30  * Configure UART port with a string:
31  * path:options
32  *
33  * @path: full path used in the device tree for the UART. If the path
34  * doesn't start with '/', we assuming that it's an alias.
35  * @options: UART speficic options (see in each UART driver)
36  */
37 static char __initdata opt_dtuart[256] = "";
38 string_param("dtuart", opt_dtuart);
39 
dt_uart_init(void)40 static void __init dt_uart_init(void)
41 {
42     struct dt_device_node *dev;
43     int ret;
44     const char *devpath = opt_dtuart;
45     char *options;
46 
47     if ( !console_has("dtuart") )
48         return; /* Not for us */
49 
50     if ( !strcmp(opt_dtuart, "") )
51     {
52         const struct dt_device_node *chosen = dt_find_node_by_path("/chosen");
53 
54         if ( chosen )
55         {
56             const char *stdout;
57 
58             ret = dt_property_read_string(chosen, "stdout-path", &stdout);
59             if ( ret >= 0 )
60             {
61                 printk("Taking dtuart configuration from /chosen/stdout-path\n");
62                 if ( strlcpy(opt_dtuart, stdout, sizeof(opt_dtuart))
63                      >= sizeof(opt_dtuart) )
64                     printk("WARNING: /chosen/stdout-path too long, truncated\n");
65             }
66             else if ( ret != -EINVAL /* Not present */ )
67                 printk("Failed to read /chosen/stdout-path (%d)\n", ret);
68         }
69     }
70 
71     if ( !strcmp(opt_dtuart, "") )
72     {
73         printk("No dtuart path configured\n");
74         return;
75     }
76 
77     options = strchr(opt_dtuart, ':');
78     if ( options != NULL )
79         *(options++) = '\0';
80     else
81         options = "";
82 
83     printk("Looking for dtuart at \"%s\", options \"%s\"\n", devpath, options);
84     if ( *devpath == '/' )
85         dev = dt_find_node_by_path(devpath);
86     else
87         dev = dt_find_node_by_alias(devpath);
88 
89     if ( !dev )
90     {
91         printk("Unable to find device \"%s\"\n", devpath);
92         return;
93     }
94 
95     ret = device_init(dev, DEVICE_SERIAL, options);
96 
97     if ( ret )
98         printk("Unable to initialize dtuart: %d\n", ret);
99 }
100 
101 #ifdef CONFIG_ACPI
acpi_uart_init(void)102 static void __init acpi_uart_init(void)
103 {
104     struct acpi_table_spcr *spcr = NULL;
105     int ret;
106 
107     acpi_get_table(ACPI_SIG_SPCR, 0, (struct acpi_table_header **)&spcr);
108 
109     if ( spcr == NULL )
110     {
111         printk("Unable to get spcr table\n");
112     }
113     else
114     {
115         ret = acpi_device_init(DEVICE_SERIAL, NULL, spcr->interface_type);
116 
117         if ( ret )
118             printk("Unable to initialize acpi uart: %d\n", ret);
119     }
120 }
121 #else
acpi_uart_init(void)122 static void __init acpi_uart_init(void) { }
123 #endif
124 
arm_uart_init(void)125 void __init arm_uart_init(void)
126 {
127     if ( acpi_disabled )
128         dt_uart_init();
129     else
130         acpi_uart_init();
131 }
132 
133 /*
134  * Local variables:
135  * mode: C
136  * c-file-style: "BSD"
137  * c-basic-offset: 4
138  * tab-width: 4
139  * indent-tabs-mode: nil
140  * End:
141  */
142