fdt_serial.c 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. /*
  2. * SPDX-License-Identifier: BSD-2-Clause
  3. *
  4. * Copyright (c) 2020 Western Digital Corporation or its affiliates.
  5. *
  6. * Authors:
  7. * Anup Patel <anup.patel@wdc.com>
  8. */
  9. #include <libfdt.h>
  10. #include <sbi/sbi_error.h>
  11. #include <sbi/sbi_scratch.h>
  12. #include <sbi_utils/fdt/fdt_helper.h>
  13. #include <sbi_utils/serial/fdt_serial.h>
  14. extern struct fdt_serial fdt_serial_uart8250;
  15. extern struct fdt_serial fdt_serial_sifive;
  16. extern struct fdt_serial fdt_serial_litex;
  17. extern struct fdt_serial fdt_serial_htif;
  18. extern struct fdt_serial fdt_serial_shakti;
  19. extern struct fdt_serial fdt_serial_gaisler;
  20. static struct fdt_serial *serial_drivers[] = {
  21. &fdt_serial_uart8250,
  22. &fdt_serial_sifive,
  23. &fdt_serial_litex,
  24. &fdt_serial_htif,
  25. &fdt_serial_shakti,
  26. &fdt_serial_gaisler
  27. };
  28. static struct fdt_serial dummy = {
  29. .match_table = NULL,
  30. .init = NULL,
  31. };
  32. static struct fdt_serial *current_driver = &dummy;
  33. int fdt_serial_init(void)
  34. {
  35. const void *prop;
  36. struct fdt_serial *drv;
  37. const struct fdt_match *match;
  38. int pos, noff = -1, len, coff, rc;
  39. void *fdt = fdt_get_address();
  40. /* Find offset of node pointed to by stdout-path */
  41. coff = fdt_path_offset(fdt, "/chosen");
  42. if (-1 < coff) {
  43. prop = fdt_getprop(fdt, coff, "stdout-path", &len);
  44. if (prop && len) {
  45. const char *sep, *start = prop;
  46. /* The device path may be followed by ':' */
  47. sep = strchr(start, ':');
  48. if (sep)
  49. noff = fdt_path_offset_namelen(fdt, prop,
  50. sep - start);
  51. else
  52. noff = fdt_path_offset(fdt, prop);
  53. }
  54. }
  55. /* First check DT node pointed by stdout-path */
  56. for (pos = 0; pos < array_size(serial_drivers) && -1 < noff; pos++) {
  57. drv = serial_drivers[pos];
  58. match = fdt_match_node(fdt, noff, drv->match_table);
  59. if (!match)
  60. continue;
  61. if (drv->init) {
  62. rc = drv->init(fdt, noff, match);
  63. if (rc == SBI_ENODEV)
  64. continue;
  65. if (rc)
  66. return rc;
  67. }
  68. current_driver = drv;
  69. break;
  70. }
  71. /* Check if we found desired driver */
  72. if (current_driver != &dummy)
  73. goto done;
  74. /* Lastly check all DT nodes */
  75. for (pos = 0; pos < array_size(serial_drivers); pos++) {
  76. drv = serial_drivers[pos];
  77. noff = fdt_find_match(fdt, -1, drv->match_table, &match);
  78. if (noff < 0)
  79. continue;
  80. if (drv->init) {
  81. rc = drv->init(fdt, noff, match);
  82. if (rc == SBI_ENODEV)
  83. continue;
  84. if (rc)
  85. return rc;
  86. }
  87. current_driver = drv;
  88. break;
  89. }
  90. done:
  91. return 0;
  92. }