Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / drivers / gpu / drm / sti / sti_awg_utils.c
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
11 enum opcode {
12         SET,
13         RPTSET,
14         RPLSET,
15         SKIP,
16         STOP,
17         REPEAT,
18         REPLAY,
19         JUMP,
20         HOLD,
21 };
22
23 static 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.
37          */
38
39         while (arg_tmp > 0) {
40                 arg = arg_tmp;
41                 if (fwparams->instruction_offset >= AWG_MAX_INST) {
42                         DRM_ERROR("too many number of instructions\n");
43                         return -EINVAL;
44                 }
45
46                 switch (opcode) {
47                 case SKIP:
48                         /* leave 'arg' + 1 pixel elapsing without changing
49                          * output bus */
50                         arg--; /* pixel adjustment */
51                         arg_tmp--;
52
53                         if (arg < 0) {
54                                 /* SKIP instruction not needed */
55                                 return 0;
56                         }
57
58                         if (arg == 0) {
59                                 /* SKIP 0 not permitted but we want to skip 1
60                                  * pixel. So we transform SKIP into SET
61                                  * instruction */
62                                 opcode = SET;
63                                 break;
64                         }
65
66                         mux = 0;
67                         data_enable = 0;
68                         arg = (arg << 22) >> 22;
69                         arg &= (0x3ff);
70                         break;
71                 case REPEAT:
72                 case REPLAY:
73                         if (arg == 0) {
74                                 /* REPEAT or REPLAY instruction not needed */
75                                 return 0;
76                         }
77
78                         mux = 0;
79                         data_enable = 0;
80                         arg = (arg << 22) >> 22;
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 */
87                         arg = (arg << 22) >> 22;
88                         arg &= 0x3ff;
89                         break;
90                 case STOP:
91                         arg = 0;
92                         break;
93                 case SET:
94                 case RPTSET:
95                 case RPLSET:
96                 case HOLD:
97                         arg = (arg << 24) >> 24;
98                         arg &= (0x0ff);
99                         break;
100                 default:
101                         DRM_ERROR("instruction %d does not exist\n", opcode);
102                         return -EINVAL;
103                 }
104
105                 arg_tmp = arg_tmp - arg;
106
107                 arg = ((arg + mux) + data_enable);
108
109                 instruction = ((opcode) << AWG_OPCODE_OFFSET) | arg;
110                 fwparams->ram_code[fwparams->instruction_offset] =
111                         instruction & (0x3fff);
112                 fwparams->instruction_offset++;
113         }
114         return 0;
115 }
116
117 int sti_awg_generate_code_data_enable_mode(
118                 struct awg_code_generation_params *fwparams,
119                 struct awg_timing *timing)
120 {
121         long int val;
122         long int data_en;
123         int ret = 0;
124
125         if (timing->trailing_lines > 0) {
126                 /* skip trailing lines */
127                 val = timing->blanking_level;
128                 data_en = 0;
129                 ret |= awg_generate_instr(RPLSET, val, 0, data_en, fwparams);
130
131                 val = timing->trailing_lines - 1;
132                 data_en = 0;
133                 ret |= awg_generate_instr(REPLAY, val, 0, data_en, fwparams);
134         }
135
136         if (timing->trailing_pixels > 0) {
137                 /* skip trailing pixel */
138                 val = timing->blanking_level;
139                 data_en = 0;
140                 ret |= awg_generate_instr(RPLSET, val, 0, data_en, fwparams);
141
142                 val = timing->trailing_pixels - 1;
143                 data_en = 0;
144                 ret |= awg_generate_instr(SKIP, val, 0, data_en, fwparams);
145         }
146
147         /* set DE signal high */
148         val = timing->blanking_level;
149         data_en = 1;
150         ret |= awg_generate_instr((timing->trailing_pixels > 0) ? SET : RPLSET,
151                         val, 0, data_en, fwparams);
152
153         if (timing->blanking_pixels > 0) {
154                 /* skip the number of active pixel */
155                 val = timing->active_pixels - 1;
156                 data_en = 1;
157                 ret |= awg_generate_instr(SKIP, val, 0, data_en, fwparams);
158
159                 /* set DE signal low */
160                 val = timing->blanking_level;
161                 data_en = 0;
162                 ret |= awg_generate_instr(SET, val, 0, data_en, fwparams);
163         }
164
165         /* replay the sequence as many active lines defined */
166         val = timing->active_lines - 1;
167         data_en = 0;
168         ret |= awg_generate_instr(REPLAY, val, 0, data_en, fwparams);
169
170         if (timing->blanking_lines > 0) {
171                 /* skip blanking lines */
172                 val = timing->blanking_level;
173                 data_en = 0;
174                 ret |= awg_generate_instr(RPLSET, val, 0, data_en, fwparams);
175
176                 val = timing->blanking_lines - 1;
177                 data_en = 0;
178                 ret |= awg_generate_instr(REPLAY, val, 0, data_en, fwparams);
179         }
180
181         return ret;
182 }