sti_awg_utils.c 4.2 KB

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