blob: 7887733b9b31731dbdd3d08749436d9451863c88 [file] [log] [blame]
Benjamin Herrenschmidt14a43e62011-09-19 17:44:57 +00001/*
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
22struct opal {
23 u64 base;
24 u64 entry;
25} opal;
26
27static struct device_node *opal_node;
28static DEFINE_SPINLOCK(opal_write_lock);
29
30int __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
64int opal_get_chars(uint32_t vtermno, char *buf, int count)
65{
66 s64 len, rc;
67 u64 evt;
68
69 if (!opal.entry)
Benjamin Herrenschmidtdaea1172011-09-19 17:44:59 +000070 return -ENODEV;
Benjamin Herrenschmidt14a43e62011-09-19 17:44:57 +000071 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
81int opal_put_chars(uint32_t vtermno, const char *data, int total_len)
82{
83 int written = 0;
Benjamin Herrenschmidtdaea1172011-09-19 17:44:59 +000084 s64 len, rc;
Benjamin Herrenschmidt14a43e62011-09-19 17:44:57 +000085 unsigned long flags;
86 u64 evt;
87
88 if (!opal.entry)
Benjamin Herrenschmidtdaea1172011-09-19 17:44:59 +000089 return -ENODEV;
Benjamin Herrenschmidt14a43e62011-09-19 17:44:57 +000090
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
Benjamin Herrenschmidtdaea1172011-09-19 17:44:59 +000093 * -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
Benjamin Herrenschmidt14a43e62011-09-19 17:44:57 +000098 */
99 spin_lock_irqsave(&opal_write_lock, flags);
Benjamin Herrenschmidtdaea1172011-09-19 17:44:59 +0000100 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 }
Benjamin Herrenschmidt14a43e62011-09-19 17:44:57 +0000110 }
111
112 /* We still try to handle partial completions, though they
113 * should no longer happen.
114 */
Benjamin Herrenschmidtdaea1172011-09-19 17:44:59 +0000115 rc = OPAL_BUSY;
Benjamin Herrenschmidt14a43e62011-09-19 17:44:57 +0000116 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
138static 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}
161subsys_initcall(opal_init);