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