sti_awg_utils.c 4.1 KB

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