cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sti_awg_utils.c (4266B)


      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}