opal-lpc.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. /*
  2. * PowerNV LPC bus handling.
  3. *
  4. * Copyright 2013 IBM Corp.
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version
  9. * 2 of the License, or (at your option) any later version.
  10. */
  11. #include <linux/kernel.h>
  12. #include <linux/of.h>
  13. #include <linux/bug.h>
  14. #include <asm/machdep.h>
  15. #include <asm/firmware.h>
  16. #include <asm/xics.h>
  17. #include <asm/opal.h>
  18. #include <asm/prom.h>
  19. static int opal_lpc_chip_id = -1;
  20. static u8 opal_lpc_inb(unsigned long port)
  21. {
  22. int64_t rc;
  23. uint32_t data;
  24. if (opal_lpc_chip_id < 0 || port > 0xffff)
  25. return 0xff;
  26. rc = opal_lpc_read(opal_lpc_chip_id, OPAL_LPC_IO, port, &data, 1);
  27. return rc ? 0xff : data;
  28. }
  29. static __le16 __opal_lpc_inw(unsigned long port)
  30. {
  31. int64_t rc;
  32. uint32_t data;
  33. if (opal_lpc_chip_id < 0 || port > 0xfffe)
  34. return 0xffff;
  35. if (port & 1)
  36. return (__le16)opal_lpc_inb(port) << 8 | opal_lpc_inb(port + 1);
  37. rc = opal_lpc_read(opal_lpc_chip_id, OPAL_LPC_IO, port, &data, 2);
  38. return rc ? 0xffff : data;
  39. }
  40. static u16 opal_lpc_inw(unsigned long port)
  41. {
  42. return le16_to_cpu(__opal_lpc_inw(port));
  43. }
  44. static __le32 __opal_lpc_inl(unsigned long port)
  45. {
  46. int64_t rc;
  47. uint32_t data;
  48. if (opal_lpc_chip_id < 0 || port > 0xfffc)
  49. return 0xffffffff;
  50. if (port & 3)
  51. return (__le32)opal_lpc_inb(port ) << 24 |
  52. (__le32)opal_lpc_inb(port + 1) << 16 |
  53. (__le32)opal_lpc_inb(port + 2) << 8 |
  54. opal_lpc_inb(port + 3);
  55. rc = opal_lpc_read(opal_lpc_chip_id, OPAL_LPC_IO, port, &data, 4);
  56. return rc ? 0xffffffff : data;
  57. }
  58. static u32 opal_lpc_inl(unsigned long port)
  59. {
  60. return le32_to_cpu(__opal_lpc_inl(port));
  61. }
  62. static void opal_lpc_outb(u8 val, unsigned long port)
  63. {
  64. if (opal_lpc_chip_id < 0 || port > 0xffff)
  65. return;
  66. opal_lpc_write(opal_lpc_chip_id, OPAL_LPC_IO, port, val, 1);
  67. }
  68. static void __opal_lpc_outw(__le16 val, unsigned long port)
  69. {
  70. if (opal_lpc_chip_id < 0 || port > 0xfffe)
  71. return;
  72. if (port & 1) {
  73. opal_lpc_outb(val >> 8, port);
  74. opal_lpc_outb(val , port + 1);
  75. return;
  76. }
  77. opal_lpc_write(opal_lpc_chip_id, OPAL_LPC_IO, port, val, 2);
  78. }
  79. static void opal_lpc_outw(u16 val, unsigned long port)
  80. {
  81. __opal_lpc_outw(cpu_to_le16(val), port);
  82. }
  83. static void __opal_lpc_outl(__le32 val, unsigned long port)
  84. {
  85. if (opal_lpc_chip_id < 0 || port > 0xfffc)
  86. return;
  87. if (port & 3) {
  88. opal_lpc_outb(val >> 24, port);
  89. opal_lpc_outb(val >> 16, port + 1);
  90. opal_lpc_outb(val >> 8, port + 2);
  91. opal_lpc_outb(val , port + 3);
  92. return;
  93. }
  94. opal_lpc_write(opal_lpc_chip_id, OPAL_LPC_IO, port, val, 4);
  95. }
  96. static void opal_lpc_outl(u32 val, unsigned long port)
  97. {
  98. __opal_lpc_outl(cpu_to_le32(val), port);
  99. }
  100. static void opal_lpc_insb(unsigned long p, void *b, unsigned long c)
  101. {
  102. u8 *ptr = b;
  103. while(c--)
  104. *(ptr++) = opal_lpc_inb(p);
  105. }
  106. static void opal_lpc_insw(unsigned long p, void *b, unsigned long c)
  107. {
  108. __le16 *ptr = b;
  109. while(c--)
  110. *(ptr++) = __opal_lpc_inw(p);
  111. }
  112. static void opal_lpc_insl(unsigned long p, void *b, unsigned long c)
  113. {
  114. __le32 *ptr = b;
  115. while(c--)
  116. *(ptr++) = __opal_lpc_inl(p);
  117. }
  118. static void opal_lpc_outsb(unsigned long p, const void *b, unsigned long c)
  119. {
  120. const u8 *ptr = b;
  121. while(c--)
  122. opal_lpc_outb(*(ptr++), p);
  123. }
  124. static void opal_lpc_outsw(unsigned long p, const void *b, unsigned long c)
  125. {
  126. const __le16 *ptr = b;
  127. while(c--)
  128. __opal_lpc_outw(*(ptr++), p);
  129. }
  130. static void opal_lpc_outsl(unsigned long p, const void *b, unsigned long c)
  131. {
  132. const __le32 *ptr = b;
  133. while(c--)
  134. __opal_lpc_outl(*(ptr++), p);
  135. }
  136. static const struct ppc_pci_io opal_lpc_io = {
  137. .inb = opal_lpc_inb,
  138. .inw = opal_lpc_inw,
  139. .inl = opal_lpc_inl,
  140. .outb = opal_lpc_outb,
  141. .outw = opal_lpc_outw,
  142. .outl = opal_lpc_outl,
  143. .insb = opal_lpc_insb,
  144. .insw = opal_lpc_insw,
  145. .insl = opal_lpc_insl,
  146. .outsb = opal_lpc_outsb,
  147. .outsw = opal_lpc_outsw,
  148. .outsl = opal_lpc_outsl,
  149. };
  150. void opal_lpc_init(void)
  151. {
  152. struct device_node *np;
  153. /*
  154. * Look for a Power8 LPC bus tagged as "primary",
  155. * we currently support only one though the OPAL APIs
  156. * support any number.
  157. */
  158. for_each_compatible_node(np, NULL, "ibm,power8-lpc") {
  159. if (!of_device_is_available(np))
  160. continue;
  161. if (!of_get_property(np, "primary", NULL))
  162. continue;
  163. opal_lpc_chip_id = of_get_ibm_chip_id(np);
  164. break;
  165. }
  166. if (opal_lpc_chip_id < 0)
  167. return;
  168. /* Setup special IO ops */
  169. ppc_pci_io = opal_lpc_io;
  170. isa_io_special = true;
  171. pr_info("OPAL: Power8 LPC bus found, chip ID %d\n", opal_lpc_chip_id);
  172. }