serial_arc.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. /*
  2. * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com)
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License version 2 as
  6. * published by the Free Software Foundation.
  7. *
  8. */
  9. #include <common.h>
  10. #include <dm.h>
  11. #include <serial.h>
  12. DECLARE_GLOBAL_DATA_PTR;
  13. struct arc_serial_regs {
  14. unsigned int id0;
  15. unsigned int id1;
  16. unsigned int id2;
  17. unsigned int id3;
  18. unsigned int data;
  19. unsigned int status;
  20. unsigned int baudl;
  21. unsigned int baudh;
  22. };
  23. struct arc_serial_platdata {
  24. struct arc_serial_regs *reg;
  25. unsigned int uartclk;
  26. };
  27. /* Bit definitions of STATUS register */
  28. #define UART_RXEMPTY (1 << 5)
  29. #define UART_OVERFLOW_ERR (1 << 1)
  30. #define UART_TXEMPTY (1 << 7)
  31. static int arc_serial_setbrg(struct udevice *dev, int baudrate)
  32. {
  33. struct arc_serial_platdata *plat = dev->platdata;
  34. struct arc_serial_regs *const regs = plat->reg;
  35. int arc_console_baud = gd->cpu_clk / (baudrate * 4) - 1;
  36. writeb(arc_console_baud & 0xff, &regs->baudl);
  37. #ifdef CONFIG_ARC
  38. /*
  39. * UART ISS(Instruction Set simulator) emulation has a subtle bug:
  40. * A existing value of Baudh = 0 is used as a indication to startup
  41. * it's internal state machine.
  42. * Thus if baudh is set to 0, 2 times, it chokes.
  43. * This happens with BAUD=115200 and the formaula above
  44. * Until that is fixed, when running on ISS, we will set baudh to !0
  45. */
  46. if (gd->arch.running_on_hw)
  47. writeb((arc_console_baud & 0xff00) >> 8, &regs->baudh);
  48. else
  49. writeb(1, &regs->baudh);
  50. #else
  51. writeb((arc_console_baud & 0xff00) >> 8, &regs->baudh);
  52. #endif
  53. return 0;
  54. }
  55. static int arc_serial_putc(struct udevice *dev, const char c)
  56. {
  57. struct arc_serial_platdata *plat = dev->platdata;
  58. struct arc_serial_regs *const regs = plat->reg;
  59. if (c == '\n')
  60. arc_serial_putc(dev, '\r');
  61. while (!(readb(&regs->status) & UART_TXEMPTY))
  62. ;
  63. writeb(c, &regs->data);
  64. return 0;
  65. }
  66. static int arc_serial_tstc(struct arc_serial_regs *const regs)
  67. {
  68. return !(readb(&regs->status) & UART_RXEMPTY);
  69. }
  70. static int arc_serial_pending(struct udevice *dev, bool input)
  71. {
  72. struct arc_serial_platdata *plat = dev->platdata;
  73. struct arc_serial_regs *const regs = plat->reg;
  74. uint32_t status = readb(&regs->status);
  75. if (input)
  76. return status & UART_RXEMPTY ? 0 : 1;
  77. else
  78. return status & UART_TXEMPTY ? 0 : 1;
  79. }
  80. static int arc_serial_getc(struct udevice *dev)
  81. {
  82. struct arc_serial_platdata *plat = dev->platdata;
  83. struct arc_serial_regs *const regs = plat->reg;
  84. while (!arc_serial_tstc(regs))
  85. ;
  86. /* Check for overflow errors */
  87. if (readb(&regs->status) & UART_OVERFLOW_ERR)
  88. return 0;
  89. return readb(&regs->data) & 0xFF;
  90. }
  91. static int arc_serial_probe(struct udevice *dev)
  92. {
  93. return 0;
  94. }
  95. static const struct dm_serial_ops arc_serial_ops = {
  96. .putc = arc_serial_putc,
  97. .pending = arc_serial_pending,
  98. .getc = arc_serial_getc,
  99. .setbrg = arc_serial_setbrg,
  100. };
  101. static const struct udevice_id arc_serial_ids[] = {
  102. { .compatible = "snps,arc-uart" },
  103. { }
  104. };
  105. static int arc_serial_ofdata_to_platdata(struct udevice *dev)
  106. {
  107. struct arc_serial_platdata *plat = dev_get_platdata(dev);
  108. DECLARE_GLOBAL_DATA_PTR;
  109. plat->reg = (struct arc_serial_regs *)fdtdec_get_addr(gd->fdt_blob,
  110. dev->of_offset, "reg");
  111. plat->uartclk = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
  112. "clock-frequency", 0);
  113. return 0;
  114. }
  115. U_BOOT_DRIVER(serial_arc) = {
  116. .name = "serial_arc",
  117. .id = UCLASS_SERIAL,
  118. .of_match = arc_serial_ids,
  119. .ofdata_to_platdata = arc_serial_ofdata_to_platdata,
  120. .probe = arc_serial_probe,
  121. .ops = &arc_serial_ops,
  122. .flags = DM_FLAG_PRE_RELOC,
  123. };