These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[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 &= (0x3ff);
69                         break;
70                 case REPEAT:
71                 case REPLAY:
72                         if (arg == 0) {
73                                 /* REPEAT or REPLAY instruction not needed */
74                                 return 0;
75                         }
76
77                         mux = 0;
78                         data_enable = 0;
79                         arg &= (0x3ff);
80                         break;
81                 case JUMP:
82                         mux = 0;
83                         data_enable = 0;
84                         arg |= 0x40; /* for jump instruction 7th bit is 1 */
85                         arg &= 0x3ff;
86                         break;
87                 case STOP:
88                         arg = 0;
89                         break;
90                 case SET:
91                 case RPTSET:
92                 case RPLSET:
93                 case HOLD:
94                         arg &= (0x0ff);
95                         break;
96                 default:
97                         DRM_ERROR("instruction %d does not exist\n", opcode);
98                         return -EINVAL;
99                 }
100
101                 arg_tmp = arg_tmp - arg;
102
103                 arg = ((arg + mux) + data_enable);
104
105                 instruction = ((opcode) << AWG_OPCODE_OFFSET) | arg;
106                 fwparams->ram_code[fwparams->instruction_offset] =
107                         instruction & (0x3fff);
108                 fwparams->instruction_offset++;
109         }
110         return 0;
111 }
112
113 int sti_awg_generate_code_data_enable_mode(
114                 struct awg_code_generation_params *fwparams,
115                 struct awg_timing *timing)
116 {
117         long int val;
118         long int data_en;
119         int ret = 0;
120
121         if (timing->trailing_lines > 0) {
122                 /* skip trailing lines */
123                 val = timing->blanking_level;
124                 data_en = 0;
125                 ret |= awg_generate_instr(RPLSET, val, 0, data_en, fwparams);
126
127                 val = timing->trailing_lines - 1;
128                 data_en = 0;
129                 ret |= awg_generate_instr(REPLAY, val, 0, data_en, fwparams);
130         }
131
132         if (timing->trailing_pixels > 0) {
133                 /* skip trailing pixel */
134                 val = timing->blanking_level;
135                 data_en = 0;
136                 ret |= awg_generate_instr(RPLSET, val, 0, data_en, fwparams);
137
138                 val = timing->trailing_pixels - 1;
139                 data_en = 0;
140                 ret |= awg_generate_instr(SKIP, val, 0, data_en, fwparams);
141         }
142
143         /* set DE signal high */
144         val = timing->blanking_level;
145         data_en = 1;
146         ret |= awg_generate_instr((timing->trailing_pixels > 0) ? SET : RPLSET,
147                         val, 0, data_en, fwparams);
148
149         if (timing->blanking_pixels > 0) {
150                 /* skip the number of active pixel */
151                 val = timing->active_pixels - 1;
152                 data_en = 1;
153                 ret |= awg_generate_instr(SKIP, val, 0, data_en, fwparams);
154
155                 /* set DE signal low */
156                 val = timing->blanking_level;
157                 data_en = 0;
158                 ret |= awg_generate_instr(SET, val, 0, data_en, fwparams);
159         }
160
161         /* replay the sequence as many active lines defined */
162         val = timing->active_lines - 1;
163         data_en = 0;
164         ret |= awg_generate_instr(REPLAY, val, 0, data_en, fwparams);
165
166         if (timing->blanking_lines > 0) {
167                 /* skip blanking lines */
168                 val = timing->blanking_level;
169                 data_en = 0;
170                 ret |= awg_generate_instr(RPLSET, val, 0, data_en, fwparams);
171
172                 val = timing->blanking_lines - 1;
173                 data_en = 0;
174                 ret |= awg_generate_instr(REPLAY, val, 0, data_en, fwparams);
175         }
176
177         return ret;
178 }