powerpc/powernv: Support for OPAL console
[pandora-kernel.git] / arch / powerpc / platforms / powernv / opal.c
1 /*
2  * PowerNV OPAL high level interfaces
3  *
4  * Copyright 2011 IBM Corp.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version
9  * 2 of the License, or (at your option) any later version.
10  */
11
12 #undef DEBUG
13
14 #include <linux/types.h>
15 #include <linux/of.h>
16 #include <linux/of_platform.h>
17 #include <asm/opal.h>
18 #include <asm/firmware.h>
19
20 #include "powernv.h"
21
22 struct opal {
23         u64 base;
24         u64 entry;
25 } opal;
26
27 static struct device_node *opal_node;
28 static DEFINE_SPINLOCK(opal_write_lock);
29
30 int __init early_init_dt_scan_opal(unsigned long node,
31                                    const char *uname, int depth, void *data)
32 {
33         const void *basep, *entryp;
34         unsigned long basesz, entrysz;
35
36         if (depth != 1 || strcmp(uname, "ibm,opal") != 0)
37                 return 0;
38
39         basep  = of_get_flat_dt_prop(node, "opal-base-address", &basesz);
40         entryp = of_get_flat_dt_prop(node, "opal-entry-address", &entrysz);
41
42         if (!basep || !entryp)
43                 return 1;
44
45         opal.base = of_read_number(basep, basesz/4);
46         opal.entry = of_read_number(entryp, entrysz/4);
47
48         pr_debug("OPAL Base  = 0x%llx (basep=%p basesz=%ld)\n",
49                  opal.base, basep, basesz);
50         pr_debug("OPAL Entry = 0x%llx (entryp=%p basesz=%ld)\n",
51                  opal.entry, entryp, entrysz);
52
53         powerpc_firmware_features |= FW_FEATURE_OPAL;
54         if (of_flat_dt_is_compatible(node, "ibm,opal-v2")) {
55                 powerpc_firmware_features |= FW_FEATURE_OPALv2;
56                 printk("OPAL V2 detected !\n");
57         } else {
58                 printk("OPAL V1 detected !\n");
59         }
60
61         return 1;
62 }
63
64 int opal_get_chars(uint32_t vtermno, char *buf, int count)
65 {
66         s64 len, rc;
67         u64 evt;
68
69         if (!opal.entry)
70                 return -ENODEV;
71         opal_poll_events(&evt);
72         if ((evt & OPAL_EVENT_CONSOLE_INPUT) == 0)
73                 return 0;
74         len = count;
75         rc = opal_console_read(vtermno, &len, buf);
76         if (rc == OPAL_SUCCESS)
77                 return len;
78         return 0;
79 }
80
81 int opal_put_chars(uint32_t vtermno, const char *data, int total_len)
82 {
83         int written = 0;
84         s64 len, rc;
85         unsigned long flags;
86         u64 evt;
87
88         if (!opal.entry)
89                 return -ENODEV;
90
91         /* We want put_chars to be atomic to avoid mangling of hvsi
92          * packets. To do that, we first test for room and return
93          * -EAGAIN if there isn't enough.
94          *
95          * Unfortunately, opal_console_write_buffer_space() doesn't
96          * appear to work on opal v1, so we just assume there is
97          * enough room and be done with it
98          */
99         spin_lock_irqsave(&opal_write_lock, flags);
100         if (firmware_has_feature(FW_FEATURE_OPALv2)) {
101                 rc = opal_console_write_buffer_space(vtermno, &len);
102                 if (rc || len < total_len) {
103                         spin_unlock_irqrestore(&opal_write_lock, flags);
104                         /* Closed -> drop characters */
105                         if (rc)
106                                 return total_len;
107                         opal_poll_events(&evt);
108                         return -EAGAIN;
109                 }
110         }
111
112         /* We still try to handle partial completions, though they
113          * should no longer happen.
114          */
115         rc = OPAL_BUSY;
116         while(total_len > 0 && (rc == OPAL_BUSY ||
117                                 rc == OPAL_BUSY_EVENT || rc == OPAL_SUCCESS)) {
118                 len = total_len;
119                 rc = opal_console_write(vtermno, &len, data);
120                 if (rc == OPAL_SUCCESS) {
121                         total_len -= len;
122                         data += len;
123                         written += len;
124                 }
125                 /* This is a bit nasty but we need that for the console to
126                  * flush when there aren't any interrupts. We will clean
127                  * things a bit later to limit that to synchronous path
128                  * such as the kernel console and xmon/udbg
129                  */
130                 do
131                         opal_poll_events(&evt);
132                 while(rc == OPAL_SUCCESS && (evt & OPAL_EVENT_CONSOLE_OUTPUT));
133         }
134         spin_unlock_irqrestore(&opal_write_lock, flags);
135         return written;
136 }
137
138 static int __init opal_init(void)
139 {
140         struct device_node *np, *consoles;
141
142         opal_node = of_find_node_by_path("/ibm,opal");
143         if (!opal_node) {
144                 pr_warn("opal: Node not found\n");
145                 return -ENODEV;
146         }
147         if (firmware_has_feature(FW_FEATURE_OPALv2))
148                 consoles = of_find_node_by_path("/ibm,opal/consoles");
149         else
150                 consoles = of_node_get(opal_node);
151
152         /* Register serial ports */
153         for_each_child_of_node(consoles, np) {
154                 if (strcmp(np->name, "serial"))
155                         continue;
156                 of_platform_device_create(np, NULL, NULL);
157         }
158         of_node_put(consoles);
159         return 0;
160 }
161 subsys_initcall(opal_init);