serial_efi.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright (c) 2015 Google, Inc
  4. * Written by Simon Glass <sjg@chromium.org>
  5. */
  6. #include <common.h>
  7. #include <debug_uart.h>
  8. #include <dm.h>
  9. #include <efi.h>
  10. #include <efi_api.h>
  11. #include <errno.h>
  12. #include <fdtdec.h>
  13. #include <linux/compiler.h>
  14. #include <asm/io.h>
  15. #include <serial.h>
  16. /* Information about the efi console */
  17. struct serial_efi_priv {
  18. struct efi_simple_input_interface *con_in;
  19. struct efi_simple_text_output_protocol *con_out;
  20. struct efi_input_key key;
  21. bool have_key;
  22. };
  23. int serial_efi_setbrg(struct udevice *dev, int baudrate)
  24. {
  25. return 0;
  26. }
  27. static int serial_efi_get_key(struct serial_efi_priv *priv)
  28. {
  29. int ret;
  30. if (priv->have_key)
  31. return 0;
  32. ret = priv->con_in->read_key_stroke(priv->con_in, &priv->key);
  33. if (ret == EFI_NOT_READY)
  34. return -EAGAIN;
  35. else if (ret != EFI_SUCCESS)
  36. return -EIO;
  37. priv->have_key = true;
  38. return 0;
  39. }
  40. static int serial_efi_getc(struct udevice *dev)
  41. {
  42. struct serial_efi_priv *priv = dev_get_priv(dev);
  43. int ret, ch;
  44. ret = serial_efi_get_key(priv);
  45. if (ret)
  46. return ret;
  47. priv->have_key = false;
  48. ch = priv->key.unicode_char;
  49. /*
  50. * Unicode char 8 (for backspace) is never returned. Instead we get a
  51. * key scan code of 8. Handle this so that backspace works correctly
  52. * in the U-Boot command line.
  53. */
  54. if (!ch && priv->key.scan_code == 8)
  55. ch = 8;
  56. debug(" [%x %x %x] ", ch, priv->key.unicode_char, priv->key.scan_code);
  57. return ch;
  58. }
  59. static int serial_efi_putc(struct udevice *dev, const char ch)
  60. {
  61. struct serial_efi_priv *priv = dev_get_priv(dev);
  62. uint16_t ucode[2];
  63. int ret;
  64. ucode[0] = ch;
  65. ucode[1] = '\0';
  66. ret = priv->con_out->output_string(priv->con_out, ucode);
  67. if (ret)
  68. return -EIO;
  69. return 0;
  70. }
  71. static int serial_efi_pending(struct udevice *dev, bool input)
  72. {
  73. struct serial_efi_priv *priv = dev_get_priv(dev);
  74. int ret;
  75. /* We assume that EFI will stall if its output buffer fills up */
  76. if (!input)
  77. return 0;
  78. ret = serial_efi_get_key(priv);
  79. if (ret == -EAGAIN)
  80. return 0;
  81. else if (ret)
  82. return ret;
  83. return 1;
  84. }
  85. /*
  86. * There is nothing to init here since the EFI console is already running by
  87. * the time we enter U-Boot.
  88. */
  89. static inline void _debug_uart_init(void)
  90. {
  91. }
  92. static inline void _debug_uart_putc(int ch)
  93. {
  94. struct efi_system_table *sys_table = efi_get_sys_table();
  95. uint16_t ucode[2];
  96. ucode[0] = ch;
  97. ucode[1] = '\0';
  98. sys_table->con_out->output_string(sys_table->con_out, ucode);
  99. }
  100. DEBUG_UART_FUNCS
  101. static int serial_efi_probe(struct udevice *dev)
  102. {
  103. struct efi_system_table *table = efi_get_sys_table();
  104. struct serial_efi_priv *priv = dev_get_priv(dev);
  105. priv->con_in = table->con_in;
  106. priv->con_out = table->con_out;
  107. return 0;
  108. }
  109. static const struct dm_serial_ops serial_efi_ops = {
  110. .putc = serial_efi_putc,
  111. .getc = serial_efi_getc,
  112. .pending = serial_efi_pending,
  113. .setbrg = serial_efi_setbrg,
  114. };
  115. static const struct udevice_id serial_efi_ids[] = {
  116. { .compatible = "efi,uart" },
  117. { }
  118. };
  119. U_BOOT_DRIVER(serial_efi) = {
  120. .name = "serial_efi",
  121. .id = UCLASS_SERIAL,
  122. .of_match = serial_efi_ids,
  123. .priv_auto_alloc_size = sizeof(struct serial_efi_priv),
  124. .probe = serial_efi_probe,
  125. .ops = &serial_efi_ops,
  126. .flags = DM_FLAG_PRE_RELOC,
  127. };