serial_efi.c 3.4 KB

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