gt215.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. /*
  2. * Copyright 2013 Red Hat Inc.
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  17. * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  18. * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19. * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20. * OTHER DEALINGS IN THE SOFTWARE.
  21. *
  22. * Authors: Ben Skeggs
  23. */
  24. #include "priv.h"
  25. #include "fuc/gt215.fuc3.h"
  26. #include <subdev/timer.h>
  27. int
  28. gt215_pmu_send(struct nvkm_pmu *pmu, u32 reply[2],
  29. u32 process, u32 message, u32 data0, u32 data1)
  30. {
  31. struct nvkm_subdev *subdev = &pmu->subdev;
  32. struct nvkm_device *device = subdev->device;
  33. u32 addr;
  34. mutex_lock(&subdev->mutex);
  35. /* wait for a free slot in the fifo */
  36. addr = nvkm_rd32(device, 0x10a4a0);
  37. if (nvkm_msec(device, 2000,
  38. u32 tmp = nvkm_rd32(device, 0x10a4b0);
  39. if (tmp != (addr ^ 8))
  40. break;
  41. ) < 0) {
  42. mutex_unlock(&subdev->mutex);
  43. return -EBUSY;
  44. }
  45. /* we currently only support a single process at a time waiting
  46. * on a synchronous reply, take the PMU mutex and tell the
  47. * receive handler what we're waiting for
  48. */
  49. if (reply) {
  50. pmu->recv.message = message;
  51. pmu->recv.process = process;
  52. }
  53. /* acquire data segment access */
  54. do {
  55. nvkm_wr32(device, 0x10a580, 0x00000001);
  56. } while (nvkm_rd32(device, 0x10a580) != 0x00000001);
  57. /* write the packet */
  58. nvkm_wr32(device, 0x10a1c0, 0x01000000 | (((addr & 0x07) << 4) +
  59. pmu->send.base));
  60. nvkm_wr32(device, 0x10a1c4, process);
  61. nvkm_wr32(device, 0x10a1c4, message);
  62. nvkm_wr32(device, 0x10a1c4, data0);
  63. nvkm_wr32(device, 0x10a1c4, data1);
  64. nvkm_wr32(device, 0x10a4a0, (addr + 1) & 0x0f);
  65. /* release data segment access */
  66. nvkm_wr32(device, 0x10a580, 0x00000000);
  67. /* wait for reply, if requested */
  68. if (reply) {
  69. wait_event(pmu->recv.wait, (pmu->recv.process == 0));
  70. reply[0] = pmu->recv.data[0];
  71. reply[1] = pmu->recv.data[1];
  72. }
  73. mutex_unlock(&subdev->mutex);
  74. return 0;
  75. }
  76. void
  77. gt215_pmu_recv(struct nvkm_pmu *pmu)
  78. {
  79. struct nvkm_subdev *subdev = &pmu->subdev;
  80. struct nvkm_device *device = subdev->device;
  81. u32 process, message, data0, data1;
  82. /* nothing to do if GET == PUT */
  83. u32 addr = nvkm_rd32(device, 0x10a4cc);
  84. if (addr == nvkm_rd32(device, 0x10a4c8))
  85. return;
  86. /* acquire data segment access */
  87. do {
  88. nvkm_wr32(device, 0x10a580, 0x00000002);
  89. } while (nvkm_rd32(device, 0x10a580) != 0x00000002);
  90. /* read the packet */
  91. nvkm_wr32(device, 0x10a1c0, 0x02000000 | (((addr & 0x07) << 4) +
  92. pmu->recv.base));
  93. process = nvkm_rd32(device, 0x10a1c4);
  94. message = nvkm_rd32(device, 0x10a1c4);
  95. data0 = nvkm_rd32(device, 0x10a1c4);
  96. data1 = nvkm_rd32(device, 0x10a1c4);
  97. nvkm_wr32(device, 0x10a4cc, (addr + 1) & 0x0f);
  98. /* release data segment access */
  99. nvkm_wr32(device, 0x10a580, 0x00000000);
  100. /* wake process if it's waiting on a synchronous reply */
  101. if (pmu->recv.process) {
  102. if (process == pmu->recv.process &&
  103. message == pmu->recv.message) {
  104. pmu->recv.data[0] = data0;
  105. pmu->recv.data[1] = data1;
  106. pmu->recv.process = 0;
  107. wake_up(&pmu->recv.wait);
  108. return;
  109. }
  110. }
  111. /* right now there's no other expected responses from the engine,
  112. * so assume that any unexpected message is an error.
  113. */
  114. nvkm_warn(subdev, "%c%c%c%c %08x %08x %08x %08x\n",
  115. (char)((process & 0x000000ff) >> 0),
  116. (char)((process & 0x0000ff00) >> 8),
  117. (char)((process & 0x00ff0000) >> 16),
  118. (char)((process & 0xff000000) >> 24),
  119. process, message, data0, data1);
  120. }
  121. void
  122. gt215_pmu_intr(struct nvkm_pmu *pmu)
  123. {
  124. struct nvkm_subdev *subdev = &pmu->subdev;
  125. struct nvkm_device *device = subdev->device;
  126. u32 disp = nvkm_rd32(device, 0x10a01c);
  127. u32 intr = nvkm_rd32(device, 0x10a008) & disp & ~(disp >> 16);
  128. if (intr & 0x00000020) {
  129. u32 stat = nvkm_rd32(device, 0x10a16c);
  130. if (stat & 0x80000000) {
  131. nvkm_error(subdev, "UAS fault at %06x addr %08x\n",
  132. stat & 0x00ffffff,
  133. nvkm_rd32(device, 0x10a168));
  134. nvkm_wr32(device, 0x10a16c, 0x00000000);
  135. intr &= ~0x00000020;
  136. }
  137. }
  138. if (intr & 0x00000040) {
  139. schedule_work(&pmu->recv.work);
  140. nvkm_wr32(device, 0x10a004, 0x00000040);
  141. intr &= ~0x00000040;
  142. }
  143. if (intr & 0x00000080) {
  144. nvkm_info(subdev, "wr32 %06x %08x\n",
  145. nvkm_rd32(device, 0x10a7a0),
  146. nvkm_rd32(device, 0x10a7a4));
  147. nvkm_wr32(device, 0x10a004, 0x00000080);
  148. intr &= ~0x00000080;
  149. }
  150. if (intr) {
  151. nvkm_error(subdev, "intr %08x\n", intr);
  152. nvkm_wr32(device, 0x10a004, intr);
  153. }
  154. }
  155. void
  156. gt215_pmu_fini(struct nvkm_pmu *pmu)
  157. {
  158. nvkm_wr32(pmu->subdev.device, 0x10a014, 0x00000060);
  159. }
  160. void
  161. gt215_pmu_reset(struct nvkm_pmu *pmu)
  162. {
  163. struct nvkm_device *device = pmu->subdev.device;
  164. nvkm_mask(device, 0x000200, 0x00002000, 0x00000000);
  165. nvkm_mask(device, 0x000200, 0x00002000, 0x00002000);
  166. nvkm_rd32(device, 0x000200);
  167. }
  168. int
  169. gt215_pmu_init(struct nvkm_pmu *pmu)
  170. {
  171. struct nvkm_device *device = pmu->subdev.device;
  172. int i;
  173. /* upload data segment */
  174. nvkm_wr32(device, 0x10a1c0, 0x01000000);
  175. for (i = 0; i < pmu->func->data.size / 4; i++)
  176. nvkm_wr32(device, 0x10a1c4, pmu->func->data.data[i]);
  177. /* upload code segment */
  178. nvkm_wr32(device, 0x10a180, 0x01000000);
  179. for (i = 0; i < pmu->func->code.size / 4; i++) {
  180. if ((i & 0x3f) == 0)
  181. nvkm_wr32(device, 0x10a188, i >> 6);
  182. nvkm_wr32(device, 0x10a184, pmu->func->code.data[i]);
  183. }
  184. /* start it running */
  185. nvkm_wr32(device, 0x10a10c, 0x00000000);
  186. nvkm_wr32(device, 0x10a104, 0x00000000);
  187. nvkm_wr32(device, 0x10a100, 0x00000002);
  188. /* wait for valid host->pmu ring configuration */
  189. if (nvkm_msec(device, 2000,
  190. if (nvkm_rd32(device, 0x10a4d0))
  191. break;
  192. ) < 0)
  193. return -EBUSY;
  194. pmu->send.base = nvkm_rd32(device, 0x10a4d0) & 0x0000ffff;
  195. pmu->send.size = nvkm_rd32(device, 0x10a4d0) >> 16;
  196. /* wait for valid pmu->host ring configuration */
  197. if (nvkm_msec(device, 2000,
  198. if (nvkm_rd32(device, 0x10a4dc))
  199. break;
  200. ) < 0)
  201. return -EBUSY;
  202. pmu->recv.base = nvkm_rd32(device, 0x10a4dc) & 0x0000ffff;
  203. pmu->recv.size = nvkm_rd32(device, 0x10a4dc) >> 16;
  204. nvkm_wr32(device, 0x10a010, 0x000000e0);
  205. return 0;
  206. }
  207. static const struct nvkm_pmu_func
  208. gt215_pmu = {
  209. .code.data = gt215_pmu_code,
  210. .code.size = sizeof(gt215_pmu_code),
  211. .data.data = gt215_pmu_data,
  212. .data.size = sizeof(gt215_pmu_data),
  213. .reset = gt215_pmu_reset,
  214. .init = gt215_pmu_init,
  215. .fini = gt215_pmu_fini,
  216. .intr = gt215_pmu_intr,
  217. .send = gt215_pmu_send,
  218. .recv = gt215_pmu_recv,
  219. };
  220. int
  221. gt215_pmu_new(struct nvkm_device *device, int index, struct nvkm_pmu **ppmu)
  222. {
  223. return nvkm_pmu_new_(&gt215_pmu, device, index, ppmu);
  224. }