sti_awg_utils.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) STMicroelectronics SA 2014
  4. * Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
  5. */
  6. #include <drm/drm_print.h>
  7. #include "sti_awg_utils.h"
  8. #define AWG_DELAY (-5)
  9. #define AWG_OPCODE_OFFSET 10
  10. #define AWG_MAX_ARG 0x3ff
  11. enum opcode {
  12. SET,
  13. RPTSET,
  14. RPLSET,
  15. SKIP,
  16. STOP,
  17. REPEAT,
  18. REPLAY,
  19. JUMP,
  20. HOLD,
  21. };
  22. static int awg_generate_instr(enum opcode opcode,
  23. long int arg,
  24. long int mux_sel,
  25. long int data_en,
  26. struct awg_code_generation_params *fwparams)
  27. {
  28. u32 instruction = 0;
  29. u32 mux = (mux_sel << 8) & 0x1ff;
  30. u32 data_enable = (data_en << 9) & 0x2ff;
  31. long int arg_tmp = arg;
  32. /* skip, repeat and replay arg should not exceed 1023.
  33. * If user wants to exceed this value, the instruction should be
  34. * duplicate and arg should be adjust for each duplicated instruction.
  35. *
  36. * mux_sel is used in case of SAV/EAV synchronization.
  37. */
  38. while (arg_tmp > 0) {
  39. arg = arg_tmp;
  40. if (fwparams->instruction_offset >= AWG_MAX_INST) {
  41. DRM_ERROR("too many number of instructions\n");
  42. return -EINVAL;
  43. }
  44. switch (opcode) {
  45. case SKIP:
  46. /* leave 'arg' + 1 pixel elapsing without changing
  47. * output bus */
  48. arg--; /* pixel adjustment */
  49. arg_tmp--;
  50. if (arg < 0) {
  51. /* SKIP instruction not needed */
  52. return 0;
  53. }
  54. if (arg == 0) {
  55. /* SKIP 0 not permitted but we want to skip 1
  56. * pixel. So we transform SKIP into SET
  57. * instruction */
  58. opcode = SET;
  59. break;
  60. }
  61. mux = 0;
  62. data_enable = 0;
  63. arg &= AWG_MAX_ARG;
  64. break;
  65. case REPEAT:
  66. case REPLAY:
  67. if (arg == 0) {
  68. /* REPEAT or REPLAY instruction not needed */
  69. return 0;
  70. }
  71. mux = 0;
  72. data_enable = 0;
  73. arg &= AWG_MAX_ARG;
  74. break;
  75. case JUMP:
  76. mux = 0;
  77. data_enable = 0;
  78. arg |= 0x40; /* for jump instruction 7th bit is 1 */
  79. arg &= AWG_MAX_ARG;
  80. break;
  81. case STOP:
  82. arg = 0;
  83. break;
  84. case SET:
  85. case RPTSET:
  86. case RPLSET:
  87. case HOLD:
  88. arg &= (0x0ff);
  89. break;
  90. default:
  91. DRM_ERROR("instruction %d does not exist\n", opcode);
  92. return -EINVAL;
  93. }
  94. arg_tmp = arg_tmp - arg;
  95. arg = ((arg + mux) + data_enable);
  96. instruction = ((opcode) << AWG_OPCODE_OFFSET) | arg;
  97. fwparams->ram_code[fwparams->instruction_offset] =
  98. instruction & (0x3fff);
  99. fwparams->instruction_offset++;
  100. }
  101. return 0;
  102. }
  103. static int awg_generate_line_signal(
  104. struct awg_code_generation_params *fwparams,
  105. struct awg_timing *timing)
  106. {
  107. long int val;
  108. int ret = 0;
  109. if (timing->trailing_pixels > 0) {
  110. /* skip trailing pixel */
  111. val = timing->blanking_level;
  112. ret |= awg_generate_instr(RPLSET, val, 0, 0, fwparams);
  113. val = timing->trailing_pixels - 1 + AWG_DELAY;
  114. ret |= awg_generate_instr(SKIP, val, 0, 0, fwparams);
  115. }
  116. /* set DE signal high */
  117. val = timing->blanking_level;
  118. ret |= awg_generate_instr((timing->trailing_pixels > 0) ? SET : RPLSET,
  119. val, 0, 1, fwparams);
  120. if (timing->blanking_pixels > 0) {
  121. /* skip the number of active pixel */
  122. val = timing->active_pixels - 1;
  123. ret |= awg_generate_instr(SKIP, val, 0, 1, fwparams);
  124. /* set DE signal low */
  125. val = timing->blanking_level;
  126. ret |= awg_generate_instr(SET, val, 0, 0, fwparams);
  127. }
  128. return ret;
  129. }
  130. int sti_awg_generate_code_data_enable_mode(
  131. struct awg_code_generation_params *fwparams,
  132. struct awg_timing *timing)
  133. {
  134. long int val, tmp_val;
  135. int ret = 0;
  136. if (timing->trailing_lines > 0) {
  137. /* skip trailing lines */
  138. val = timing->blanking_level;
  139. ret |= awg_generate_instr(RPLSET, val, 0, 0, fwparams);
  140. val = timing->trailing_lines - 1;
  141. ret |= awg_generate_instr(REPLAY, val, 0, 0, fwparams);
  142. }
  143. tmp_val = timing->active_lines - 1;
  144. while (tmp_val > 0) {
  145. /* generate DE signal for each line */
  146. ret |= awg_generate_line_signal(fwparams, timing);
  147. /* replay the sequence as many active lines defined */
  148. ret |= awg_generate_instr(REPLAY,
  149. min_t(int, AWG_MAX_ARG, tmp_val),
  150. 0, 0, fwparams);
  151. tmp_val -= AWG_MAX_ARG;
  152. }
  153. if (timing->blanking_lines > 0) {
  154. /* skip blanking lines */
  155. val = timing->blanking_level;
  156. ret |= awg_generate_instr(RPLSET, val, 0, 0, fwparams);
  157. val = timing->blanking_lines - 1;
  158. ret |= awg_generate_instr(REPLAY, val, 0, 0, fwparams);
  159. }
  160. return ret;
  161. }