serial_htif.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright (C) 2022 Ventana Micro Systems Inc.
  4. */
  5. #include <common.h>
  6. #include <dm.h>
  7. #include <errno.h>
  8. #include <fdtdec.h>
  9. #include <log.h>
  10. #include <watchdog.h>
  11. #include <asm/global_data.h>
  12. #include <asm/io.h>
  13. #include <linux/compiler.h>
  14. #include <serial.h>
  15. #include <linux/err.h>
  16. DECLARE_GLOBAL_DATA_PTR;
  17. #define HTIF_DATA_BITS 48
  18. #define HTIF_DATA_MASK ((1ULL << HTIF_DATA_BITS) - 1)
  19. #define HTIF_DATA_SHIFT 0
  20. #define HTIF_CMD_BITS 8
  21. #define HTIF_CMD_MASK ((1ULL << HTIF_CMD_BITS) - 1)
  22. #define HTIF_CMD_SHIFT 48
  23. #define HTIF_DEV_BITS 8
  24. #define HTIF_DEV_MASK ((1ULL << HTIF_DEV_BITS) - 1)
  25. #define HTIF_DEV_SHIFT 56
  26. #define HTIF_DEV_SYSTEM 0
  27. #define HTIF_DEV_CONSOLE 1
  28. #define HTIF_CONSOLE_CMD_GETC 0
  29. #define HTIF_CONSOLE_CMD_PUTC 1
  30. #if __riscv_xlen == 64
  31. # define TOHOST_CMD(dev, cmd, payload) \
  32. (((u64)(dev) << HTIF_DEV_SHIFT) | \
  33. ((u64)(cmd) << HTIF_CMD_SHIFT) | \
  34. (u64)(payload))
  35. #else
  36. # define TOHOST_CMD(dev, cmd, payload) ({ \
  37. if ((dev) || (cmd)) \
  38. __builtin_trap(); \
  39. (payload); })
  40. #endif
  41. #define FROMHOST_DEV(fromhost_value) \
  42. ((u64)((fromhost_value) >> HTIF_DEV_SHIFT) & HTIF_DEV_MASK)
  43. #define FROMHOST_CMD(fromhost_value) \
  44. ((u64)((fromhost_value) >> HTIF_CMD_SHIFT) & HTIF_CMD_MASK)
  45. #define FROMHOST_DATA(fromhost_value) \
  46. ((u64)((fromhost_value) >> HTIF_DATA_SHIFT) & HTIF_DATA_MASK)
  47. struct htif_plat {
  48. void *fromhost;
  49. void *tohost;
  50. int console_char;
  51. };
  52. static void __check_fromhost(struct htif_plat *plat)
  53. {
  54. u64 fh = readq(plat->fromhost);
  55. if (!fh)
  56. return;
  57. writeq(0, plat->fromhost);
  58. /* this should be from the console */
  59. if (FROMHOST_DEV(fh) != HTIF_DEV_CONSOLE)
  60. __builtin_trap();
  61. switch (FROMHOST_CMD(fh)) {
  62. case HTIF_CONSOLE_CMD_GETC:
  63. plat->console_char = 1 + (u8)FROMHOST_DATA(fh);
  64. break;
  65. case HTIF_CONSOLE_CMD_PUTC:
  66. break;
  67. default:
  68. __builtin_trap();
  69. }
  70. }
  71. static void __set_tohost(struct htif_plat *plat,
  72. u64 dev, u64 cmd, u64 data)
  73. {
  74. while (readq(plat->tohost))
  75. __check_fromhost(plat);
  76. writeq(TOHOST_CMD(dev, cmd, data), plat->tohost);
  77. }
  78. static int htif_serial_putc(struct udevice *dev, const char ch)
  79. {
  80. struct htif_plat *plat = dev_get_plat(dev);
  81. __set_tohost(plat, HTIF_DEV_CONSOLE, HTIF_CONSOLE_CMD_PUTC, ch);
  82. return 0;
  83. }
  84. static int htif_serial_getc(struct udevice *dev)
  85. {
  86. int ch;
  87. struct htif_plat *plat = dev_get_plat(dev);
  88. if (plat->console_char < 0)
  89. __check_fromhost(plat);
  90. if (plat->console_char >= 0) {
  91. ch = plat->console_char;
  92. plat->console_char = -1;
  93. __set_tohost(plat, HTIF_DEV_CONSOLE, HTIF_CONSOLE_CMD_GETC, 0);
  94. return (ch) ? ch - 1 : -EAGAIN;
  95. }
  96. return -EAGAIN;
  97. }
  98. static int htif_serial_pending(struct udevice *dev, bool input)
  99. {
  100. struct htif_plat *plat = dev_get_plat(dev);
  101. if (!input)
  102. return 0;
  103. if (plat->console_char < 0)
  104. __check_fromhost(plat);
  105. return (plat->console_char >= 0) ? 1 : 0;
  106. }
  107. static int htif_serial_probe(struct udevice *dev)
  108. {
  109. struct htif_plat *plat = dev_get_plat(dev);
  110. /* Queue first getc request */
  111. __set_tohost(plat, HTIF_DEV_CONSOLE, HTIF_CONSOLE_CMD_GETC, 0);
  112. return 0;
  113. }
  114. static int htif_serial_of_to_plat(struct udevice *dev)
  115. {
  116. fdt_addr_t addr;
  117. struct htif_plat *plat = dev_get_plat(dev);
  118. addr = dev_read_addr_index(dev, 0);
  119. if (addr == FDT_ADDR_T_NONE)
  120. return -ENODEV;
  121. plat->fromhost = (void *)(uintptr_t)addr;
  122. plat->tohost = plat->fromhost + sizeof(u64);
  123. addr = dev_read_addr_index(dev, 1);
  124. if (addr != FDT_ADDR_T_NONE)
  125. plat->tohost = (void *)(uintptr_t)addr;
  126. plat->console_char = -1;
  127. return 0;
  128. }
  129. static const struct dm_serial_ops htif_serial_ops = {
  130. .putc = htif_serial_putc,
  131. .getc = htif_serial_getc,
  132. .pending = htif_serial_pending,
  133. };
  134. static const struct udevice_id htif_serial_ids[] = {
  135. { .compatible = "ucb,htif0" },
  136. { }
  137. };
  138. U_BOOT_DRIVER(serial_htif) = {
  139. .name = "serial_htif",
  140. .id = UCLASS_SERIAL,
  141. .of_match = htif_serial_ids,
  142. .of_to_plat = htif_serial_of_to_plat,
  143. .plat_auto = sizeof(struct htif_plat),
  144. .probe = htif_serial_probe,
  145. .ops = &htif_serial_ops,
  146. };