185 lines
		
	
	
	
		
			4 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			185 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; | ||
|  | } |