early_printk.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. /*
  2. * Earlyprintk support.
  3. *
  4. * Copyright (C) 2012 ARM Ltd.
  5. * Author: Catalin Marinas <catalin.marinas@arm.com>
  6. *
  7. * This program is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License version 2 as
  9. * published by the Free Software Foundation.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include <linux/kernel.h>
  20. #include <linux/console.h>
  21. #include <linux/init.h>
  22. #include <linux/string.h>
  23. #include <linux/mm.h>
  24. #include <linux/io.h>
  25. #include <linux/amba/serial.h>
  26. #include <linux/serial_reg.h>
  27. static void __iomem *early_base;
  28. static void (*printch)(char ch);
  29. /*
  30. * PL011 single character TX.
  31. */
  32. static void pl011_printch(char ch)
  33. {
  34. while (readl_relaxed(early_base + UART01x_FR) & UART01x_FR_TXFF)
  35. ;
  36. writeb_relaxed(ch, early_base + UART01x_DR);
  37. while (readl_relaxed(early_base + UART01x_FR) & UART01x_FR_BUSY)
  38. ;
  39. }
  40. /*
  41. * Semihosting-based debug console
  42. */
  43. static void smh_printch(char ch)
  44. {
  45. asm volatile("mov x1, %0\n"
  46. "mov x0, #3\n"
  47. "hlt 0xf000\n"
  48. : : "r" (&ch) : "x0", "x1", "memory");
  49. }
  50. /*
  51. * 8250/16550 (8-bit aligned registers) single character TX.
  52. */
  53. static void uart8250_8bit_printch(char ch)
  54. {
  55. while (!(readb_relaxed(early_base + UART_LSR) & UART_LSR_THRE))
  56. ;
  57. writeb_relaxed(ch, early_base + UART_TX);
  58. }
  59. /*
  60. * 8250/16550 (32-bit aligned registers) single character TX.
  61. */
  62. static void uart8250_32bit_printch(char ch)
  63. {
  64. while (!(readl_relaxed(early_base + (UART_LSR << 2)) & UART_LSR_THRE))
  65. ;
  66. writel_relaxed(ch, early_base + (UART_TX << 2));
  67. }
  68. struct earlycon_match {
  69. const char *name;
  70. void (*printch)(char ch);
  71. };
  72. static const struct earlycon_match earlycon_match[] __initconst = {
  73. { .name = "pl011", .printch = pl011_printch, },
  74. { .name = "smh", .printch = smh_printch, },
  75. { .name = "uart8250-8bit", .printch = uart8250_8bit_printch, },
  76. { .name = "uart8250-32bit", .printch = uart8250_32bit_printch, },
  77. {}
  78. };
  79. static void early_write(struct console *con, const char *s, unsigned n)
  80. {
  81. while (n-- > 0) {
  82. if (*s == '\n')
  83. printch('\r');
  84. printch(*s);
  85. s++;
  86. }
  87. }
  88. static struct console early_console = {
  89. .name = "earlycon",
  90. .write = early_write,
  91. .flags = CON_PRINTBUFFER | CON_BOOT,
  92. .index = -1,
  93. };
  94. /*
  95. * Parse earlyprintk=... parameter in the format:
  96. *
  97. * <name>[,<addr>][,<options>]
  98. *
  99. * and register the early console. It is assumed that the UART has been
  100. * initialised by the bootloader already.
  101. */
  102. static int __init setup_early_printk(char *buf)
  103. {
  104. const struct earlycon_match *match = earlycon_match;
  105. phys_addr_t paddr = 0;
  106. if (!buf) {
  107. pr_warning("No earlyprintk arguments passed.\n");
  108. return 0;
  109. }
  110. while (match->name) {
  111. size_t len = strlen(match->name);
  112. if (!strncmp(buf, match->name, len)) {
  113. buf += len;
  114. break;
  115. }
  116. match++;
  117. }
  118. if (!match->name) {
  119. pr_warning("Unknown earlyprintk arguments: %s\n", buf);
  120. return 0;
  121. }
  122. /* I/O address */
  123. if (!strncmp(buf, ",0x", 3)) {
  124. char *e;
  125. paddr = simple_strtoul(buf + 1, &e, 16);
  126. buf = e;
  127. }
  128. /* no options parsing yet */
  129. if (paddr)
  130. early_base = early_io_map(paddr, EARLYCON_IOBASE);
  131. printch = match->printch;
  132. register_console(&early_console);
  133. return 0;
  134. }
  135. early_param("earlyprintk", setup_early_printk);