root/drivers/gpu/drm/sti/sti_awg_utils.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. awg_generate_instr
  2. awg_generate_line_signal
  3. sti_awg_generate_code_data_enable_mode

   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 
  16 enum opcode {
  17         SET,
  18         RPTSET,
  19         RPLSET,
  20         SKIP,
  21         STOP,
  22         REPEAT,
  23         REPLAY,
  24         JUMP,
  25         HOLD,
  26 };
  27 
  28 static 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 
 120 static 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 
 154 int 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 }

/* [<][>][^][v][top][bottom][index][help] */