fdt_serial.c 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  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_htif;
  17. extern struct fdt_serial fdt_serial_shakti;
  18. extern struct fdt_serial fdt_serial_gaisler;
  19. static struct fdt_serial *serial_drivers[] = {
  20. &fdt_serial_uart8250,
  21. &fdt_serial_sifive,
  22. &fdt_serial_htif,
  23. &fdt_serial_shakti,
  24. &fdt_serial_gaisler
  25. };
  26. static struct fdt_serial dummy = {
  27. .match_table = NULL,
  28. .init = NULL,
  29. };
  30. static struct fdt_serial *current_driver = &dummy;
  31. int fdt_serial_init(void)
  32. {
  33. const void *prop;
  34. struct fdt_serial *drv;
  35. const struct fdt_match *match;
  36. int pos, noff = -1, len, coff, rc;
  37. void *fdt = sbi_scratch_thishart_arg1_ptr();
  38. /* Find offset of node pointed by stdout-path */
  39. coff = fdt_path_offset(fdt, "/chosen");
  40. if (-1 < coff) {
  41. prop = fdt_getprop(fdt, coff, "stdout-path", &len);
  42. if (prop && len)
  43. noff = fdt_path_offset(fdt, prop);
  44. }
  45. /* First check DT node pointed by stdout-path */
  46. for (pos = 0; pos < array_size(serial_drivers) && -1 < noff; pos++) {
  47. drv = serial_drivers[pos];
  48. match = fdt_match_node(fdt, noff, drv->match_table);
  49. if (!match)
  50. continue;
  51. if (drv->init) {
  52. rc = drv->init(fdt, noff, match);
  53. if (rc == SBI_ENODEV)
  54. continue;
  55. if (rc)
  56. return rc;
  57. }
  58. current_driver = drv;
  59. break;
  60. }
  61. /* Check if we found desired driver */
  62. if (current_driver != &dummy)
  63. goto done;
  64. /* Lastly check all DT nodes */
  65. for (pos = 0; pos < array_size(serial_drivers); pos++) {
  66. drv = serial_drivers[pos];
  67. noff = fdt_find_match(fdt, -1, drv->match_table, &match);
  68. if (noff < 0)
  69. continue;
  70. if (drv->init) {
  71. rc = drv->init(fdt, noff, match);
  72. if (rc == SBI_ENODEV)
  73. continue;
  74. if (rc)
  75. return rc;
  76. }
  77. current_driver = drv;
  78. break;
  79. }
  80. done:
  81. return 0;
  82. }