sti_awg_utils.c 3.9 KB

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