brintos

brintos / linux-shallow public Read only

0
0
Text · 4.2 KiB · 5ff87a4 Raw
193 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (C) STMicroelectronics SA 20144 * 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 1014#define AWG_MAX_ARG       0x3ff15 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 be41	 * 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 changing56			 * 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 167				 * pixel. So we transform SKIP into SET68				 * 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}193