1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Copyright (c) 2016 IBM Corporation. |
4 | */ |
5 | |
6 | #include "ops.h" |
7 | #include "stdio.h" |
8 | #include "io.h" |
9 | #include <libfdt.h> |
10 | #include "../include/asm/opal-api.h" |
11 | |
12 | /* Global OPAL struct used by opal-call.S */ |
13 | struct opal { |
14 | u64 base; |
15 | u64 entry; |
16 | } opal; |
17 | |
18 | static u32 opal_con_id; |
19 | |
20 | /* see opal-wrappers.S */ |
21 | int64_t opal_console_write(int64_t term_number, u64 *length, const u8 *buffer); |
22 | int64_t opal_console_read(int64_t term_number, uint64_t *length, u8 *buffer); |
23 | int64_t opal_console_write_buffer_space(uint64_t term_number, uint64_t *length); |
24 | int64_t opal_console_flush(uint64_t term_number); |
25 | int64_t opal_poll_events(uint64_t *outstanding_event_mask); |
26 | |
27 | void opal_kentry(unsigned long fdt_addr, void *vmlinux_addr); |
28 | |
29 | static int opal_con_open(void) |
30 | { |
31 | /* |
32 | * When OPAL loads the boot kernel it stashes the OPAL base and entry |
33 | * address in r8 and r9 so the kernel can use the OPAL console |
34 | * before unflattening the devicetree. While executing the wrapper will |
35 | * probably trash r8 and r9 so this kentry hook restores them before |
36 | * entering the decompressed kernel. |
37 | */ |
38 | platform_ops.kentry = opal_kentry; |
39 | return 0; |
40 | } |
41 | |
42 | static void opal_con_putc(unsigned char c) |
43 | { |
44 | int64_t rc; |
45 | uint64_t olen, len; |
46 | |
47 | do { |
48 | rc = opal_console_write_buffer_space(term_number: opal_con_id, length: &olen); |
49 | len = be64_to_cpu(olen); |
50 | if (rc) |
51 | return; |
52 | opal_poll_events(NULL); |
53 | } while (len < 1); |
54 | |
55 | |
56 | olen = cpu_to_be64(1); |
57 | opal_console_write(term_number: opal_con_id, length: &olen, buffer: &c); |
58 | } |
59 | |
60 | static void opal_con_close(void) |
61 | { |
62 | opal_console_flush(term_number: opal_con_id); |
63 | } |
64 | |
65 | static void opal_init(void) |
66 | { |
67 | void *opal_node; |
68 | |
69 | opal_node = finddevice(name: "/ibm,opal" ); |
70 | if (!opal_node) |
71 | return; |
72 | if (getprop(devp: opal_node, name: "opal-base-address" , buf: &opal.base, buflen: sizeof(u64)) < 0) |
73 | return; |
74 | opal.base = be64_to_cpu(opal.base); |
75 | if (getprop(devp: opal_node, name: "opal-entry-address" , buf: &opal.entry, buflen: sizeof(u64)) < 0) |
76 | return; |
77 | opal.entry = be64_to_cpu(opal.entry); |
78 | } |
79 | |
80 | int opal_console_init(void *devp, struct serial_console_data *scdp) |
81 | { |
82 | opal_init(); |
83 | |
84 | if (devp) { |
85 | int n = getprop(devp, name: "reg" , buf: &opal_con_id, buflen: sizeof(u32)); |
86 | if (n != sizeof(u32)) |
87 | return -1; |
88 | opal_con_id = be32_to_cpu(opal_con_id); |
89 | } else |
90 | opal_con_id = 0; |
91 | |
92 | scdp->open = opal_con_open; |
93 | scdp->putc = opal_con_putc; |
94 | scdp->close = opal_con_close; |
95 | |
96 | return 0; |
97 | } |
98 | |