Loading...
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
7#include "sti_awg_utils.h"
8
9#define AWG_OPCODE_OFFSET 10
10#define AWG_MAX_ARG 0x3ff
11
12enum opcode {
13 SET,
14 RPTSET,
15 RPLSET,
16 SKIP,
17 STOP,
18 REPEAT,
19 REPLAY,
20 JUMP,
21 HOLD,
22};
23
24static int awg_generate_instr(enum opcode opcode,
25 long int arg,
26 long int mux_sel,
27 long int data_en,
28 struct awg_code_generation_params *fwparams)
29{
30 u32 instruction = 0;
31 u32 mux = (mux_sel << 8) & 0x1ff;
32 u32 data_enable = (data_en << 9) & 0x2ff;
33 long int arg_tmp = arg;
34
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.
38 *
39 * mux_sel is used in case of SAV/EAV synchronization.
40 */
41
42 while (arg_tmp > 0) {
43 arg = arg_tmp;
44 if (fwparams->instruction_offset >= AWG_MAX_INST) {
45 DRM_ERROR("too many number of instructions\n");
46 return -EINVAL;
47 }
48
49 switch (opcode) {
50 case SKIP:
51 /* leave 'arg' + 1 pixel elapsing without changing
52 * output bus */
53 arg--; /* pixel adjustment */
54 arg_tmp--;
55
56 if (arg < 0) {
57 /* SKIP instruction not needed */
58 return 0;
59 }
60
61 if (arg == 0) {
62 /* SKIP 0 not permitted but we want to skip 1
63 * pixel. So we transform SKIP into SET
64 * instruction */
65 opcode = SET;
66 break;
67 }
68
69 mux = 0;
70 data_enable = 0;
71 arg &= AWG_MAX_ARG;
72 break;
73 case REPEAT:
74 case REPLAY:
75 if (arg == 0) {
76 /* REPEAT or REPLAY instruction not needed */
77 return 0;
78 }
79
80 mux = 0;
81 data_enable = 0;
82 arg &= AWG_MAX_ARG;
83 break;
84 case JUMP:
85 mux = 0;
86 data_enable = 0;
87 arg |= 0x40; /* for jump instruction 7th bit is 1 */
88 arg &= AWG_MAX_ARG;
89 break;
90 case STOP:
91 arg = 0;
92 break;
93 case SET:
94 case RPTSET:
95 case RPLSET:
96 case HOLD:
97 arg &= (0x0ff);
98 break;
99 default:
100 DRM_ERROR("instruction %d does not exist\n", opcode);
101 return -EINVAL;
102 }
103
104 arg_tmp = arg_tmp - arg;
105
106 arg = ((arg + mux) + data_enable);
107
108 instruction = ((opcode) << AWG_OPCODE_OFFSET) | arg;
109 fwparams->ram_code[fwparams->instruction_offset] =
110 instruction & (0x3fff);
111 fwparams->instruction_offset++;
112 }
113 return 0;
114}
115
116static int awg_generate_line_signal(
117 struct awg_code_generation_params *fwparams,
118 struct awg_timing *timing)
119{
120 long int val;
121 int ret = 0;
122
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);
127
128 val = timing->trailing_pixels - 1;
129 ret |= awg_generate_instr(SKIP, val, 0, 0, fwparams);
130 }
131
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);
136
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);
141
142 /* set DE signal low */
143 val = timing->blanking_level;
144 ret |= awg_generate_instr(SET, val, 0, 0, fwparams);
145 }
146
147 return ret;
148}
149
150int sti_awg_generate_code_data_enable_mode(
151 struct awg_code_generation_params *fwparams,
152 struct awg_timing *timing)
153{
154 long int val, tmp_val;
155 int ret = 0;
156
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);
161
162 val = timing->trailing_lines - 1;
163 ret |= awg_generate_instr(REPLAY, val, 0, 0, fwparams);
164 }
165
166 tmp_val = timing->active_lines - 1;
167
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),
174 0, 0, fwparams);
175 tmp_val -= AWG_MAX_ARG;
176 }
177
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);
182
183 val = timing->blanking_lines - 1;
184 ret |= awg_generate_instr(REPLAY, val, 0, 0, fwparams);
185 }
186
187 return ret;
188}
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) STMicroelectronics SA 2014
4 * Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
5 */
6
7#include <drm/drm_print.h>
8
9#include "sti_awg_utils.h"
10
11#define AWG_DELAY (-5)
12
13#define AWG_OPCODE_OFFSET 10
14#define AWG_MAX_ARG 0x3ff
15
16enum opcode {
17 SET,
18 RPTSET,
19 RPLSET,
20 SKIP,
21 STOP,
22 REPEAT,
23 REPLAY,
24 JUMP,
25 HOLD,
26};
27
28static int awg_generate_instr(enum opcode opcode,
29 long int arg,
30 long int mux_sel,
31 long int data_en,
32 struct awg_code_generation_params *fwparams)
33{
34 u32 instruction = 0;
35 u32 mux = (mux_sel << 8) & 0x1ff;
36 u32 data_enable = (data_en << 9) & 0x2ff;
37 long int arg_tmp = arg;
38
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.
42 *
43 * mux_sel is used in case of SAV/EAV synchronization.
44 */
45
46 while (arg_tmp > 0) {
47 arg = arg_tmp;
48 if (fwparams->instruction_offset >= AWG_MAX_INST) {
49 DRM_ERROR("too many number of instructions\n");
50 return -EINVAL;
51 }
52
53 switch (opcode) {
54 case SKIP:
55 /* leave 'arg' + 1 pixel elapsing without changing
56 * output bus */
57 arg--; /* pixel adjustment */
58 arg_tmp--;
59
60 if (arg < 0) {
61 /* SKIP instruction not needed */
62 return 0;
63 }
64
65 if (arg == 0) {
66 /* SKIP 0 not permitted but we want to skip 1
67 * pixel. So we transform SKIP into SET
68 * instruction */
69 opcode = SET;
70 break;
71 }
72
73 mux = 0;
74 data_enable = 0;
75 arg &= AWG_MAX_ARG;
76 break;
77 case REPEAT:
78 case REPLAY:
79 if (arg == 0) {
80 /* REPEAT or REPLAY instruction not needed */
81 return 0;
82 }
83
84 mux = 0;
85 data_enable = 0;
86 arg &= AWG_MAX_ARG;
87 break;
88 case JUMP:
89 mux = 0;
90 data_enable = 0;
91 arg |= 0x40; /* for jump instruction 7th bit is 1 */
92 arg &= AWG_MAX_ARG;
93 break;
94 case STOP:
95 arg = 0;
96 break;
97 case SET:
98 case RPTSET:
99 case RPLSET:
100 case HOLD:
101 arg &= (0x0ff);
102 break;
103 default:
104 DRM_ERROR("instruction %d does not exist\n", opcode);
105 return -EINVAL;
106 }
107
108 arg_tmp = arg_tmp - arg;
109
110 arg = ((arg + mux) + data_enable);
111
112 instruction = ((opcode) << AWG_OPCODE_OFFSET) | arg;
113 fwparams->ram_code[fwparams->instruction_offset] =
114 instruction & (0x3fff);
115 fwparams->instruction_offset++;
116 }
117 return 0;
118}
119
120static int awg_generate_line_signal(
121 struct awg_code_generation_params *fwparams,
122 struct awg_timing *timing)
123{
124 long int val;
125 int ret = 0;
126
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);
131
132 val = timing->trailing_pixels - 1 + AWG_DELAY;
133 ret |= awg_generate_instr(SKIP, val, 0, 0, fwparams);
134 }
135
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);
140
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);
145
146 /* set DE signal low */
147 val = timing->blanking_level;
148 ret |= awg_generate_instr(SET, val, 0, 0, fwparams);
149 }
150
151 return ret;
152}
153
154int sti_awg_generate_code_data_enable_mode(
155 struct awg_code_generation_params *fwparams,
156 struct awg_timing *timing)
157{
158 long int val, tmp_val;
159 int ret = 0;
160
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);
165
166 val = timing->trailing_lines - 1;
167 ret |= awg_generate_instr(REPLAY, val, 0, 0, fwparams);
168 }
169
170 tmp_val = timing->active_lines - 1;
171
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),
178 0, 0, fwparams);
179 tmp_val -= AWG_MAX_ARG;
180 }
181
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);
186
187 val = timing->blanking_lines - 1;
188 ret |= awg_generate_instr(REPLAY, val, 0, 0, fwparams);
189 }
190
191 return ret;
192}