linux/arch/powerpc/boot/opal.c
<<
>>
Prefs
   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 */
  13struct opal {
  14        u64 base;
  15        u64 entry;
  16} opal;
  17
  18static u32 opal_con_id;
  19
  20/* see opal-wrappers.S */
  21int64_t opal_console_write(int64_t term_number, u64 *length, const u8 *buffer);
  22int64_t opal_console_read(int64_t term_number, uint64_t *length, u8 *buffer);
  23int64_t opal_console_write_buffer_space(uint64_t term_number, uint64_t *length);
  24int64_t opal_console_flush(uint64_t term_number);
  25int64_t opal_poll_events(uint64_t *outstanding_event_mask);
  26
  27void opal_kentry(unsigned long fdt_addr, void *vmlinux_addr);
  28
  29static 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
  42static 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
  60static void opal_con_close(void)
  61{
  62        opal_console_flush(opal_con_id);
  63}
  64
  65static 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
  80int 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