xtensa.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. /*
  2. * Copyright 2013 Ilia Mirkin
  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. #include <engine/xtensa.h>
  23. #include <core/gpuobj.h>
  24. #include <engine/fifo.h>
  25. static int
  26. nvkm_xtensa_oclass_get(struct nvkm_oclass *oclass, int index)
  27. {
  28. struct nvkm_xtensa *xtensa = nvkm_xtensa(oclass->engine);
  29. int c = 0;
  30. while (xtensa->func->sclass[c].oclass) {
  31. if (c++ == index) {
  32. oclass->base = xtensa->func->sclass[index];
  33. return index;
  34. }
  35. }
  36. return c;
  37. }
  38. static int
  39. nvkm_xtensa_cclass_bind(struct nvkm_object *object, struct nvkm_gpuobj *parent,
  40. int align, struct nvkm_gpuobj **pgpuobj)
  41. {
  42. return nvkm_gpuobj_new(object->engine->subdev.device, 0x10000, align,
  43. true, parent, pgpuobj);
  44. }
  45. static const struct nvkm_object_func
  46. nvkm_xtensa_cclass = {
  47. .bind = nvkm_xtensa_cclass_bind,
  48. };
  49. static void
  50. nvkm_xtensa_intr(struct nvkm_engine *engine)
  51. {
  52. struct nvkm_xtensa *xtensa = nvkm_xtensa(engine);
  53. struct nvkm_subdev *subdev = &xtensa->engine.subdev;
  54. struct nvkm_device *device = subdev->device;
  55. const u32 base = xtensa->addr;
  56. u32 unk104 = nvkm_rd32(device, base + 0xd04);
  57. u32 intr = nvkm_rd32(device, base + 0xc20);
  58. u32 chan = nvkm_rd32(device, base + 0xc28);
  59. u32 unk10c = nvkm_rd32(device, base + 0xd0c);
  60. if (intr & 0x10)
  61. nvkm_warn(subdev, "Watchdog interrupt, engine hung.\n");
  62. nvkm_wr32(device, base + 0xc20, intr);
  63. intr = nvkm_rd32(device, base + 0xc20);
  64. if (unk104 == 0x10001 && unk10c == 0x200 && chan && !intr) {
  65. nvkm_debug(subdev, "Enabling FIFO_CTRL\n");
  66. nvkm_mask(device, xtensa->addr + 0xd94, 0, xtensa->func->fifo_val);
  67. }
  68. }
  69. static int
  70. nvkm_xtensa_fini(struct nvkm_engine *engine, bool suspend)
  71. {
  72. struct nvkm_xtensa *xtensa = nvkm_xtensa(engine);
  73. struct nvkm_device *device = xtensa->engine.subdev.device;
  74. const u32 base = xtensa->addr;
  75. nvkm_wr32(device, base + 0xd84, 0); /* INTR_EN */
  76. nvkm_wr32(device, base + 0xd94, 0); /* FIFO_CTRL */
  77. if (!suspend)
  78. nvkm_memory_unref(&xtensa->gpu_fw);
  79. return 0;
  80. }
  81. static int
  82. nvkm_xtensa_init(struct nvkm_engine *engine)
  83. {
  84. struct nvkm_xtensa *xtensa = nvkm_xtensa(engine);
  85. struct nvkm_subdev *subdev = &xtensa->engine.subdev;
  86. struct nvkm_device *device = subdev->device;
  87. const u32 base = xtensa->addr;
  88. const struct firmware *fw;
  89. char name[32];
  90. int i, ret;
  91. u64 addr, size;
  92. u32 tmp;
  93. if (!xtensa->gpu_fw) {
  94. snprintf(name, sizeof(name), "nouveau/nv84_xuc%03x",
  95. xtensa->addr >> 12);
  96. ret = request_firmware(&fw, name, device->dev);
  97. if (ret) {
  98. nvkm_warn(subdev, "unable to load firmware %s\n", name);
  99. return ret;
  100. }
  101. if (fw->size > 0x40000) {
  102. nvkm_warn(subdev, "firmware %s too large\n", name);
  103. release_firmware(fw);
  104. return -EINVAL;
  105. }
  106. ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST,
  107. 0x40000, 0x1000, false,
  108. &xtensa->gpu_fw);
  109. if (ret) {
  110. release_firmware(fw);
  111. return ret;
  112. }
  113. nvkm_kmap(xtensa->gpu_fw);
  114. for (i = 0; i < fw->size / 4; i++)
  115. nvkm_wo32(xtensa->gpu_fw, i * 4, *((u32 *)fw->data + i));
  116. nvkm_done(xtensa->gpu_fw);
  117. release_firmware(fw);
  118. }
  119. addr = nvkm_memory_addr(xtensa->gpu_fw);
  120. size = nvkm_memory_size(xtensa->gpu_fw);
  121. nvkm_wr32(device, base + 0xd10, 0x1fffffff); /* ?? */
  122. nvkm_wr32(device, base + 0xd08, 0x0fffffff); /* ?? */
  123. nvkm_wr32(device, base + 0xd28, xtensa->func->unkd28); /* ?? */
  124. nvkm_wr32(device, base + 0xc20, 0x3f); /* INTR */
  125. nvkm_wr32(device, base + 0xd84, 0x3f); /* INTR_EN */
  126. nvkm_wr32(device, base + 0xcc0, addr >> 8); /* XT_REGION_BASE */
  127. nvkm_wr32(device, base + 0xcc4, 0x1c); /* XT_REGION_SETUP */
  128. nvkm_wr32(device, base + 0xcc8, size >> 8); /* XT_REGION_LIMIT */
  129. tmp = nvkm_rd32(device, 0x0);
  130. nvkm_wr32(device, base + 0xde0, tmp); /* SCRATCH_H2X */
  131. nvkm_wr32(device, base + 0xce8, 0xf); /* XT_REGION_SETUP */
  132. nvkm_wr32(device, base + 0xc20, 0x3f); /* INTR */
  133. nvkm_wr32(device, base + 0xd84, 0x3f); /* INTR_EN */
  134. return 0;
  135. }
  136. static void *
  137. nvkm_xtensa_dtor(struct nvkm_engine *engine)
  138. {
  139. return nvkm_xtensa(engine);
  140. }
  141. static const struct nvkm_engine_func
  142. nvkm_xtensa = {
  143. .dtor = nvkm_xtensa_dtor,
  144. .init = nvkm_xtensa_init,
  145. .fini = nvkm_xtensa_fini,
  146. .intr = nvkm_xtensa_intr,
  147. .fifo.sclass = nvkm_xtensa_oclass_get,
  148. .cclass = &nvkm_xtensa_cclass,
  149. };
  150. int
  151. nvkm_xtensa_new_(const struct nvkm_xtensa_func *func,
  152. struct nvkm_device *device, int index, bool enable,
  153. u32 addr, struct nvkm_engine **pengine)
  154. {
  155. struct nvkm_xtensa *xtensa;
  156. if (!(xtensa = kzalloc(sizeof(*xtensa), GFP_KERNEL)))
  157. return -ENOMEM;
  158. xtensa->func = func;
  159. xtensa->addr = addr;
  160. *pengine = &xtensa->engine;
  161. return nvkm_engine_ctor(&nvkm_xtensa, device, index,
  162. enable, &xtensa->engine);
  163. }