Linux Audio

Check our new training course

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