123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178 |
- /*
- * Copyright (C) STMicroelectronics SA 2014
- * Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
- * License terms: GNU General Public License (GPL), version 2
- */
- #include "sti_awg_utils.h"
- #define AWG_OPCODE_OFFSET 10
- enum opcode {
- SET,
- RPTSET,
- RPLSET,
- SKIP,
- STOP,
- REPEAT,
- REPLAY,
- JUMP,
- HOLD,
- };
- static int awg_generate_instr(enum opcode opcode,
- long int arg,
- long int mux_sel,
- long int data_en,
- struct awg_code_generation_params *fwparams)
- {
- u32 instruction = 0;
- u32 mux = (mux_sel << 8) & 0x1ff;
- u32 data_enable = (data_en << 9) & 0x2ff;
- long int arg_tmp = arg;
- /* skip, repeat and replay arg should not exceed 1023.
- * If user wants to exceed this value, the instruction should be
- * duplicate and arg should be adjust for each duplicated instruction.
- */
- while (arg_tmp > 0) {
- arg = arg_tmp;
- if (fwparams->instruction_offset >= AWG_MAX_INST) {
- DRM_ERROR("too many number of instructions\n");
- return -EINVAL;
- }
- switch (opcode) {
- case SKIP:
- /* leave 'arg' + 1 pixel elapsing without changing
- * output bus */
- arg--; /* pixel adjustment */
- arg_tmp--;
- if (arg < 0) {
- /* SKIP instruction not needed */
- return 0;
- }
- if (arg == 0) {
- /* SKIP 0 not permitted but we want to skip 1
- * pixel. So we transform SKIP into SET
- * instruction */
- opcode = SET;
- break;
- }
- mux = 0;
- data_enable = 0;
- arg &= (0x3ff);
- break;
- case REPEAT:
- case REPLAY:
- if (arg == 0) {
- /* REPEAT or REPLAY instruction not needed */
- return 0;
- }
- mux = 0;
- data_enable = 0;
- arg &= (0x3ff);
- break;
- case JUMP:
- mux = 0;
- data_enable = 0;
- arg |= 0x40; /* for jump instruction 7th bit is 1 */
- arg &= 0x3ff;
- break;
- case STOP:
- arg = 0;
- break;
- case SET:
- case RPTSET:
- case RPLSET:
- case HOLD:
- arg &= (0x0ff);
- break;
- default:
- DRM_ERROR("instruction %d does not exist\n", opcode);
- return -EINVAL;
- }
- arg_tmp = arg_tmp - arg;
- arg = ((arg + mux) + data_enable);
- instruction = ((opcode) << AWG_OPCODE_OFFSET) | arg;
- fwparams->ram_code[fwparams->instruction_offset] =
- instruction & (0x3fff);
- fwparams->instruction_offset++;
- }
- return 0;
- }
- int sti_awg_generate_code_data_enable_mode(
- struct awg_code_generation_params *fwparams,
- struct awg_timing *timing)
- {
- long int val;
- long int data_en;
- int ret = 0;
- if (timing->trailing_lines > 0) {
- /* skip trailing lines */
- val = timing->blanking_level;
- data_en = 0;
- ret |= awg_generate_instr(RPLSET, val, 0, data_en, fwparams);
- val = timing->trailing_lines - 1;
- data_en = 0;
- ret |= awg_generate_instr(REPLAY, val, 0, data_en, fwparams);
- }
- if (timing->trailing_pixels > 0) {
- /* skip trailing pixel */
- val = timing->blanking_level;
- data_en = 0;
- ret |= awg_generate_instr(RPLSET, val, 0, data_en, fwparams);
- val = timing->trailing_pixels - 1;
- data_en = 0;
- ret |= awg_generate_instr(SKIP, val, 0, data_en, fwparams);
- }
- /* set DE signal high */
- val = timing->blanking_level;
- data_en = 1;
- ret |= awg_generate_instr((timing->trailing_pixels > 0) ? SET : RPLSET,
- val, 0, data_en, fwparams);
- if (timing->blanking_pixels > 0) {
- /* skip the number of active pixel */
- val = timing->active_pixels - 1;
- data_en = 1;
- ret |= awg_generate_instr(SKIP, val, 0, data_en, fwparams);
- /* set DE signal low */
- val = timing->blanking_level;
- data_en = 0;
- ret |= awg_generate_instr(SET, val, 0, data_en, fwparams);
- }
- /* replay the sequence as many active lines defined */
- val = timing->active_lines - 1;
- data_en = 0;
- ret |= awg_generate_instr(REPLAY, val, 0, data_en, fwparams);
- if (timing->blanking_lines > 0) {
- /* skip blanking lines */
- val = timing->blanking_level;
- data_en = 0;
- ret |= awg_generate_instr(RPLSET, val, 0, data_en, fwparams);
- val = timing->blanking_lines - 1;
- data_en = 0;
- ret |= awg_generate_instr(REPLAY, val, 0, data_en, fwparams);
- }
- return ret;
- }
|