brintos

brintos / linux-shallow public Read only

0
0
Text · 13.3 KiB · c810277 Raw
514 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 *4 *  Copyright (C) 2005 Mike Isely <isely@pobox.com>5 *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>6 */7 8#include <linux/device.h>   // for linux/firmware.h9#include <linux/firmware.h>10#include "pvrusb2-util.h"11#include "pvrusb2-encoder.h"12#include "pvrusb2-hdw-internal.h"13#include "pvrusb2-debug.h"14#include "pvrusb2-fx2-cmd.h"15 16 17 18/* Firmware mailbox flags - definitions found from ivtv */19#define IVTV_MBOX_FIRMWARE_DONE 0x0000000420#define IVTV_MBOX_DRIVER_DONE 0x0000000221#define IVTV_MBOX_DRIVER_BUSY 0x0000000122 23#define MBOX_BASE 0x4424 25 26static int pvr2_encoder_write_words(struct pvr2_hdw *hdw,27				    unsigned int offs,28				    const u32 *data, unsigned int dlen)29{30	unsigned int idx,addr;31	unsigned int bAddr;32	int ret;33	unsigned int chunkCnt;34 35	/*36 37	Format: First byte must be 0x01.  Remaining 32 bit words are38	spread out into chunks of 7 bytes each, with the first 4 bytes39	being the data word (little endian), and the next 3 bytes40	being the address where that data word is to be written (big41	endian).  Repeat request for additional words, with offset42	adjusted accordingly.43 44	*/45	while (dlen) {46		chunkCnt = 8;47		if (chunkCnt > dlen) chunkCnt = dlen;48		memset(hdw->cmd_buffer,0,sizeof(hdw->cmd_buffer));49		bAddr = 0;50		hdw->cmd_buffer[bAddr++] = FX2CMD_MEM_WRITE_DWORD;51		for (idx = 0; idx < chunkCnt; idx++) {52			addr = idx + offs;53			hdw->cmd_buffer[bAddr+6] = (addr & 0xffu);54			hdw->cmd_buffer[bAddr+5] = ((addr>>8) & 0xffu);55			hdw->cmd_buffer[bAddr+4] = ((addr>>16) & 0xffu);56			PVR2_DECOMPOSE_LE(hdw->cmd_buffer, bAddr,data[idx]);57			bAddr += 7;58		}59		ret = pvr2_send_request(hdw,60					hdw->cmd_buffer,1+(chunkCnt*7),61					NULL,0);62		if (ret) return ret;63		data += chunkCnt;64		dlen -= chunkCnt;65		offs += chunkCnt;66	}67 68	return 0;69}70 71 72static int pvr2_encoder_read_words(struct pvr2_hdw *hdw,73				   unsigned int offs,74				   u32 *data, unsigned int dlen)75{76	unsigned int idx;77	int ret;78	unsigned int chunkCnt;79 80	/*81 82	Format: First byte must be 0x02 (status check) or 0x28 (read83	back block of 32 bit words).  Next 6 bytes must be zero,84	followed by a single byte of MBOX_BASE+offset for portion to85	be read.  Returned data is packed set of 32 bits words that86	were read.87 88	*/89 90	while (dlen) {91		chunkCnt = 16;92		if (chunkCnt > dlen) chunkCnt = dlen;93		if (chunkCnt < 16) chunkCnt = 1;94		hdw->cmd_buffer[0] =95			((chunkCnt == 1) ?96			 FX2CMD_MEM_READ_DWORD : FX2CMD_MEM_READ_64BYTES);97		hdw->cmd_buffer[1] = 0;98		hdw->cmd_buffer[2] = 0;99		hdw->cmd_buffer[3] = 0;100		hdw->cmd_buffer[4] = 0;101		hdw->cmd_buffer[5] = ((offs>>16) & 0xffu);102		hdw->cmd_buffer[6] = ((offs>>8) & 0xffu);103		hdw->cmd_buffer[7] = (offs & 0xffu);104		ret = pvr2_send_request(hdw,105					hdw->cmd_buffer,8,106					hdw->cmd_buffer,107					(chunkCnt == 1 ? 4 : 16 * 4));108		if (ret) return ret;109 110		for (idx = 0; idx < chunkCnt; idx++) {111			data[idx] = PVR2_COMPOSE_LE(hdw->cmd_buffer,idx*4);112		}113		data += chunkCnt;114		dlen -= chunkCnt;115		offs += chunkCnt;116	}117 118	return 0;119}120 121 122/* This prototype is set up to be compatible with the123   cx2341x_mbox_func prototype in cx2341x.h, which should be in124   kernels 2.6.18 or later.  We do this so that we can enable125   cx2341x.ko to write to our encoder (by handing it a pointer to this126   function).  For earlier kernels this doesn't really matter. */127static int pvr2_encoder_cmd(void *ctxt,128			    u32 cmd,129			    int arg_cnt_send,130			    int arg_cnt_recv,131			    u32 *argp)132{133	unsigned int poll_count;134	unsigned int try_count = 0;135	int retry_flag;136	int ret = 0;137	unsigned int idx;138	/* These sizes look to be limited by the FX2 firmware implementation */139	u32 wrData[16];140	u32 rdData[16];141	struct pvr2_hdw *hdw = (struct pvr2_hdw *)ctxt;142 143 144	/*145 146	The encoder seems to speak entirely using blocks 32 bit words.147	In ivtv driver terms, this is a mailbox at MBOX_BASE which we148	populate with data and watch what the hardware does with it.149	The first word is a set of flags used to control the150	transaction, the second word is the command to execute, the151	third byte is zero (ivtv driver suggests that this is some152	kind of return value), and the fourth byte is a specified153	timeout (windows driver always uses 0x00060000 except for one154	case when it is zero).  All successive words are the argument155	words for the command.156 157	First, write out the entire set of words, with the first word158	being zero.159 160	Next, write out just the first word again, but set it to161	IVTV_MBOX_DRIVER_DONE | IVTV_DRIVER_BUSY this time (which162	probably means "go").163 164	Next, read back the return count words.  Check the first word,165	which should have IVTV_MBOX_FIRMWARE_DONE set.  If however166	that bit is not set, then the command isn't done so repeat the167	read until it is set.168 169	Finally, write out just the first word again, but set it to170	0x0 this time (which probably means "idle").171 172	*/173 174	if (arg_cnt_send > (ARRAY_SIZE(wrData) - 4)) {175		pvr2_trace(176			PVR2_TRACE_ERROR_LEGS,177			"Failed to write cx23416 command - too many input arguments (was given %u limit %lu)",178			arg_cnt_send, (long unsigned) ARRAY_SIZE(wrData) - 4);179		return -EINVAL;180	}181 182	if (arg_cnt_recv > (ARRAY_SIZE(rdData) - 4)) {183		pvr2_trace(184			PVR2_TRACE_ERROR_LEGS,185			"Failed to write cx23416 command - too many return arguments (was given %u limit %lu)",186			arg_cnt_recv, (long unsigned) ARRAY_SIZE(rdData) - 4);187		return -EINVAL;188	}189 190 191	LOCK_TAKE(hdw->ctl_lock);192	while (1) {193		if (!hdw->state_encoder_ok) {194			ret = -EIO;195			break;196		}197 198		retry_flag = 0;199		try_count++;200		ret = 0;201		wrData[0] = 0;202		wrData[1] = cmd;203		wrData[2] = 0;204		wrData[3] = 0x00060000;205		for (idx = 0; idx < arg_cnt_send; idx++) {206			wrData[idx+4] = argp[idx];207		}208		for (; idx < ARRAY_SIZE(wrData) - 4; idx++) {209			wrData[idx+4] = 0;210		}211 212		ret = pvr2_encoder_write_words(hdw,MBOX_BASE,wrData,idx);213		if (ret) break;214		wrData[0] = IVTV_MBOX_DRIVER_DONE|IVTV_MBOX_DRIVER_BUSY;215		ret = pvr2_encoder_write_words(hdw,MBOX_BASE,wrData,1);216		if (ret) break;217		poll_count = 0;218		while (1) {219			poll_count++;220			ret = pvr2_encoder_read_words(hdw,MBOX_BASE,rdData,221						      arg_cnt_recv+4);222			if (ret) {223				break;224			}225			if (rdData[0] & IVTV_MBOX_FIRMWARE_DONE) {226				break;227			}228			if (rdData[0] && (poll_count < 1000)) continue;229			if (!rdData[0]) {230				retry_flag = !0;231				pvr2_trace(232					PVR2_TRACE_ERROR_LEGS,233					"Encoder timed out waiting for us; arranging to retry");234			} else {235				pvr2_trace(236					PVR2_TRACE_ERROR_LEGS,237					"***WARNING*** device's encoder appears to be stuck (status=0x%08x)",238rdData[0]);239			}240			pvr2_trace(241				PVR2_TRACE_ERROR_LEGS,242				"Encoder command: 0x%02x",cmd);243			for (idx = 4; idx < arg_cnt_send; idx++) {244				pvr2_trace(245					PVR2_TRACE_ERROR_LEGS,246					"Encoder arg%d: 0x%08x",247					idx-3,wrData[idx]);248			}249			ret = -EBUSY;250			break;251		}252		if (retry_flag) {253			if (try_count < 20) continue;254			pvr2_trace(255				PVR2_TRACE_ERROR_LEGS,256				"Too many retries...");257			ret = -EBUSY;258		}259		if (ret) {260			del_timer_sync(&hdw->encoder_run_timer);261			hdw->state_encoder_ok = 0;262			pvr2_trace(PVR2_TRACE_STBITS,263				   "State bit %s <-- %s",264				   "state_encoder_ok",265				   (hdw->state_encoder_ok ? "true" : "false"));266			if (hdw->state_encoder_runok) {267				hdw->state_encoder_runok = 0;268				pvr2_trace(PVR2_TRACE_STBITS,269				   "State bit %s <-- %s",270					   "state_encoder_runok",271					   (hdw->state_encoder_runok ?272					    "true" : "false"));273			}274			pvr2_trace(275				PVR2_TRACE_ERROR_LEGS,276				"Giving up on command.  This is normally recovered via a firmware reload and re-initialization; concern is only warranted if this happens repeatedly and rapidly.");277			break;278		}279		wrData[0] = 0x7;280		for (idx = 0; idx < arg_cnt_recv; idx++) {281			argp[idx] = rdData[idx+4];282		}283 284		wrData[0] = 0x0;285		ret = pvr2_encoder_write_words(hdw,MBOX_BASE,wrData,1);286		break;287	}288	LOCK_GIVE(hdw->ctl_lock);289 290	return ret;291}292 293 294static int pvr2_encoder_vcmd(struct pvr2_hdw *hdw, int cmd,295			     int args, ...)296{297	va_list vl;298	unsigned int idx;299	u32 data[12];300 301	if (args > ARRAY_SIZE(data)) {302		pvr2_trace(303			PVR2_TRACE_ERROR_LEGS,304			"Failed to write cx23416 command - too many arguments (was given %u limit %lu)",305			args, (long unsigned) ARRAY_SIZE(data));306		return -EINVAL;307	}308 309	va_start(vl, args);310	for (idx = 0; idx < args; idx++) {311		data[idx] = va_arg(vl, u32);312	}313	va_end(vl);314 315	return pvr2_encoder_cmd(hdw,cmd,args,0,data);316}317 318 319/* This implements some extra setup for the encoder that seems to be320   specific to the PVR USB2 hardware. */321static int pvr2_encoder_prep_config(struct pvr2_hdw *hdw)322{323	int ret = 0;324	int encMisc3Arg = 0;325 326#if 0327	/* This inexplicable bit happens in the Hauppauge windows328	   driver (for both 24xxx and 29xxx devices).  However I329	   currently see no difference in behavior with or without330	   this stuff.  Leave this here as a note of its existence,331	   but don't use it. */332	LOCK_TAKE(hdw->ctl_lock); do {333		u32 dat[1];334		dat[0] = 0x80000640;335		pvr2_encoder_write_words(hdw,0x01fe,dat,1);336		pvr2_encoder_write_words(hdw,0x023e,dat,1);337	} while(0); LOCK_GIVE(hdw->ctl_lock);338#endif339 340	/* Mike Isely <isely@pobox.com> 26-Jan-2006 The windows driver341	   sends the following list of ENC_MISC commands (for both342	   24xxx and 29xxx devices).  Meanings are not entirely clear,343	   however without the ENC_MISC(3,1) command then we risk344	   random perpetual video corruption whenever the video input345	   breaks up for a moment (like when switching channels). */346 347 348#if 0349	/* This ENC_MISC(5,0) command seems to hurt 29xxx sync350	   performance on channel changes, but is not a problem on351	   24xxx devices. */352	ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 5,0,0,0);353#endif354 355	/* This ENC_MISC(3,encMisc3Arg) command is critical - without356	   it there will eventually be video corruption.  Also, the357	   saa7115 case is strange - the Windows driver is passing 1358	   regardless of device type but if we have 1 for saa7115359	   devices the video turns sluggish.  */360	if (hdw->hdw_desc->flag_has_cx25840) {361		encMisc3Arg = 1;362	} else {363		encMisc3Arg = 0;364	}365	ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 3,366				 encMisc3Arg,0,0);367 368	ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 8,0,0,0);369 370#if 0371	/* This ENC_MISC(4,1) command is poisonous, so it is commented372	   out.  But I'm leaving it here anyway to document its373	   existence in the Windows driver.  The effect of this374	   command is that apps displaying the stream become sluggish375	   with stuttering video. */376	ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 4,1,0,0);377#endif378 379	ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 0,3,0,0);380	ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4,15,0,0,0);381 382	/* prevent the PTSs from slowly drifting away in the generated383	   MPEG stream */384	ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC, 2, 4, 1);385 386	return ret;387}388 389int pvr2_encoder_adjust(struct pvr2_hdw *hdw)390{391	int ret;392	ret = cx2341x_update(hdw,pvr2_encoder_cmd,393			     (hdw->enc_cur_valid ? &hdw->enc_cur_state : NULL),394			     &hdw->enc_ctl_state);395	if (ret) {396		pvr2_trace(PVR2_TRACE_ERROR_LEGS,397			   "Error from cx2341x module code=%d",ret);398	} else {399		hdw->enc_cur_state = hdw->enc_ctl_state;400		hdw->enc_cur_valid = !0;401	}402	return ret;403}404 405 406int pvr2_encoder_configure(struct pvr2_hdw *hdw)407{408	int ret;409	int val;410	pvr2_trace(PVR2_TRACE_ENCODER, "pvr2_encoder_configure (cx2341x module)");411	hdw->enc_ctl_state.port = CX2341X_PORT_STREAMING;412	hdw->enc_ctl_state.width = hdw->res_hor_val;413	hdw->enc_ctl_state.height = hdw->res_ver_val;414	hdw->enc_ctl_state.is_50hz = ((hdw->std_mask_cur & V4L2_STD_525_60) ?415				      0 : 1);416 417	ret = 0;418 419	ret |= pvr2_encoder_prep_config(hdw);420 421	/* saa7115: 0xf0 */422	val = 0xf0;423	if (hdw->hdw_desc->flag_has_cx25840) {424		/* ivtv cx25840: 0x140 */425		val = 0x140;426	}427 428	if (!ret) ret = pvr2_encoder_vcmd(429		hdw,CX2341X_ENC_SET_NUM_VSYNC_LINES, 2,430		val, val);431 432	/* setup firmware to notify us about some events (don't know why...) */433	if (!ret) ret = pvr2_encoder_vcmd(434		hdw,CX2341X_ENC_SET_EVENT_NOTIFICATION, 4,435		0, 0, 0x10000000, 0xffffffff);436 437	if (!ret) ret = pvr2_encoder_vcmd(438		hdw,CX2341X_ENC_SET_VBI_LINE, 5,439		0xffffffff,0,0,0,0);440 441	if (ret) {442		pvr2_trace(PVR2_TRACE_ERROR_LEGS,443			   "Failed to configure cx23416");444		return ret;445	}446 447	ret = pvr2_encoder_adjust(hdw);448	if (ret) return ret;449 450	ret = pvr2_encoder_vcmd(451		hdw, CX2341X_ENC_INITIALIZE_INPUT, 0);452 453	if (ret) {454		pvr2_trace(PVR2_TRACE_ERROR_LEGS,455			   "Failed to initialize cx23416 video input");456		return ret;457	}458 459	return 0;460}461 462 463int pvr2_encoder_start(struct pvr2_hdw *hdw)464{465	int status;466 467	/* unmask some interrupts */468	pvr2_write_register(hdw, 0x0048, 0xbfffffff);469 470	pvr2_encoder_vcmd(hdw,CX2341X_ENC_MUTE_VIDEO,1,471			  hdw->input_val == PVR2_CVAL_INPUT_RADIO ? 1 : 0);472 473	switch (hdw->active_stream_type) {474	case pvr2_config_vbi:475		status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,476					   0x01,0x14);477		break;478	case pvr2_config_mpeg:479		status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,480					   0,0x13);481		break;482	default: /* Unhandled cases for now */483		status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,484					   0,0x13);485		break;486	}487	return status;488}489 490int pvr2_encoder_stop(struct pvr2_hdw *hdw)491{492	int status;493 494	/* mask all interrupts */495	pvr2_write_register(hdw, 0x0048, 0xffffffff);496 497	switch (hdw->active_stream_type) {498	case pvr2_config_vbi:499		status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,500					   0x01,0x01,0x14);501		break;502	case pvr2_config_mpeg:503		status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,504					   0x01,0,0x13);505		break;506	default: /* Unhandled cases for now */507		status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,508					   0x01,0,0x13);509		break;510	}511 512	return status;513}514