 f32c4c506f
			
		
	
	
	f32c4c506f
	
	
	
		
			
			Digital Video Out connector driver LCD panels. Like HDMI and HDA it create bridge, encoder and connector drm object. Add binding description. Signed-off-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
		
			
				
	
	
		
			184 lines
		
	
	
	
		
			4 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			184 lines
		
	
	
	
		
			4 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * 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;
 | |
| 				arg = (arg << 24) >> 24;
 | |
| 				arg &= (0x0ff);
 | |
| 				break;
 | |
| 			}
 | |
| 
 | |
| 			mux = 0;
 | |
| 			data_enable = 0;
 | |
| 			arg = (arg << 22) >> 22;
 | |
| 			arg &= (0x3ff);
 | |
| 			break;
 | |
| 		case REPEAT:
 | |
| 		case REPLAY:
 | |
| 			if (arg == 0) {
 | |
| 				/* REPEAT or REPLAY instruction not needed */
 | |
| 				return 0;
 | |
| 			}
 | |
| 
 | |
| 			mux = 0;
 | |
| 			data_enable = 0;
 | |
| 			arg = (arg << 22) >> 22;
 | |
| 			arg &= (0x3ff);
 | |
| 			break;
 | |
| 		case JUMP:
 | |
| 			mux = 0;
 | |
| 			data_enable = 0;
 | |
| 			arg |= 0x40; /* for jump instruction 7th bit is 1 */
 | |
| 			arg = (arg << 22) >> 22;
 | |
| 			arg &= 0x3ff;
 | |
| 			break;
 | |
| 		case STOP:
 | |
| 			arg = 0;
 | |
| 			break;
 | |
| 		case SET:
 | |
| 		case RPTSET:
 | |
| 		case RPLSET:
 | |
| 		case HOLD:
 | |
| 			arg = (arg << 24) >> 24;
 | |
| 			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;
 | |
| }
 |