integrator_ap.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Copyright (C) 2000-2003 Deep Blue Solutions Ltd
  4. */
  5. #include <linux/kernel.h>
  6. #include <linux/init.h>
  7. #include <linux/syscore_ops.h>
  8. #include <linux/amba/bus.h>
  9. #include <linux/io.h>
  10. #include <linux/irqchip.h>
  11. #include <linux/of_irq.h>
  12. #include <linux/of_address.h>
  13. #include <linux/of_platform.h>
  14. #include <linux/uaccess.h>
  15. #include <linux/termios.h>
  16. #include <linux/mfd/syscon.h>
  17. #include <linux/regmap.h>
  18. #include <asm/mach/arch.h>
  19. #include <asm/mach/map.h>
  20. #include "integrator-hardware.h"
  21. #include "integrator-cm.h"
  22. #include "integrator.h"
  23. /* Regmap to the AP system controller */
  24. static struct regmap *ap_syscon_map;
  25. /*
  26. * All IO addresses are mapped onto VA 0xFFFx.xxxx, where x.xxxx
  27. * is the (PA >> 12).
  28. *
  29. * Setup a VA for the Integrator interrupt controller (for header #0,
  30. * just for now).
  31. */
  32. #define VA_IC_BASE __io_address(INTEGRATOR_IC_BASE)
  33. /*
  34. * Logical Physical
  35. * f1400000 14000000 Interrupt controller
  36. * f1600000 16000000 UART 0
  37. */
  38. static struct map_desc ap_io_desc[] __initdata __maybe_unused = {
  39. {
  40. .virtual = IO_ADDRESS(INTEGRATOR_IC_BASE),
  41. .pfn = __phys_to_pfn(INTEGRATOR_IC_BASE),
  42. .length = SZ_4K,
  43. .type = MT_DEVICE
  44. }, {
  45. .virtual = IO_ADDRESS(INTEGRATOR_UART0_BASE),
  46. .pfn = __phys_to_pfn(INTEGRATOR_UART0_BASE),
  47. .length = SZ_4K,
  48. .type = MT_DEVICE
  49. }
  50. };
  51. static void __init ap_map_io(void)
  52. {
  53. iotable_init(ap_io_desc, ARRAY_SIZE(ap_io_desc));
  54. }
  55. #ifdef CONFIG_PM
  56. static unsigned long ic_irq_enable;
  57. static int irq_suspend(void)
  58. {
  59. ic_irq_enable = readl(VA_IC_BASE + IRQ_ENABLE);
  60. return 0;
  61. }
  62. static void irq_resume(void)
  63. {
  64. /* disable all irq sources */
  65. cm_clear_irqs();
  66. writel(-1, VA_IC_BASE + IRQ_ENABLE_CLEAR);
  67. writel(-1, VA_IC_BASE + FIQ_ENABLE_CLEAR);
  68. writel(ic_irq_enable, VA_IC_BASE + IRQ_ENABLE_SET);
  69. }
  70. #else
  71. #define irq_suspend NULL
  72. #define irq_resume NULL
  73. #endif
  74. static struct syscore_ops irq_syscore_ops = {
  75. .suspend = irq_suspend,
  76. .resume = irq_resume,
  77. };
  78. static int __init irq_syscore_init(void)
  79. {
  80. register_syscore_ops(&irq_syscore_ops);
  81. return 0;
  82. }
  83. device_initcall(irq_syscore_init);
  84. /*
  85. * For the PL010 found in the Integrator/AP some of the UART control is
  86. * implemented in the system controller and accessed using a callback
  87. * from the driver.
  88. */
  89. static void integrator_uart_set_mctrl(struct amba_device *dev,
  90. void __iomem *base, unsigned int mctrl)
  91. {
  92. unsigned int ctrls = 0, ctrlc = 0, rts_mask, dtr_mask;
  93. u32 phybase = dev->res.start;
  94. int ret;
  95. if (phybase == INTEGRATOR_UART0_BASE) {
  96. /* UART0 */
  97. rts_mask = 1 << 4;
  98. dtr_mask = 1 << 5;
  99. } else {
  100. /* UART1 */
  101. rts_mask = 1 << 6;
  102. dtr_mask = 1 << 7;
  103. }
  104. if (mctrl & TIOCM_RTS)
  105. ctrlc |= rts_mask;
  106. else
  107. ctrls |= rts_mask;
  108. if (mctrl & TIOCM_DTR)
  109. ctrlc |= dtr_mask;
  110. else
  111. ctrls |= dtr_mask;
  112. ret = regmap_write(ap_syscon_map,
  113. INTEGRATOR_SC_CTRLS_OFFSET,
  114. ctrls);
  115. if (ret)
  116. pr_err("MODEM: unable to write PL010 UART CTRLS\n");
  117. ret = regmap_write(ap_syscon_map,
  118. INTEGRATOR_SC_CTRLC_OFFSET,
  119. ctrlc);
  120. if (ret)
  121. pr_err("MODEM: unable to write PL010 UART CRTLC\n");
  122. }
  123. struct amba_pl010_data ap_uart_data = {
  124. .set_mctrl = integrator_uart_set_mctrl,
  125. };
  126. static void __init ap_init_irq_of(void)
  127. {
  128. cm_init();
  129. irqchip_init();
  130. }
  131. /* For the Device Tree, add in the UART callbacks as AUXDATA */
  132. static struct of_dev_auxdata ap_auxdata_lookup[] __initdata = {
  133. OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_UART0_BASE,
  134. "uart0", &ap_uart_data),
  135. OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_UART1_BASE,
  136. "uart1", &ap_uart_data),
  137. { /* sentinel */ },
  138. };
  139. static const struct of_device_id ap_syscon_match[] = {
  140. { .compatible = "arm,integrator-ap-syscon"},
  141. { },
  142. };
  143. static void __init ap_init_of(void)
  144. {
  145. struct device_node *syscon;
  146. of_platform_default_populate(NULL, ap_auxdata_lookup, NULL);
  147. syscon = of_find_matching_node(NULL, ap_syscon_match);
  148. if (!syscon)
  149. return;
  150. ap_syscon_map = syscon_node_to_regmap(syscon);
  151. if (IS_ERR(ap_syscon_map)) {
  152. pr_crit("could not find Integrator/AP system controller\n");
  153. return;
  154. }
  155. }
  156. static const char * ap_dt_board_compat[] = {
  157. "arm,integrator-ap",
  158. NULL,
  159. };
  160. DT_MACHINE_START(INTEGRATOR_AP_DT, "ARM Integrator/AP (Device Tree)")
  161. .reserve = integrator_reserve,
  162. .map_io = ap_map_io,
  163. .init_irq = ap_init_irq_of,
  164. .init_machine = ap_init_of,
  165. .dt_compat = ap_dt_board_compat,
  166. MACHINE_END