Linux Audio

Check our new training course

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