blob: b900a60c2a9c25c18fff0ab5e2b0fc22ab253631 [file] [log] [blame]
Joel Stanleyb314cb52017-06-07 14:51:57 +09301From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
Joel Stanley2b0f7b42016-07-19 23:26:28 +09302From: Oliver O'Halloran <oohall@gmail.com>
3Date: Fri, 24 Jun 2016 17:28:43 +1000
Joel Stanleyb314cb52017-06-07 14:51:57 +09304Subject: [PATCH 06/11] powerpc/boot: Add OPAL console to epapr wrappers
Joel Stanley2b0f7b42016-07-19 23:26:28 +09305
6This patch adds an OPAL console backend to the powerpc boot wrapper so
7that decompression failures inside the wrapper can be reported to the
8user. This is important since it typically indicates data corruption in
9the firmware and other nasty things.
10
11Currently this only works when building a little endian kernel. When
12compiling a 64 bit BE kernel the wrapper is always build 32 bit to be
13compatible with some 32 bit firmwares. BE support will be added at a
14later date. Another limitation of this is that only the "raw" type of
15OPAL console is supported, however machines that provide a hvsi console
16also provide a raw console so this is not an issue in practice.
17
18Actually-written-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
19Signed-off-by: Oliver O'Halloran <oohall@gmail.com>
20Cc: Stewart Smith <stewart@linux.vnet.ibm.com>
21Signed-off-by: Joel Stanley <joel@jms.id.au>
Samuel Mendoza-Jonas7d8f5b92017-10-17 14:16:45 +110022Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>
Joel Stanley2b0f7b42016-07-19 23:26:28 +093023---
24 arch/powerpc/boot/Makefile | 4 +-
25 arch/powerpc/boot/opal-calls.S | 58 +++++++++++++++++++++++++
26 arch/powerpc/boot/opal.c | 97 ++++++++++++++++++++++++++++++++++++++++++
27 arch/powerpc/boot/ops.h | 1 +
28 arch/powerpc/boot/ppc_asm.h | 4 ++
29 arch/powerpc/boot/serial.c | 2 +
30 arch/powerpc/boot/types.h | 10 +++++
31 7 files changed, 174 insertions(+), 2 deletions(-)
32 create mode 100644 arch/powerpc/boot/opal-calls.S
33 create mode 100644 arch/powerpc/boot/opal.c
34
35diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
36index 99e4487248ff..321a603f6ae3 100644
37--- a/arch/powerpc/boot/Makefile
38+++ b/arch/powerpc/boot/Makefile
39@@ -70,7 +70,7 @@ $(addprefix $(obj)/,$(zlib) cuboot-c2k.o gunzip_util.o main.o): \
40 libfdt := fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c
41 libfdtheader := fdt.h libfdt.h libfdt_internal.h
42
43-$(addprefix $(obj)/,$(libfdt) libfdt-wrapper.o simpleboot.o epapr.o): \
44+$(addprefix $(obj)/,$(libfdt) libfdt-wrapper.o simpleboot.o epapr.o opal.o): \
45 $(addprefix $(obj)/,$(libfdtheader))
46
47 src-wlib-y := string.S crt0.S crtsavres.S stdio.c main.c \
48@@ -78,7 +78,7 @@ src-wlib-y := string.S crt0.S crtsavres.S stdio.c main.c \
49 ns16550.c serial.c simple_alloc.c div64.S util.S \
50 gunzip_util.c elf_util.c $(zlib) devtree.c stdlib.c \
51 oflib.c ofconsole.c cuboot.c mpsc.c cpm-serial.c \
52- uartlite.c mpc52xx-psc.c
53+ uartlite.c mpc52xx-psc.c opal.c opal-calls.S
54 src-wlib-$(CONFIG_40x) += 4xx.c planetcore.c
55 src-wlib-$(CONFIG_44x) += 4xx.c ebony.c bamboo.c
56 src-wlib-$(CONFIG_8xx) += mpc8xx.c planetcore.c fsl-soc.c
57diff --git a/arch/powerpc/boot/opal-calls.S b/arch/powerpc/boot/opal-calls.S
58new file mode 100644
59index 000000000000..ff2f1b97bc53
60--- /dev/null
61+++ b/arch/powerpc/boot/opal-calls.S
62@@ -0,0 +1,58 @@
63+/*
64+ * Copyright (c) 2016 IBM Corporation.
65+ *
66+ * This program is free software; you can redistribute it and/or
67+ * modify it under the terms of the GNU General Public License
68+ * as published by the Free Software Foundation; either version
69+ * 2 of the License, or (at your option) any later version.
70+ */
71+
72+#include "ppc_asm.h"
73+#include "../include/asm/opal-api.h"
74+
75+ .text
76+
77+#define OPAL_CALL(name, token) \
78+ .globl name; \
79+name: \
80+ li r0, token; \
81+ b opal_call;
82+
83+opal_call:
84+ mflr r11
85+ std r11,16(r1)
86+ mfcr r12
87+ stw r12,8(r1)
88+ mr r13,r2
89+
90+ /* Set opal return address */
91+ ld r11,opal_return@got(r2)
92+ mtlr r11
93+ mfmsr r12
94+
95+ /* switch to BE when we enter OPAL */
96+ li r11,MSR_LE
97+ andc r12,r12,r11
98+ mtspr SPRN_HSRR1,r12
99+
100+ /* load the opal call entry point and base */
101+ ld r11,opal@got(r2)
102+ ld r12,8(r11)
103+ ld r2,0(r11)
104+ mtspr SPRN_HSRR0,r12
105+ hrfid
106+
107+opal_return:
108+ FIXUP_ENDIAN
109+ mr r2,r13;
110+ lwz r11,8(r1);
111+ ld r12,16(r1)
112+ mtcr r11;
113+ mtlr r12
114+ blr
115+
116+OPAL_CALL(opal_console_write, OPAL_CONSOLE_WRITE);
117+OPAL_CALL(opal_console_read, OPAL_CONSOLE_READ);
118+OPAL_CALL(opal_console_write_buffer_space, OPAL_CONSOLE_WRITE_BUFFER_SPACE);
119+OPAL_CALL(opal_poll_events, OPAL_POLL_EVENTS);
120+OPAL_CALL(opal_console_flush, OPAL_CONSOLE_FLUSH);
121diff --git a/arch/powerpc/boot/opal.c b/arch/powerpc/boot/opal.c
122new file mode 100644
123index 000000000000..3a2ce1e1f048
124--- /dev/null
125+++ b/arch/powerpc/boot/opal.c
126@@ -0,0 +1,97 @@
127+/*
128+ * Copyright (c) 2016 IBM Corporation.
129+ *
130+ * This program is free software; you can redistribute it and/or
131+ * modify it under the terms of the GNU General Public License
132+ * as published by the Free Software Foundation; either version
133+ * 2 of the License, or (at your option) any later version.
134+ */
135+
136+#include "ops.h"
137+#include "stdio.h"
138+#include "io.h"
139+#include <libfdt.h>
140+#include "../include/asm/opal-api.h"
141+
142+/* Global OPAL struct used by opal-call.S */
143+struct opal {
144+ u64 base;
145+ u64 entry;
146+} opal;
147+
148+static u32 opal_con_id;
149+
150+int64_t opal_console_write(int64_t term_number, u64 *length, const u8 *buffer);
151+int64_t opal_console_read(int64_t term_number, uint64_t *length, u8 *buffer);
152+int64_t opal_console_write_buffer_space(uint64_t term_number, uint64_t *length);
153+int64_t opal_console_flush(uint64_t term_number);
154+int64_t opal_poll_events(uint64_t *outstanding_event_mask);
155+
156+static int opal_con_open(void)
157+{
158+ return 0;
159+}
160+
161+static void opal_con_putc(unsigned char c)
162+{
163+ int64_t rc;
164+ uint64_t olen, len;
165+
166+ do {
167+ rc = opal_console_write_buffer_space(opal_con_id, &olen);
168+ len = be64_to_cpu(olen);
169+ if (rc)
170+ return;
171+ opal_poll_events(NULL);
172+ } while (len < 1);
173+
174+
175+ olen = cpu_to_be64(1);
176+ opal_console_write(opal_con_id, &olen, &c);
177+}
178+
179+static void opal_con_close(void)
180+{
181+ opal_console_flush(opal_con_id);
182+}
183+
184+static void opal_init(void)
185+{
186+ void *opal_node;
187+
188+ opal_node = finddevice("/ibm,opal");
189+ if (!opal_node)
190+ return;
191+ if (getprop(opal_node, "opal-base-address", &opal.base, sizeof(u64)) < 0)
192+ return;
193+ opal.base = be64_to_cpu(opal.base);
194+ if (getprop(opal_node, "opal-entry-address", &opal.entry, sizeof(u64)) < 0)
195+ return;
196+ opal.entry = be64_to_cpu(opal.entry);
197+}
198+
199+#ifdef __powerpc64__
200+int opal_console_init(void *devp, struct serial_console_data *scdp)
201+{
202+ opal_init();
203+
204+ if (devp) {
205+ int n = getprop(devp, "reg", &opal_con_id, sizeof(u32));
206+ if (n != sizeof(u32))
207+ return -1;
208+ opal_con_id = be32_to_cpu(opal_con_id);
209+ } else
210+ opal_con_id = 0;
211+
212+ scdp->open = opal_con_open;
213+ scdp->putc = opal_con_putc;
214+ scdp->close = opal_con_close;
215+
216+ return 0;
217+}
218+#else
219+int opal_console_init(void *devp, struct serial_console_data *scdp)
220+{
221+ return -1;
222+}
223+#endif
224diff --git a/arch/powerpc/boot/ops.h b/arch/powerpc/boot/ops.h
225index 5e75e1c5518e..e19b64ef977a 100644
226--- a/arch/powerpc/boot/ops.h
227+++ b/arch/powerpc/boot/ops.h
228@@ -89,6 +89,7 @@ int mpsc_console_init(void *devp, struct serial_console_data *scdp);
229 int cpm_console_init(void *devp, struct serial_console_data *scdp);
230 int mpc5200_psc_console_init(void *devp, struct serial_console_data *scdp);
231 int uartlite_console_init(void *devp, struct serial_console_data *scdp);
232+int opal_console_init(void *devp, struct serial_console_data *scdp);
233 void *simple_alloc_init(char *base, unsigned long heap_size,
234 unsigned long granularity, unsigned long max_allocs);
235 extern void flush_cache(void *, unsigned long);
236diff --git a/arch/powerpc/boot/ppc_asm.h b/arch/powerpc/boot/ppc_asm.h
237index 35ea60c1f070..b03373d8b386 100644
238--- a/arch/powerpc/boot/ppc_asm.h
239+++ b/arch/powerpc/boot/ppc_asm.h
240@@ -61,6 +61,10 @@
241
242 #define SPRN_TBRL 268
243 #define SPRN_TBRU 269
244+#define SPRN_HSRR0 0x13A /* Hypervisor Save/Restore 0 */
245+#define SPRN_HSRR1 0x13B /* Hypervisor Save/Restore 1 */
246+
247+#define MSR_LE 0x0000000000000001
248
249 #define FIXUP_ENDIAN \
250 tdi 0, 0, 0x48; /* Reverse endian of b . + 8 */ \
251diff --git a/arch/powerpc/boot/serial.c b/arch/powerpc/boot/serial.c
252index 167ee9433de6..e04c1e4063ae 100644
253--- a/arch/powerpc/boot/serial.c
254+++ b/arch/powerpc/boot/serial.c
255@@ -132,6 +132,8 @@ int serial_console_init(void)
256 else if (dt_is_compatible(devp, "xlnx,opb-uartlite-1.00.b") ||
257 dt_is_compatible(devp, "xlnx,xps-uartlite-1.00.a"))
258 rc = uartlite_console_init(devp, &serial_cd);
259+ else if (dt_is_compatible(devp, "ibm,opal-console-raw"))
260+ rc = opal_console_init(devp, &serial_cd);
261
262 /* Add other serial console driver calls here */
263
264diff --git a/arch/powerpc/boot/types.h b/arch/powerpc/boot/types.h
265index 31393d17a9c1..85565a89bcc2 100644
266--- a/arch/powerpc/boot/types.h
267+++ b/arch/powerpc/boot/types.h
268@@ -12,6 +12,16 @@ typedef short s16;
269 typedef int s32;
270 typedef long long s64;
271
272+/* required for opal-api.h */
273+typedef u8 uint8_t;
274+typedef u16 uint16_t;
275+typedef u32 uint32_t;
276+typedef u64 uint64_t;
277+typedef s8 int8_t;
278+typedef s16 int16_t;
279+typedef s32 int32_t;
280+typedef s64 int64_t;
281+
282 #define min(x,y) ({ \
283 typeof(x) _x = (x); \
284 typeof(y) _y = (y); \