• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
awg_generate_instr(enum opcode opcode,long int arg,long int mux_sel,long int data_en,struct awg_code_generation_params * fwparams)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 
sti_awg_generate_code_data_enable_mode(struct awg_code_generation_params * fwparams,struct awg_timing * timing)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 }
179