opal.c 2.2 KB

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