cros_ec_lpc_mec.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. // SPDX-License-Identifier: GPL-2.0
  2. // LPC variant I/O for Microchip EC
  3. //
  4. // Copyright (C) 2016 Google, Inc
  5. #include <linux/delay.h>
  6. #include <linux/io.h>
  7. #include <linux/mutex.h>
  8. #include <linux/types.h>
  9. #include "cros_ec_lpc_mec.h"
  10. #define ACPI_LOCK_DELAY_MS 500
  11. /*
  12. * This mutex must be held while accessing the EMI unit. We can't rely on the
  13. * EC mutex because memmap data may be accessed without it being held.
  14. */
  15. static DEFINE_MUTEX(io_mutex);
  16. /*
  17. * An alternative mutex to be used when the ACPI AML code may also
  18. * access memmap data. When set, this mutex is used in preference to
  19. * io_mutex.
  20. */
  21. static acpi_handle aml_mutex;
  22. static u16 mec_emi_base, mec_emi_end;
  23. /**
  24. * cros_ec_lpc_mec_lock() - Acquire mutex for EMI
  25. *
  26. * @return: Negative error code, or zero for success
  27. */
  28. static int cros_ec_lpc_mec_lock(void)
  29. {
  30. bool success;
  31. if (!aml_mutex) {
  32. mutex_lock(&io_mutex);
  33. return 0;
  34. }
  35. success = ACPI_SUCCESS(acpi_acquire_mutex(aml_mutex,
  36. NULL, ACPI_LOCK_DELAY_MS));
  37. if (!success)
  38. return -EBUSY;
  39. return 0;
  40. }
  41. /**
  42. * cros_ec_lpc_mec_unlock() - Release mutex for EMI
  43. *
  44. * @return: Negative error code, or zero for success
  45. */
  46. static int cros_ec_lpc_mec_unlock(void)
  47. {
  48. bool success;
  49. if (!aml_mutex) {
  50. mutex_unlock(&io_mutex);
  51. return 0;
  52. }
  53. success = ACPI_SUCCESS(acpi_release_mutex(aml_mutex, NULL));
  54. if (!success)
  55. return -EBUSY;
  56. return 0;
  57. }
  58. /**
  59. * cros_ec_lpc_mec_emi_write_address() - Initialize EMI at a given address.
  60. *
  61. * @addr: Starting read / write address
  62. * @access_type: Type of access, typically 32-bit auto-increment
  63. */
  64. static void cros_ec_lpc_mec_emi_write_address(u16 addr,
  65. enum cros_ec_lpc_mec_emi_access_mode access_type)
  66. {
  67. outb((addr & 0xfc) | access_type, MEC_EMI_EC_ADDRESS_B0(mec_emi_base));
  68. outb((addr >> 8) & 0x7f, MEC_EMI_EC_ADDRESS_B1(mec_emi_base));
  69. }
  70. /**
  71. * cros_ec_lpc_mec_in_range() - Determine if addresses are in MEC EMI range.
  72. *
  73. * @offset: Address offset
  74. * @length: Number of bytes to check
  75. *
  76. * Return: 1 if in range, 0 if not, and -EINVAL on failure
  77. * such as the mec range not being initialized
  78. */
  79. int cros_ec_lpc_mec_in_range(unsigned int offset, unsigned int length)
  80. {
  81. if (WARN_ON(mec_emi_base == 0 || mec_emi_end == 0))
  82. return -EINVAL;
  83. if (offset >= mec_emi_base && offset < mec_emi_end) {
  84. if (WARN_ON(offset + length - 1 >= mec_emi_end))
  85. return -EINVAL;
  86. return 1;
  87. }
  88. if (WARN_ON(offset + length > mec_emi_base && offset < mec_emi_end))
  89. return -EINVAL;
  90. return 0;
  91. }
  92. /**
  93. * cros_ec_lpc_io_bytes_mec() - Read / write bytes to MEC EMI port.
  94. *
  95. * @io_type: MEC_IO_READ or MEC_IO_WRITE, depending on request
  96. * @offset: Base read / write address
  97. * @length: Number of bytes to read / write
  98. * @buf: Destination / source buffer
  99. *
  100. * @return: A negative error code on error, or 8-bit checksum of all
  101. * bytes read / written
  102. */
  103. int cros_ec_lpc_io_bytes_mec(enum cros_ec_lpc_mec_io_type io_type,
  104. unsigned int offset, unsigned int length,
  105. u8 *buf)
  106. {
  107. int i = 0;
  108. int io_addr;
  109. u8 sum = 0;
  110. enum cros_ec_lpc_mec_emi_access_mode access, new_access;
  111. int ret;
  112. if (length == 0)
  113. return 0;
  114. /* Return checksum of 0 if window is not initialized */
  115. WARN_ON(mec_emi_base == 0 || mec_emi_end == 0);
  116. if (mec_emi_base == 0 || mec_emi_end == 0)
  117. return 0;
  118. /*
  119. * Long access cannot be used on misaligned data since reading B0 loads
  120. * the data register and writing B3 flushes.
  121. */
  122. if (offset & 0x3 || length < 4)
  123. access = ACCESS_TYPE_BYTE;
  124. else
  125. access = ACCESS_TYPE_LONG_AUTO_INCREMENT;
  126. ret = cros_ec_lpc_mec_lock();
  127. if (ret)
  128. return ret;
  129. /* Initialize I/O at desired address */
  130. cros_ec_lpc_mec_emi_write_address(offset, access);
  131. /* Skip bytes in case of misaligned offset */
  132. io_addr = MEC_EMI_EC_DATA_B0(mec_emi_base) + (offset & 0x3);
  133. while (i < length) {
  134. while (io_addr <= MEC_EMI_EC_DATA_B3(mec_emi_base)) {
  135. if (io_type == MEC_IO_READ)
  136. buf[i] = inb(io_addr++);
  137. else
  138. outb(buf[i], io_addr++);
  139. sum += buf[i++];
  140. offset++;
  141. /* Extra bounds check in case of misaligned length */
  142. if (i == length)
  143. goto done;
  144. }
  145. /*
  146. * Use long auto-increment access except for misaligned write,
  147. * since writing B3 triggers the flush.
  148. */
  149. if (length - i < 4 && io_type == MEC_IO_WRITE)
  150. new_access = ACCESS_TYPE_BYTE;
  151. else
  152. new_access = ACCESS_TYPE_LONG_AUTO_INCREMENT;
  153. if (new_access != access ||
  154. access != ACCESS_TYPE_LONG_AUTO_INCREMENT) {
  155. access = new_access;
  156. cros_ec_lpc_mec_emi_write_address(offset, access);
  157. }
  158. /* Access [B0, B3] on each loop pass */
  159. io_addr = MEC_EMI_EC_DATA_B0(mec_emi_base);
  160. }
  161. done:
  162. ret = cros_ec_lpc_mec_unlock();
  163. if (ret)
  164. return ret;
  165. return sum;
  166. }
  167. EXPORT_SYMBOL(cros_ec_lpc_io_bytes_mec);
  168. void cros_ec_lpc_mec_init(unsigned int base, unsigned int end)
  169. {
  170. mec_emi_base = base;
  171. mec_emi_end = end;
  172. }
  173. EXPORT_SYMBOL(cros_ec_lpc_mec_init);
  174. int cros_ec_lpc_mec_acpi_mutex(struct acpi_device *adev, const char *pathname)
  175. {
  176. int status;
  177. if (!adev)
  178. return -ENOENT;
  179. status = acpi_get_handle(adev->handle, pathname, &aml_mutex);
  180. if (ACPI_FAILURE(status))
  181. return -ENOENT;
  182. return 0;
  183. }
  184. EXPORT_SYMBOL(cros_ec_lpc_mec_acpi_mutex);