fdt_serial.c 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  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. /* List of FDT serial drivers generated at compile time */
  15. extern struct fdt_serial *fdt_serial_drivers[];
  16. extern unsigned long fdt_serial_drivers_size;
  17. static struct fdt_serial dummy = {
  18. .match_table = NULL,
  19. .init = NULL,
  20. };
  21. static struct fdt_serial *current_driver = &dummy;
  22. int fdt_serial_init(void)
  23. {
  24. const void *prop;
  25. struct fdt_serial *drv;
  26. const struct fdt_match *match;
  27. int pos, noff = -1, len, coff, rc;
  28. void *fdt = fdt_get_address();
  29. /* Find offset of node pointed to by stdout-path */
  30. coff = fdt_path_offset(fdt, "/chosen");
  31. if (-1 < coff) {
  32. prop = fdt_getprop(fdt, coff, "stdout-path", &len);
  33. if (prop && len) {
  34. const char *sep, *start = prop;
  35. /* The device path may be followed by ':' */
  36. sep = strchr(start, ':');
  37. if (sep)
  38. noff = fdt_path_offset_namelen(fdt, prop,
  39. sep - start);
  40. else
  41. noff = fdt_path_offset(fdt, prop);
  42. }
  43. }
  44. /* First check DT node pointed by stdout-path */
  45. for (pos = 0; pos < fdt_serial_drivers_size && -1 < noff; pos++) {
  46. drv = fdt_serial_drivers[pos];
  47. match = fdt_match_node(fdt, noff, drv->match_table);
  48. if (!match)
  49. continue;
  50. if (drv->init) {
  51. rc = drv->init(fdt, noff, match);
  52. if (rc == SBI_ENODEV)
  53. continue;
  54. if (rc)
  55. return rc;
  56. }
  57. current_driver = drv;
  58. break;
  59. }
  60. /* Check if we found desired driver */
  61. if (current_driver != &dummy)
  62. goto done;
  63. /* Lastly check all DT nodes */
  64. for (pos = 0; pos < fdt_serial_drivers_size; pos++) {
  65. drv = fdt_serial_drivers[pos];
  66. noff = fdt_find_match(fdt, -1, drv->match_table, &match);
  67. if (noff < 0)
  68. continue;
  69. if (drv->init) {
  70. rc = drv->init(fdt, noff, match);
  71. if (rc == SBI_ENODEV)
  72. continue;
  73. if (rc)
  74. return rc;
  75. }
  76. current_driver = drv;
  77. break;
  78. }
  79. done:
  80. return 0;
  81. }