mv64x60_udbg.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. /*
  2. * udbg serial input/output routines for the Marvell MV64x60 (Discovery).
  3. *
  4. * Author: Dale Farnsworth <dale@farnsworth.org>
  5. *
  6. * 2007 (c) MontaVista Software, Inc. This file is licensed under
  7. * the terms of the GNU General Public License version 2. This program
  8. * is licensed "as is" without any warranty of any kind, whether express
  9. * or implied.
  10. */
  11. #include <asm/io.h>
  12. #include <asm/prom.h>
  13. #include <asm/udbg.h>
  14. #include <sysdev/mv64x60.h>
  15. #define MPSC_0_CR1_OFFSET 0x000c
  16. #define MPSC_0_CR2_OFFSET 0x0010
  17. #define MPSC_CHR_2_TCS (1 << 9)
  18. #define MPSC_0_CHR_10_OFFSET 0x0030
  19. #define MPSC_INTR_CAUSE_OFF_0 0x0004
  20. #define MPSC_INTR_CAUSE_OFF_1 0x000c
  21. #define MPSC_INTR_CAUSE_RCC (1<<6)
  22. static void __iomem *mpsc_base;
  23. static void __iomem *mpsc_intr_cause;
  24. static void mv64x60_udbg_putc(char c)
  25. {
  26. if (c == '\n')
  27. mv64x60_udbg_putc('\r');
  28. while(in_le32(mpsc_base + MPSC_0_CR2_OFFSET) & MPSC_CHR_2_TCS)
  29. ;
  30. out_le32(mpsc_base + MPSC_0_CR1_OFFSET, c);
  31. out_le32(mpsc_base + MPSC_0_CR2_OFFSET, MPSC_CHR_2_TCS);
  32. }
  33. static int mv64x60_udbg_testc(void)
  34. {
  35. return (in_le32(mpsc_intr_cause) & MPSC_INTR_CAUSE_RCC) != 0;
  36. }
  37. static int mv64x60_udbg_getc(void)
  38. {
  39. int cause = 0;
  40. int c;
  41. while (!mv64x60_udbg_testc())
  42. ;
  43. c = in_8(mpsc_base + MPSC_0_CHR_10_OFFSET + 2);
  44. out_8(mpsc_base + MPSC_0_CHR_10_OFFSET + 2, c);
  45. out_le32(mpsc_intr_cause, cause & ~MPSC_INTR_CAUSE_RCC);
  46. return c;
  47. }
  48. static int mv64x60_udbg_getc_poll(void)
  49. {
  50. if (!mv64x60_udbg_testc())
  51. return -1;
  52. return mv64x60_udbg_getc();
  53. }
  54. static void mv64x60_udbg_init(void)
  55. {
  56. struct device_node *np, *mpscintr, *stdout = NULL;
  57. const char *path;
  58. const phandle *ph;
  59. struct resource r[2];
  60. const int *block_index;
  61. int intr_cause_offset;
  62. int err;
  63. path = of_get_property(of_chosen, "linux,stdout-path", NULL);
  64. if (!path)
  65. return;
  66. stdout = of_find_node_by_path(path);
  67. if (!stdout)
  68. return;
  69. for_each_compatible_node(np, NULL, "marvell,mv64360-mpsc") {
  70. if (np == stdout)
  71. break;
  72. }
  73. of_node_put(stdout);
  74. if (!np)
  75. return;
  76. block_index = of_get_property(np, "cell-index", NULL);
  77. if (!block_index)
  78. goto error;
  79. switch (*block_index) {
  80. case 0:
  81. intr_cause_offset = MPSC_INTR_CAUSE_OFF_0;
  82. break;
  83. case 1:
  84. intr_cause_offset = MPSC_INTR_CAUSE_OFF_1;
  85. break;
  86. default:
  87. goto error;
  88. }
  89. err = of_address_to_resource(np, 0, &r[0]);
  90. if (err)
  91. goto error;
  92. ph = of_get_property(np, "mpscintr", NULL);
  93. mpscintr = of_find_node_by_phandle(*ph);
  94. if (!mpscintr)
  95. goto error;
  96. err = of_address_to_resource(mpscintr, 0, &r[1]);
  97. of_node_put(mpscintr);
  98. if (err)
  99. goto error;
  100. of_node_put(np);
  101. mpsc_base = ioremap(r[0].start, resource_size(&r[0]));
  102. if (!mpsc_base)
  103. return;
  104. mpsc_intr_cause = ioremap(r[1].start, resource_size(&r[1]));
  105. if (!mpsc_intr_cause) {
  106. iounmap(mpsc_base);
  107. return;
  108. }
  109. mpsc_intr_cause += intr_cause_offset;
  110. udbg_putc = mv64x60_udbg_putc;
  111. udbg_getc = mv64x60_udbg_getc;
  112. udbg_getc_poll = mv64x60_udbg_getc_poll;
  113. return;
  114. error:
  115. of_node_put(np);
  116. }
  117. void mv64x60_init_early(void)
  118. {
  119. mv64x60_udbg_init();
  120. }