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(opal_con_id, &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(opal_con_id, &olen, &c); 58 } 59 60 static void opal_con_close(void) 61 { 62 opal_console_flush(opal_con_id); 63 } 64 65 static void opal_init(void) 66 { 67 void *opal_node; 68 69 opal_node = finddevice("/ibm,opal"); 70 if (!opal_node) 71 return; 72 if (getprop(opal_node, "opal-base-address", &opal.base, sizeof(u64)) < 0) 73 return; 74 opal.base = be64_to_cpu(opal.base); 75 if (getprop(opal_node, "opal-entry-address", &opal.entry, 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, "reg", &opal_con_id, 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