cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

pvrusb2-encoder.c (13660B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      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.h
      9#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 0x00000004
     20#define IVTV_MBOX_DRIVER_DONE 0x00000002
     21#define IVTV_MBOX_DRIVER_BUSY 0x00000001
     22
     23#define MBOX_BASE 0x44
     24
     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 are
     38	spread out into chunks of 7 bytes each, with the first 4 bytes
     39	being the data word (little endian), and the next 3 bytes
     40	being the address where that data word is to be written (big
     41	endian).  Repeat request for additional words, with offset
     42	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 (read
     83	back block of 32 bit words).  Next 6 bytes must be zero,
     84	followed by a single byte of MBOX_BASE+offset for portion to
     85	be read.  Returned data is packed set of 32 bits words that
     86	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 the
    123   cx2341x_mbox_func prototype in cx2341x.h, which should be in
    124   kernels 2.6.18 or later.  We do this so that we can enable
    125   cx2341x.ko to write to our encoder (by handing it a pointer to this
    126   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 we
    148	populate with data and watch what the hardware does with it.
    149	The first word is a set of flags used to control the
    150	transaction, the second word is the command to execute, the
    151	third byte is zero (ivtv driver suggests that this is some
    152	kind of return value), and the fourth byte is a specified
    153	timeout (windows driver always uses 0x00060000 except for one
    154	case when it is zero).  All successive words are the argument
    155	words for the command.
    156
    157	First, write out the entire set of words, with the first word
    158	being zero.
    159
    160	Next, write out just the first word again, but set it to
    161	IVTV_MBOX_DRIVER_DONE | IVTV_DRIVER_BUSY this time (which
    162	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 however
    166	that bit is not set, then the command isn't done so repeat the
    167	read until it is set.
    168
    169	Finally, write out just the first word again, but set it to
    170	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 be
    320   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 0
    327	/* This inexplicable bit happens in the Hauppauge windows
    328	   driver (for both 24xxx and 29xxx devices).  However I
    329	   currently see no difference in behavior with or without
    330	   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#endif
    339
    340	/* Mike Isely <isely@pobox.com> 26-Jan-2006 The windows driver
    341	   sends the following list of ENC_MISC commands (for both
    342	   24xxx and 29xxx devices).  Meanings are not entirely clear,
    343	   however without the ENC_MISC(3,1) command then we risk
    344	   random perpetual video corruption whenever the video input
    345	   breaks up for a moment (like when switching channels). */
    346
    347
    348#if 0
    349	/* This ENC_MISC(5,0) command seems to hurt 29xxx sync
    350	   performance on channel changes, but is not a problem on
    351	   24xxx devices. */
    352	ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 5,0,0,0);
    353#endif
    354
    355	/* This ENC_MISC(3,encMisc3Arg) command is critical - without
    356	   it there will eventually be video corruption.  Also, the
    357	   saa7115 case is strange - the Windows driver is passing 1
    358	   regardless of device type but if we have 1 for saa7115
    359	   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 0
    371	/* This ENC_MISC(4,1) command is poisonous, so it is commented
    372	   out.  But I'm leaving it here anyway to document its
    373	   existence in the Windows driver.  The effect of this
    374	   command is that apps displaying the stream become sluggish
    375	   with stuttering video. */
    376	ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 4,1,0,0);
    377#endif
    378
    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 generated
    383	   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}