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
7 #include "sti_awg_utils.h"
9 #define AWG_OPCODE_OFFSET 10
10 #define AWG_MAX_ARG 0x3ff
24 static int awg_generate_instr(enum opcode opcode,
28 struct awg_code_generation_params *fwparams)
31 u32 mux = (mux_sel << 8) & 0x1ff;
32 u32 data_enable = (data_en << 9) & 0x2ff;
33 long int arg_tmp = arg;
35 /* skip, repeat and replay arg should not exceed 1023.
36 * If user wants to exceed this value, the instruction should be
37 * duplicate and arg should be adjust for each duplicated instruction.
39 * mux_sel is used in case of SAV/EAV synchronization.
44 if (fwparams->instruction_offset >= AWG_MAX_INST) {
45 DRM_ERROR("too many number of instructions\n");
51 /* leave 'arg' + 1 pixel elapsing without changing
53 arg--; /* pixel adjustment */
57 /* SKIP instruction not needed */
62 /* SKIP 0 not permitted but we want to skip 1
63 * pixel. So we transform SKIP into SET
76 /* REPEAT or REPLAY instruction not needed */
87 arg |= 0x40; /* for jump instruction 7th bit is 1 */
100 DRM_ERROR("instruction %d does not exist\n", opcode);
104 arg_tmp = arg_tmp - arg;
106 arg = ((arg + mux) + data_enable);
108 instruction = ((opcode) << AWG_OPCODE_OFFSET) | arg;
109 fwparams->ram_code[fwparams->instruction_offset] =
110 instruction & (0x3fff);
111 fwparams->instruction_offset++;
116 static int awg_generate_line_signal(
117 struct awg_code_generation_params *fwparams,
118 struct awg_timing *timing)
123 if (timing->trailing_pixels > 0) {
124 /* skip trailing pixel */
125 val = timing->blanking_level;
126 ret |= awg_generate_instr(RPLSET, val, 0, 0, fwparams);
128 val = timing->trailing_pixels - 1;
129 ret |= awg_generate_instr(SKIP, val, 0, 0, fwparams);
132 /* set DE signal high */
133 val = timing->blanking_level;
134 ret |= awg_generate_instr((timing->trailing_pixels > 0) ? SET : RPLSET,
135 val, 0, 1, fwparams);
137 if (timing->blanking_pixels > 0) {
138 /* skip the number of active pixel */
139 val = timing->active_pixels - 1;
140 ret |= awg_generate_instr(SKIP, val, 0, 1, fwparams);
142 /* set DE signal low */
143 val = timing->blanking_level;
144 ret |= awg_generate_instr(SET, val, 0, 0, fwparams);
150 int sti_awg_generate_code_data_enable_mode(
151 struct awg_code_generation_params *fwparams,
152 struct awg_timing *timing)
154 long int val, tmp_val;
157 if (timing->trailing_lines > 0) {
158 /* skip trailing lines */
159 val = timing->blanking_level;
160 ret |= awg_generate_instr(RPLSET, val, 0, 0, fwparams);
162 val = timing->trailing_lines - 1;
163 ret |= awg_generate_instr(REPLAY, val, 0, 0, fwparams);
166 tmp_val = timing->active_lines - 1;
168 while (tmp_val > 0) {
169 /* generate DE signal for each line */
170 ret |= awg_generate_line_signal(fwparams, timing);
171 /* replay the sequence as many active lines defined */
172 ret |= awg_generate_instr(REPLAY,
173 min_t(int, AWG_MAX_ARG, tmp_val),
175 tmp_val -= AWG_MAX_ARG;
178 if (timing->blanking_lines > 0) {
179 /* skip blanking lines */
180 val = timing->blanking_level;
181 ret |= awg_generate_instr(RPLSET, val, 0, 0, fwparams);
183 val = timing->blanking_lines - 1;
184 ret |= awg_generate_instr(REPLAY, val, 0, 0, fwparams);