fdt_serial.c 2.0 KB

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