opal-lpc.c 4.4 KB

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