1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) STMicroelectronics SA 2014
7 #include <drm/drm_print.h>
9 #include "sti_awg_utils.h"
11 #define AWG_DELAY (-5)
13 #define AWG_OPCODE_OFFSET 10
14 #define AWG_MAX_ARG 0x3ff
28 static int awg_generate_instr(enum opcode opcode,
32 struct awg_code_generation_params *fwparams)
35 u32 mux = (mux_sel << 8) & 0x1ff;
36 u32 data_enable = (data_en << 9) & 0x2ff;
37 long int arg_tmp = arg;
39 /* skip, repeat and replay arg should not exceed 1023.
40 * If user wants to exceed this value, the instruction should be
41 * duplicate and arg should be adjust for each duplicated instruction.
43 * mux_sel is used in case of SAV/EAV synchronization.
48 if (fwparams->instruction_offset >= AWG_MAX_INST) {
49 DRM_ERROR("too many number of instructions\n");
55 /* leave 'arg' + 1 pixel elapsing without changing
57 arg--; /* pixel adjustment */
61 /* SKIP instruction not needed */
66 /* SKIP 0 not permitted but we want to skip 1
67 * pixel. So we transform SKIP into SET
80 /* REPEAT or REPLAY instruction not needed */
91 arg |= 0x40; /* for jump instruction 7th bit is 1 */
104 DRM_ERROR("instruction %d does not exist\n", opcode);
108 arg_tmp = arg_tmp - arg;
110 arg = ((arg + mux) + data_enable);
112 instruction = ((opcode) << AWG_OPCODE_OFFSET) | arg;
113 fwparams->ram_code[fwparams->instruction_offset] =
114 instruction & (0x3fff);
115 fwparams->instruction_offset++;
120 static int awg_generate_line_signal(
121 struct awg_code_generation_params *fwparams,
122 struct awg_timing *timing)
127 if (timing->trailing_pixels > 0) {
128 /* skip trailing pixel */
129 val = timing->blanking_level;
130 ret |= awg_generate_instr(RPLSET, val, 0, 0, fwparams);
132 val = timing->trailing_pixels - 1 + AWG_DELAY;
133 ret |= awg_generate_instr(SKIP, val, 0, 0, fwparams);
136 /* set DE signal high */
137 val = timing->blanking_level;
138 ret |= awg_generate_instr((timing->trailing_pixels > 0) ? SET : RPLSET,
139 val, 0, 1, fwparams);
141 if (timing->blanking_pixels > 0) {
142 /* skip the number of active pixel */
143 val = timing->active_pixels - 1;
144 ret |= awg_generate_instr(SKIP, val, 0, 1, fwparams);
146 /* set DE signal low */
147 val = timing->blanking_level;
148 ret |= awg_generate_instr(SET, val, 0, 0, fwparams);
154 int sti_awg_generate_code_data_enable_mode(
155 struct awg_code_generation_params *fwparams,
156 struct awg_timing *timing)
158 long int val, tmp_val;
161 if (timing->trailing_lines > 0) {
162 /* skip trailing lines */
163 val = timing->blanking_level;
164 ret |= awg_generate_instr(RPLSET, val, 0, 0, fwparams);
166 val = timing->trailing_lines - 1;
167 ret |= awg_generate_instr(REPLAY, val, 0, 0, fwparams);
170 tmp_val = timing->active_lines - 1;
172 while (tmp_val > 0) {
173 /* generate DE signal for each line */
174 ret |= awg_generate_line_signal(fwparams, timing);
175 /* replay the sequence as many active lines defined */
176 ret |= awg_generate_instr(REPLAY,
177 min_t(int, AWG_MAX_ARG, tmp_val),
179 tmp_val -= AWG_MAX_ARG;
182 if (timing->blanking_lines > 0) {
183 /* skip blanking lines */
184 val = timing->blanking_level;
185 ret |= awg_generate_instr(RPLSET, val, 0, 0, fwparams);
187 val = timing->blanking_lines - 1;
188 ret |= awg_generate_instr(REPLAY, val, 0, 0, fwparams);