1*2874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2656ad58eSOliver O'Halloran /*
3656ad58eSOliver O'Halloran * Copyright (c) 2016 IBM Corporation.
4656ad58eSOliver O'Halloran */
5656ad58eSOliver O'Halloran
6656ad58eSOliver O'Halloran #include "ops.h"
7656ad58eSOliver O'Halloran #include "stdio.h"
8656ad58eSOliver O'Halloran #include "io.h"
9656ad58eSOliver O'Halloran #include <libfdt.h>
10656ad58eSOliver O'Halloran #include "../include/asm/opal-api.h"
11656ad58eSOliver O'Halloran
12656ad58eSOliver O'Halloran /* Global OPAL struct used by opal-call.S */
13656ad58eSOliver O'Halloran struct opal {
14656ad58eSOliver O'Halloran u64 base;
15656ad58eSOliver O'Halloran u64 entry;
16656ad58eSOliver O'Halloran } opal;
17656ad58eSOliver O'Halloran
18656ad58eSOliver O'Halloran static u32 opal_con_id;
19656ad58eSOliver O'Halloran
20a1ff5741SOliver O'Halloran /* see opal-wrappers.S */
21656ad58eSOliver O'Halloran int64_t opal_console_write(int64_t term_number, u64 *length, const u8 *buffer);
22656ad58eSOliver O'Halloran int64_t opal_console_read(int64_t term_number, uint64_t *length, u8 *buffer);
23656ad58eSOliver O'Halloran int64_t opal_console_write_buffer_space(uint64_t term_number, uint64_t *length);
24656ad58eSOliver O'Halloran int64_t opal_console_flush(uint64_t term_number);
25656ad58eSOliver O'Halloran int64_t opal_poll_events(uint64_t *outstanding_event_mask);
26656ad58eSOliver O'Halloran
27a1ff5741SOliver O'Halloran void opal_kentry(unsigned long fdt_addr, void *vmlinux_addr);
28a1ff5741SOliver O'Halloran
opal_con_open(void)29656ad58eSOliver O'Halloran static int opal_con_open(void)
30656ad58eSOliver O'Halloran {
31a1ff5741SOliver O'Halloran /*
32a1ff5741SOliver O'Halloran * When OPAL loads the boot kernel it stashes the OPAL base and entry
33a1ff5741SOliver O'Halloran * address in r8 and r9 so the kernel can use the OPAL console
34a1ff5741SOliver O'Halloran * before unflattening the devicetree. While executing the wrapper will
35a1ff5741SOliver O'Halloran * probably trash r8 and r9 so this kentry hook restores them before
36a1ff5741SOliver O'Halloran * entering the decompressed kernel.
37a1ff5741SOliver O'Halloran */
38a1ff5741SOliver O'Halloran platform_ops.kentry = opal_kentry;
39656ad58eSOliver O'Halloran return 0;
40656ad58eSOliver O'Halloran }
41656ad58eSOliver O'Halloran
opal_con_putc(unsigned char c)42656ad58eSOliver O'Halloran static void opal_con_putc(unsigned char c)
43656ad58eSOliver O'Halloran {
44656ad58eSOliver O'Halloran int64_t rc;
45656ad58eSOliver O'Halloran uint64_t olen, len;
46656ad58eSOliver O'Halloran
47656ad58eSOliver O'Halloran do {
48656ad58eSOliver O'Halloran rc = opal_console_write_buffer_space(opal_con_id, &olen);
49656ad58eSOliver O'Halloran len = be64_to_cpu(olen);
50656ad58eSOliver O'Halloran if (rc)
51656ad58eSOliver O'Halloran return;
52656ad58eSOliver O'Halloran opal_poll_events(NULL);
53656ad58eSOliver O'Halloran } while (len < 1);
54656ad58eSOliver O'Halloran
55656ad58eSOliver O'Halloran
56656ad58eSOliver O'Halloran olen = cpu_to_be64(1);
57656ad58eSOliver O'Halloran opal_console_write(opal_con_id, &olen, &c);
58656ad58eSOliver O'Halloran }
59656ad58eSOliver O'Halloran
opal_con_close(void)60656ad58eSOliver O'Halloran static void opal_con_close(void)
61656ad58eSOliver O'Halloran {
62656ad58eSOliver O'Halloran opal_console_flush(opal_con_id);
63656ad58eSOliver O'Halloran }
64656ad58eSOliver O'Halloran
opal_init(void)65656ad58eSOliver O'Halloran static void opal_init(void)
66656ad58eSOliver O'Halloran {
67656ad58eSOliver O'Halloran void *opal_node;
68656ad58eSOliver O'Halloran
69656ad58eSOliver O'Halloran opal_node = finddevice("/ibm,opal");
70656ad58eSOliver O'Halloran if (!opal_node)
71656ad58eSOliver O'Halloran return;
72656ad58eSOliver O'Halloran if (getprop(opal_node, "opal-base-address", &opal.base, sizeof(u64)) < 0)
73656ad58eSOliver O'Halloran return;
74656ad58eSOliver O'Halloran opal.base = be64_to_cpu(opal.base);
75656ad58eSOliver O'Halloran if (getprop(opal_node, "opal-entry-address", &opal.entry, sizeof(u64)) < 0)
76656ad58eSOliver O'Halloran return;
77656ad58eSOliver O'Halloran opal.entry = be64_to_cpu(opal.entry);
78656ad58eSOliver O'Halloran }
79656ad58eSOliver O'Halloran
opal_console_init(void * devp,struct serial_console_data * scdp)80656ad58eSOliver O'Halloran int opal_console_init(void *devp, struct serial_console_data *scdp)
81656ad58eSOliver O'Halloran {
82656ad58eSOliver O'Halloran opal_init();
83656ad58eSOliver O'Halloran
84656ad58eSOliver O'Halloran if (devp) {
85656ad58eSOliver O'Halloran int n = getprop(devp, "reg", &opal_con_id, sizeof(u32));
86656ad58eSOliver O'Halloran if (n != sizeof(u32))
87656ad58eSOliver O'Halloran return -1;
88656ad58eSOliver O'Halloran opal_con_id = be32_to_cpu(opal_con_id);
89656ad58eSOliver O'Halloran } else
90656ad58eSOliver O'Halloran opal_con_id = 0;
91656ad58eSOliver O'Halloran
92656ad58eSOliver O'Halloran scdp->open = opal_con_open;
93656ad58eSOliver O'Halloran scdp->putc = opal_con_putc;
94656ad58eSOliver O'Halloran scdp->close = opal_con_close;
95656ad58eSOliver O'Halloran
96656ad58eSOliver O'Halloran return 0;
97656ad58eSOliver O'Halloran }
98