drm/i915: Update intel_logical_ring_begin() to take a request structure
[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.
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;
f32c4c50
BG
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
117int 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}
This page took 0.050048 seconds and 5 git commands to generate.