etnaviv_flop_reset.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2025 Etnaviv Project
  4. */
  5. #include <linux/errno.h>
  6. #include <linux/dev_printk.h>
  7. #include <linux/string.h>
  8. #include <linux/types.h>
  9. #include "etnaviv_buffer.h"
  10. #include "etnaviv_cmdbuf.h"
  11. #include "etnaviv_gpu.h"
  12. #include "state_3d.xml.h"
  13. #include "etnaviv_flop_reset.h"
  14. static int etnaviv_force_flop_reset;
  15. module_param_named(force_flop_reset, etnaviv_force_flop_reset, int, 0);
  16. #define PPU_IMAGE_STRIDE 64
  17. #define PPU_IMAGE_XSIZE 64
  18. #define PPU_IMAGE_YSIZE 6
  19. #define PPU_FLOP_RESET_INSTR_DWORD_COUNT 16
  20. static void etnaviv_emit_flop_reset_state_ppu(struct etnaviv_cmdbuf *cmdbuf,
  21. u32 buffer_base, u32 input_offset,
  22. u32 output_offset,
  23. u32 shader_offset,
  24. u32 shader_size,
  25. u32 shader_register_count)
  26. {
  27. CMD_LOAD_STATE(cmdbuf, VIVS_GL_API_MODE, VIVS_GL_API_MODE_OPENCL);
  28. CMD_SEM(cmdbuf, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_PE);
  29. CMD_STALL(cmdbuf, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_PE);
  30. CMD_LOAD_STATES_START(cmdbuf, VIVS_SH_HALTI5_UNIFORMS(0), 4);
  31. OUT(cmdbuf, buffer_base + input_offset);
  32. OUT(cmdbuf, PPU_IMAGE_STRIDE);
  33. OUT(cmdbuf, PPU_IMAGE_XSIZE | (PPU_IMAGE_YSIZE << 16));
  34. OUT(cmdbuf, 0x444051f0);
  35. OUT(cmdbuf, 0xffffffff);
  36. CMD_LOAD_STATES_START(cmdbuf, VIVS_SH_HALTI5_UNIFORMS(4), 4);
  37. OUT(cmdbuf, buffer_base + output_offset);
  38. OUT(cmdbuf, PPU_IMAGE_STRIDE);
  39. OUT(cmdbuf, PPU_IMAGE_XSIZE | (PPU_IMAGE_YSIZE << 16));
  40. OUT(cmdbuf, 0x444051f0);
  41. OUT(cmdbuf, 0xffffffff);
  42. CMD_LOAD_STATE(cmdbuf, VIVS_CL_CONFIG,
  43. VIVS_CL_CONFIG_DIMENSIONS(2) |
  44. VIVS_CL_CONFIG_VALUE_ORDER(3));
  45. CMD_LOAD_STATE(cmdbuf, VIVS_VS_ICACHE_INVALIDATE, 0x1f);
  46. CMD_LOAD_STATE(cmdbuf, VIVS_PS_VARYING_NUM_COMPONENTS(0), 0);
  47. CMD_LOAD_STATE(cmdbuf, VIVS_PS_TEMP_REGISTER_CONTROL,
  48. shader_register_count);
  49. CMD_LOAD_STATE(cmdbuf, VIVS_PS_SAMPLER_BASE, 0x0);
  50. CMD_LOAD_STATE(cmdbuf, VIVS_PS_UNIFORM_BASE, 0x0);
  51. CMD_LOAD_STATE(cmdbuf, VIVS_PS_NEWRANGE_LOW, 0x0);
  52. CMD_LOAD_STATE(cmdbuf, VIVS_PS_NEWRANGE_HIGH, shader_size / 16);
  53. CMD_LOAD_STATE(cmdbuf, VIVS_PS_INST_ADDR, buffer_base + shader_offset);
  54. CMD_LOAD_STATE(cmdbuf, VIVS_SH_CONFIG, VIVS_SH_CONFIG_RTNE_ROUNDING);
  55. CMD_LOAD_STATE(cmdbuf, VIVS_VS_ICACHE_CONTROL,
  56. VIVS_VS_ICACHE_CONTROL_ENABLE);
  57. CMD_LOAD_STATE(cmdbuf, VIVS_PS_ICACHE_COUNT, shader_size / 16 - 1);
  58. CMD_LOAD_STATE(cmdbuf, VIVS_PS_INPUT_COUNT, 0x1f01);
  59. CMD_LOAD_STATE(cmdbuf, VIVS_VS_HALTI5_UNK008A0, 0x0);
  60. CMD_LOAD_STATE(cmdbuf, VIVS_PA_VS_OUTPUT_COUNT, 0x0);
  61. CMD_LOAD_STATE(cmdbuf, VIVS_GL_VARYING_TOTAL_COMPONENTS, 0x0);
  62. CMD_LOAD_STATE(cmdbuf, VIVS_PS_CONTROL_EXT, 0x0);
  63. CMD_LOAD_STATE(cmdbuf, VIVS_VS_OUTPUT_COUNT, 0x1);
  64. CMD_LOAD_STATE(cmdbuf, VIVS_GL_HALTI5_SH_SPECIALS, 0x0);
  65. CMD_LOAD_STATE(cmdbuf, VIVS_PS_ICACHE_PREFETCH, 0x0);
  66. CMD_LOAD_STATE(cmdbuf, VIVS_CL_UNK00924, 0x0);
  67. CMD_LOAD_STATE(cmdbuf, VIVS_CL_THREAD_ALLOCATION, 0x1);
  68. CMD_LOAD_STATE(cmdbuf, VIVS_CL_GLOBAL_WORK_OFFSET_X, 0x0);
  69. CMD_LOAD_STATE(cmdbuf, VIVS_CL_GLOBAL_WORK_OFFSET_Y, 0x0);
  70. CMD_LOAD_STATE(cmdbuf, VIVS_CL_GLOBAL_WORK_OFFSET_Z, 0x0);
  71. CMD_LOAD_STATES_START(cmdbuf, VIVS_CL_WORKGROUP_COUNT_X, 9);
  72. OUT(cmdbuf, 0xf);
  73. OUT(cmdbuf, 0x5);
  74. OUT(cmdbuf, 0xffffffff);
  75. OUT(cmdbuf, 0x0);
  76. OUT(cmdbuf, 0x0);
  77. OUT(cmdbuf, 0x3ff);
  78. OUT(cmdbuf, 0x0);
  79. OUT(cmdbuf, 0x4);
  80. OUT(cmdbuf, 0x1);
  81. OUT(cmdbuf, 0x0);
  82. CMD_LOAD_STATE(cmdbuf, VIVS_CL_KICKER, 0xbadabeeb);
  83. CMD_LOAD_STATE(cmdbuf, VIVS_GL_FLUSH_CACHE,
  84. VIVS_GL_FLUSH_CACHE_SHADER_L1 |
  85. VIVS_GL_FLUSH_CACHE_UNK10 |
  86. VIVS_GL_FLUSH_CACHE_UNK11);
  87. }
  88. static void etnaviv_flop_reset_ppu_fill_input(u32 *buffer, u32 size)
  89. {
  90. memset32(buffer, 0x01010101, size / 4);
  91. }
  92. static void etnaviv_flop_reset_ppu_set_shader(u8 *dest)
  93. {
  94. static const u32 inst[PPU_FLOP_RESET_INSTR_DWORD_COUNT] = {
  95. /* img_load.u8 r1, c0, r0.xy */
  96. 0x78011779,
  97. 0x39000804,
  98. 0x00A90050,
  99. 0x00000000,
  100. /* img_load.u8 r2, c0, r0.xy */
  101. 0x78021779,
  102. 0x39000804,
  103. 0x00A90050,
  104. 0x00000000,
  105. /* dp2x8 r1, r1, r2, c3_512 */
  106. 0xB8017145,
  107. 0x390018FC,
  108. 0x01C90140,
  109. 0x40390028,
  110. /* img_store.u8 r1, c2, r0.xy, r1 */
  111. 0x380007BA,
  112. 0x39001804,
  113. 0x00A90050,
  114. 0x00390018,
  115. };
  116. memcpy(dest, inst, sizeof(inst));
  117. }
  118. static const struct etnaviv_flop_reset_entry {
  119. u16 chip_model;
  120. u16 revision;
  121. u32 flags;
  122. } etnaviv_flop_reset_db[] = {
  123. {
  124. .chip_model = 0x8000,
  125. .revision = 0x6205,
  126. },
  127. };
  128. bool etnaviv_flop_reset_ppu_require(const struct etnaviv_chip_identity *chip_id)
  129. {
  130. const struct etnaviv_flop_reset_entry *e = etnaviv_flop_reset_db;
  131. for (int i = 0; i < ARRAY_SIZE(etnaviv_flop_reset_db); ++i, ++e) {
  132. if (chip_id->model == e->chip_model &&
  133. chip_id->revision == e->revision)
  134. return true;
  135. }
  136. if (etnaviv_force_flop_reset) {
  137. if (!(chip_id->features & chipFeatures_PIPE_3D)) {
  138. pr_warn("Etnaviv: model: 0x%04x, revision: 0x%04x does not support PIPE_3D\n",
  139. chip_id->model, chip_id->revision);
  140. pr_warn("Request to force PPU flop reset ignored.\n");
  141. return false;
  142. }
  143. pr_info("Force PPU flop reset for model: 0x%04x, revision: 0x%04x\n",
  144. chip_id->model, chip_id->revision);
  145. return true;
  146. }
  147. return false;
  148. }
  149. static const u32 image_data_size = PPU_IMAGE_STRIDE * PPU_IMAGE_YSIZE;
  150. static const u32 output_offset = ALIGN(image_data_size, 64);
  151. static const u32 shader_offset = ALIGN(output_offset + image_data_size, 64);
  152. static const u32 shader_size = PPU_FLOP_RESET_INSTR_DWORD_COUNT * sizeof(u32);
  153. static const u32 shader_register_count = 3;
  154. static const u32 buffer_size = shader_offset + shader_size;
  155. int etnaviv_flop_reset_ppu_init(struct etnaviv_drm_private *priv)
  156. {
  157. /* Get some space from the ring buffer to put the payload
  158. * (input and output image, and shader), we keep this buffer
  159. * for the whole life time the driver is bound
  160. */
  161. priv->flop_reset_data_ppu = kzalloc_obj(*priv->flop_reset_data_ppu);
  162. if (!priv->flop_reset_data_ppu)
  163. return -ENOMEM;
  164. int ret = etnaviv_cmdbuf_init(priv->cmdbuf_suballoc,
  165. priv->flop_reset_data_ppu, buffer_size);
  166. if (ret) {
  167. kfree(priv->flop_reset_data_ppu);
  168. return ret;
  169. }
  170. void *buffer_base = priv->flop_reset_data_ppu->vaddr;
  171. u32 *input_data = (u32 *)buffer_base;
  172. u8 *shader_data = (u8 *)buffer_base + shader_offset;
  173. etnaviv_flop_reset_ppu_fill_input(input_data, image_data_size);
  174. etnaviv_flop_reset_ppu_set_shader(shader_data);
  175. return 0;
  176. }
  177. void etnaviv_flop_reset_ppu_run(struct etnaviv_gpu *gpu)
  178. {
  179. struct etnaviv_drm_private *priv = gpu->drm->dev_private;
  180. if (!priv->flop_reset_data_ppu) {
  181. dev_err(gpu->dev,
  182. "Oops: Flop reset data was not initialized, skipping\n");
  183. return;
  184. }
  185. u32 buffer_base = etnaviv_cmdbuf_get_va(priv->flop_reset_data_ppu,
  186. &gpu->mmu_context->cmdbuf_mapping);
  187. etnaviv_emit_flop_reset_state_ppu(&gpu->buffer, buffer_base, 0,
  188. output_offset, shader_offset,
  189. shader_size, shader_register_count);
  190. }