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