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

vpx3220.c (13971B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * vpx3220a, vpx3216b & vpx3214c video decoder driver version 0.0.1
      4 *
      5 * Copyright (C) 2001 Laurent Pinchart <lpinchart@freegates.be>
      6 */
      7
      8#include <linux/module.h>
      9#include <linux/init.h>
     10#include <linux/delay.h>
     11#include <linux/types.h>
     12#include <linux/slab.h>
     13#include <linux/uaccess.h>
     14#include <linux/i2c.h>
     15#include <linux/videodev2.h>
     16#include <media/v4l2-device.h>
     17#include <media/v4l2-ctrls.h>
     18
     19MODULE_DESCRIPTION("vpx3220a/vpx3216b/vpx3214c video decoder driver");
     20MODULE_AUTHOR("Laurent Pinchart");
     21MODULE_LICENSE("GPL");
     22
     23static int debug;
     24module_param(debug, int, 0);
     25MODULE_PARM_DESC(debug, "Debug level (0-1)");
     26
     27
     28#define VPX_TIMEOUT_COUNT  10
     29
     30/* ----------------------------------------------------------------------- */
     31
     32struct vpx3220 {
     33	struct v4l2_subdev sd;
     34	struct v4l2_ctrl_handler hdl;
     35	unsigned char reg[255];
     36
     37	v4l2_std_id norm;
     38	int input;
     39	int enable;
     40};
     41
     42static inline struct vpx3220 *to_vpx3220(struct v4l2_subdev *sd)
     43{
     44	return container_of(sd, struct vpx3220, sd);
     45}
     46
     47static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
     48{
     49	return &container_of(ctrl->handler, struct vpx3220, hdl)->sd;
     50}
     51
     52static char *inputs[] = { "internal", "composite", "svideo" };
     53
     54/* ----------------------------------------------------------------------- */
     55
     56static inline int vpx3220_write(struct v4l2_subdev *sd, u8 reg, u8 value)
     57{
     58	struct i2c_client *client = v4l2_get_subdevdata(sd);
     59	struct vpx3220 *decoder = i2c_get_clientdata(client);
     60
     61	decoder->reg[reg] = value;
     62	return i2c_smbus_write_byte_data(client, reg, value);
     63}
     64
     65static inline int vpx3220_read(struct v4l2_subdev *sd, u8 reg)
     66{
     67	struct i2c_client *client = v4l2_get_subdevdata(sd);
     68
     69	return i2c_smbus_read_byte_data(client, reg);
     70}
     71
     72static int vpx3220_fp_status(struct v4l2_subdev *sd)
     73{
     74	unsigned char status;
     75	unsigned int i;
     76
     77	for (i = 0; i < VPX_TIMEOUT_COUNT; i++) {
     78		status = vpx3220_read(sd, 0x29);
     79
     80		if (!(status & 4))
     81			return 0;
     82
     83		udelay(10);
     84
     85		if (need_resched())
     86			cond_resched();
     87	}
     88
     89	return -1;
     90}
     91
     92static int vpx3220_fp_write(struct v4l2_subdev *sd, u8 fpaddr, u16 data)
     93{
     94	struct i2c_client *client = v4l2_get_subdevdata(sd);
     95
     96	/* Write the 16-bit address to the FPWR register */
     97	if (i2c_smbus_write_word_data(client, 0x27, swab16(fpaddr)) == -1) {
     98		v4l2_dbg(1, debug, sd, "%s: failed\n", __func__);
     99		return -1;
    100	}
    101
    102	if (vpx3220_fp_status(sd) < 0)
    103		return -1;
    104
    105	/* Write the 16-bit data to the FPDAT register */
    106	if (i2c_smbus_write_word_data(client, 0x28, swab16(data)) == -1) {
    107		v4l2_dbg(1, debug, sd, "%s: failed\n", __func__);
    108		return -1;
    109	}
    110
    111	return 0;
    112}
    113
    114static int vpx3220_fp_read(struct v4l2_subdev *sd, u16 fpaddr)
    115{
    116	struct i2c_client *client = v4l2_get_subdevdata(sd);
    117	s16 data;
    118
    119	/* Write the 16-bit address to the FPRD register */
    120	if (i2c_smbus_write_word_data(client, 0x26, swab16(fpaddr)) == -1) {
    121		v4l2_dbg(1, debug, sd, "%s: failed\n", __func__);
    122		return -1;
    123	}
    124
    125	if (vpx3220_fp_status(sd) < 0)
    126		return -1;
    127
    128	/* Read the 16-bit data from the FPDAT register */
    129	data = i2c_smbus_read_word_data(client, 0x28);
    130	if (data == -1) {
    131		v4l2_dbg(1, debug, sd, "%s: failed\n", __func__);
    132		return -1;
    133	}
    134
    135	return swab16(data);
    136}
    137
    138static int vpx3220_write_block(struct v4l2_subdev *sd, const u8 *data, unsigned int len)
    139{
    140	u8 reg;
    141	int ret = -1;
    142
    143	while (len >= 2) {
    144		reg = *data++;
    145		ret = vpx3220_write(sd, reg, *data++);
    146		if (ret < 0)
    147			break;
    148		len -= 2;
    149	}
    150
    151	return ret;
    152}
    153
    154static int vpx3220_write_fp_block(struct v4l2_subdev *sd,
    155		const u16 *data, unsigned int len)
    156{
    157	u8 reg;
    158	int ret = 0;
    159
    160	while (len > 1) {
    161		reg = *data++;
    162		ret |= vpx3220_fp_write(sd, reg, *data++);
    163		len -= 2;
    164	}
    165
    166	return ret;
    167}
    168
    169/* ---------------------------------------------------------------------- */
    170
    171static const unsigned short init_ntsc[] = {
    172	0x1c, 0x00,		/* NTSC tint angle */
    173	0x88, 17,		/* Window 1 vertical */
    174	0x89, 240,		/* Vertical lines in */
    175	0x8a, 240,		/* Vertical lines out */
    176	0x8b, 000,		/* Horizontal begin */
    177	0x8c, 640,		/* Horizontal length */
    178	0x8d, 640,		/* Number of pixels */
    179	0x8f, 0xc00,		/* Disable window 2 */
    180	0xf0, 0x73,		/* 13.5 MHz transport, Forced
    181				 * mode, latch windows */
    182	0xf2, 0x13,		/* NTSC M, composite input */
    183	0xe7, 0x1e1,		/* Enable vertical standard
    184				 * locking @ 240 lines */
    185};
    186
    187static const unsigned short init_pal[] = {
    188	0x88, 23,		/* Window 1 vertical begin */
    189	0x89, 288,		/* Vertical lines in (16 lines
    190				 * skipped by the VFE) */
    191	0x8a, 288,		/* Vertical lines out (16 lines
    192				 * skipped by the VFE) */
    193	0x8b, 16,		/* Horizontal begin */
    194	0x8c, 768,		/* Horizontal length */
    195	0x8d, 784,		/* Number of pixels
    196				 * Must be >= Horizontal begin + Horizontal length */
    197	0x8f, 0xc00,		/* Disable window 2 */
    198	0xf0, 0x77,		/* 13.5 MHz transport, Forced
    199				 * mode, latch windows */
    200	0xf2, 0x3d1,		/* PAL B,G,H,I, composite input */
    201	0xe7, 0x241,		/* PAL/SECAM set to 288 lines */
    202};
    203
    204static const unsigned short init_secam[] = {
    205	0x88, 23,		/* Window 1 vertical begin */
    206	0x89, 288,		/* Vertical lines in (16 lines
    207				 * skipped by the VFE) */
    208	0x8a, 288,		/* Vertical lines out (16 lines
    209				 * skipped by the VFE) */
    210	0x8b, 16,		/* Horizontal begin */
    211	0x8c, 768,		/* Horizontal length */
    212	0x8d, 784,		/* Number of pixels
    213				 * Must be >= Horizontal begin + Horizontal length */
    214	0x8f, 0xc00,		/* Disable window 2 */
    215	0xf0, 0x77,		/* 13.5 MHz transport, Forced
    216				 * mode, latch windows */
    217	0xf2, 0x3d5,		/* SECAM, composite input */
    218	0xe7, 0x241,		/* PAL/SECAM set to 288 lines */
    219};
    220
    221static const unsigned char init_common[] = {
    222	0xf2, 0x00,		/* Disable all outputs */
    223	0x33, 0x0d,		/* Luma : VIN2, Chroma : CIN
    224				 * (clamp off) */
    225	0xd8, 0xa8,		/* HREF/VREF active high, VREF
    226				 * pulse = 2, Odd/Even flag */
    227	0x20, 0x03,		/* IF compensation 0dB/oct */
    228	0xe0, 0xff,		/* Open up all comparators */
    229	0xe1, 0x00,
    230	0xe2, 0x7f,
    231	0xe3, 0x80,
    232	0xe4, 0x7f,
    233	0xe5, 0x80,
    234	0xe6, 0x00,		/* Brightness set to 0 */
    235	0xe7, 0xe0,		/* Contrast to 1.0, noise shaping
    236				 * 10 to 8 2-bit error diffusion */
    237	0xe8, 0xf8,		/* YUV422, CbCr binary offset,
    238				 * ... (p.32) */
    239	0xea, 0x18,		/* LLC2 connected, output FIFO
    240				 * reset with VACTintern */
    241	0xf0, 0x8a,		/* Half full level to 10, bus
    242				 * shuffler [7:0, 23:16, 15:8] */
    243	0xf1, 0x18,		/* Single clock, sync mode, no
    244				 * FE delay, no HLEN counter */
    245	0xf8, 0x12,		/* Port A, PIXCLK, HF# & FE#
    246				 * strength to 2 */
    247	0xf9, 0x24,		/* Port B, HREF, VREF, PREF &
    248				 * ALPHA strength to 4 */
    249};
    250
    251static const unsigned short init_fp[] = {
    252	0x59, 0,
    253	0xa0, 2070,		/* ACC reference */
    254	0xa3, 0,
    255	0xa4, 0,
    256	0xa8, 30,
    257	0xb2, 768,
    258	0xbe, 27,
    259	0x58, 0,
    260	0x26, 0,
    261	0x4b, 0x298,		/* PLL gain */
    262};
    263
    264
    265static int vpx3220_init(struct v4l2_subdev *sd, u32 val)
    266{
    267	struct vpx3220 *decoder = to_vpx3220(sd);
    268
    269	vpx3220_write_block(sd, init_common, sizeof(init_common));
    270	vpx3220_write_fp_block(sd, init_fp, sizeof(init_fp) >> 1);
    271	if (decoder->norm & V4L2_STD_NTSC)
    272		vpx3220_write_fp_block(sd, init_ntsc, sizeof(init_ntsc) >> 1);
    273	else if (decoder->norm & V4L2_STD_PAL)
    274		vpx3220_write_fp_block(sd, init_pal, sizeof(init_pal) >> 1);
    275	else if (decoder->norm & V4L2_STD_SECAM)
    276		vpx3220_write_fp_block(sd, init_secam, sizeof(init_secam) >> 1);
    277	else
    278		vpx3220_write_fp_block(sd, init_pal, sizeof(init_pal) >> 1);
    279	return 0;
    280}
    281
    282static int vpx3220_status(struct v4l2_subdev *sd, u32 *pstatus, v4l2_std_id *pstd)
    283{
    284	int res = V4L2_IN_ST_NO_SIGNAL, status;
    285	v4l2_std_id std = pstd ? *pstd : V4L2_STD_ALL;
    286
    287	status = vpx3220_fp_read(sd, 0x0f3);
    288
    289	v4l2_dbg(1, debug, sd, "status: 0x%04x\n", status);
    290
    291	if (status < 0)
    292		return status;
    293
    294	if ((status & 0x20) == 0) {
    295		res = 0;
    296
    297		switch (status & 0x18) {
    298		case 0x00:
    299		case 0x10:
    300		case 0x14:
    301		case 0x18:
    302			std &= V4L2_STD_PAL;
    303			break;
    304
    305		case 0x08:
    306			std &= V4L2_STD_SECAM;
    307			break;
    308
    309		case 0x04:
    310		case 0x0c:
    311		case 0x1c:
    312			std &= V4L2_STD_NTSC;
    313			break;
    314		}
    315	} else {
    316		std = V4L2_STD_UNKNOWN;
    317	}
    318	if (pstd)
    319		*pstd = std;
    320	if (pstatus)
    321		*pstatus = res;
    322	return 0;
    323}
    324
    325static int vpx3220_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
    326{
    327	v4l2_dbg(1, debug, sd, "querystd\n");
    328	return vpx3220_status(sd, NULL, std);
    329}
    330
    331static int vpx3220_g_input_status(struct v4l2_subdev *sd, u32 *status)
    332{
    333	v4l2_dbg(1, debug, sd, "g_input_status\n");
    334	return vpx3220_status(sd, status, NULL);
    335}
    336
    337static int vpx3220_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
    338{
    339	struct vpx3220 *decoder = to_vpx3220(sd);
    340	int temp_input;
    341
    342	/* Here we back up the input selection because it gets
    343	   overwritten when we fill the registers with the
    344	   chosen video norm */
    345	temp_input = vpx3220_fp_read(sd, 0xf2);
    346
    347	v4l2_dbg(1, debug, sd, "s_std %llx\n", (unsigned long long)std);
    348	if (std & V4L2_STD_NTSC) {
    349		vpx3220_write_fp_block(sd, init_ntsc, sizeof(init_ntsc) >> 1);
    350		v4l2_dbg(1, debug, sd, "norm switched to NTSC\n");
    351	} else if (std & V4L2_STD_PAL) {
    352		vpx3220_write_fp_block(sd, init_pal, sizeof(init_pal) >> 1);
    353		v4l2_dbg(1, debug, sd, "norm switched to PAL\n");
    354	} else if (std & V4L2_STD_SECAM) {
    355		vpx3220_write_fp_block(sd, init_secam, sizeof(init_secam) >> 1);
    356		v4l2_dbg(1, debug, sd, "norm switched to SECAM\n");
    357	} else {
    358		return -EINVAL;
    359	}
    360
    361	decoder->norm = std;
    362
    363	/* And here we set the backed up video input again */
    364	vpx3220_fp_write(sd, 0xf2, temp_input | 0x0010);
    365	udelay(10);
    366	return 0;
    367}
    368
    369static int vpx3220_s_routing(struct v4l2_subdev *sd,
    370			     u32 input, u32 output, u32 config)
    371{
    372	int data;
    373
    374	/* RJ:   input = 0: ST8 (PCTV) input
    375		 input = 1: COMPOSITE  input
    376		 input = 2: SVHS       input  */
    377
    378	static const int input_vals[3][2] = {
    379		{0x0c, 0},
    380		{0x0d, 0},
    381		{0x0e, 1}
    382	};
    383
    384	if (input > 2)
    385		return -EINVAL;
    386
    387	v4l2_dbg(1, debug, sd, "input switched to %s\n", inputs[input]);
    388
    389	vpx3220_write(sd, 0x33, input_vals[input][0]);
    390
    391	data = vpx3220_fp_read(sd, 0xf2) & ~(0x0020);
    392	if (data < 0)
    393		return data;
    394	/* 0x0010 is required to latch the setting */
    395	vpx3220_fp_write(sd, 0xf2,
    396			data | (input_vals[input][1] << 5) | 0x0010);
    397
    398	udelay(10);
    399	return 0;
    400}
    401
    402static int vpx3220_s_stream(struct v4l2_subdev *sd, int enable)
    403{
    404	v4l2_dbg(1, debug, sd, "s_stream %s\n", enable ? "on" : "off");
    405
    406	vpx3220_write(sd, 0xf2, (enable ? 0x1b : 0x00));
    407	return 0;
    408}
    409
    410static int vpx3220_s_ctrl(struct v4l2_ctrl *ctrl)
    411{
    412	struct v4l2_subdev *sd = to_sd(ctrl);
    413
    414	switch (ctrl->id) {
    415	case V4L2_CID_BRIGHTNESS:
    416		vpx3220_write(sd, 0xe6, ctrl->val);
    417		return 0;
    418	case V4L2_CID_CONTRAST:
    419		/* Bit 7 and 8 is for noise shaping */
    420		vpx3220_write(sd, 0xe7, ctrl->val + 192);
    421		return 0;
    422	case V4L2_CID_SATURATION:
    423		vpx3220_fp_write(sd, 0xa0, ctrl->val);
    424		return 0;
    425	case V4L2_CID_HUE:
    426		vpx3220_fp_write(sd, 0x1c, ctrl->val);
    427		return 0;
    428	}
    429	return -EINVAL;
    430}
    431
    432/* ----------------------------------------------------------------------- */
    433
    434static const struct v4l2_ctrl_ops vpx3220_ctrl_ops = {
    435	.s_ctrl = vpx3220_s_ctrl,
    436};
    437
    438static const struct v4l2_subdev_core_ops vpx3220_core_ops = {
    439	.init = vpx3220_init,
    440};
    441
    442static const struct v4l2_subdev_video_ops vpx3220_video_ops = {
    443	.s_std = vpx3220_s_std,
    444	.s_routing = vpx3220_s_routing,
    445	.s_stream = vpx3220_s_stream,
    446	.querystd = vpx3220_querystd,
    447	.g_input_status = vpx3220_g_input_status,
    448};
    449
    450static const struct v4l2_subdev_ops vpx3220_ops = {
    451	.core = &vpx3220_core_ops,
    452	.video = &vpx3220_video_ops,
    453};
    454
    455/* -----------------------------------------------------------------------
    456 * Client management code
    457 */
    458
    459static int vpx3220_probe(struct i2c_client *client,
    460			const struct i2c_device_id *id)
    461{
    462	struct vpx3220 *decoder;
    463	struct v4l2_subdev *sd;
    464	const char *name = NULL;
    465	u8 ver;
    466	u16 pn;
    467
    468	/* Check if the adapter supports the needed features */
    469	if (!i2c_check_functionality(client->adapter,
    470		I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
    471		return -ENODEV;
    472
    473	decoder = devm_kzalloc(&client->dev, sizeof(*decoder), GFP_KERNEL);
    474	if (decoder == NULL)
    475		return -ENOMEM;
    476	sd = &decoder->sd;
    477	v4l2_i2c_subdev_init(sd, client, &vpx3220_ops);
    478	decoder->norm = V4L2_STD_PAL;
    479	decoder->input = 0;
    480	decoder->enable = 1;
    481	v4l2_ctrl_handler_init(&decoder->hdl, 4);
    482	v4l2_ctrl_new_std(&decoder->hdl, &vpx3220_ctrl_ops,
    483		V4L2_CID_BRIGHTNESS, -128, 127, 1, 0);
    484	v4l2_ctrl_new_std(&decoder->hdl, &vpx3220_ctrl_ops,
    485		V4L2_CID_CONTRAST, 0, 63, 1, 32);
    486	v4l2_ctrl_new_std(&decoder->hdl, &vpx3220_ctrl_ops,
    487		V4L2_CID_SATURATION, 0, 4095, 1, 2048);
    488	v4l2_ctrl_new_std(&decoder->hdl, &vpx3220_ctrl_ops,
    489		V4L2_CID_HUE, -512, 511, 1, 0);
    490	sd->ctrl_handler = &decoder->hdl;
    491	if (decoder->hdl.error) {
    492		int err = decoder->hdl.error;
    493
    494		v4l2_ctrl_handler_free(&decoder->hdl);
    495		return err;
    496	}
    497	v4l2_ctrl_handler_setup(&decoder->hdl);
    498
    499	ver = i2c_smbus_read_byte_data(client, 0x00);
    500	pn = (i2c_smbus_read_byte_data(client, 0x02) << 8) +
    501		i2c_smbus_read_byte_data(client, 0x01);
    502	if (ver == 0xec) {
    503		switch (pn) {
    504		case 0x4680:
    505			name = "vpx3220a";
    506			break;
    507		case 0x4260:
    508			name = "vpx3216b";
    509			break;
    510		case 0x4280:
    511			name = "vpx3214c";
    512			break;
    513		}
    514	}
    515	if (name)
    516		v4l2_info(sd, "%s found @ 0x%x (%s)\n", name,
    517			client->addr << 1, client->adapter->name);
    518	else
    519		v4l2_info(sd, "chip (%02x:%04x) found @ 0x%x (%s)\n",
    520			ver, pn, client->addr << 1, client->adapter->name);
    521
    522	vpx3220_write_block(sd, init_common, sizeof(init_common));
    523	vpx3220_write_fp_block(sd, init_fp, sizeof(init_fp) >> 1);
    524	/* Default to PAL */
    525	vpx3220_write_fp_block(sd, init_pal, sizeof(init_pal) >> 1);
    526	return 0;
    527}
    528
    529static int vpx3220_remove(struct i2c_client *client)
    530{
    531	struct v4l2_subdev *sd = i2c_get_clientdata(client);
    532	struct vpx3220 *decoder = to_vpx3220(sd);
    533
    534	v4l2_device_unregister_subdev(sd);
    535	v4l2_ctrl_handler_free(&decoder->hdl);
    536
    537	return 0;
    538}
    539
    540static const struct i2c_device_id vpx3220_id[] = {
    541	{ "vpx3220a", 0 },
    542	{ "vpx3216b", 0 },
    543	{ "vpx3214c", 0 },
    544	{ }
    545};
    546MODULE_DEVICE_TABLE(i2c, vpx3220_id);
    547
    548static struct i2c_driver vpx3220_driver = {
    549	.driver = {
    550		.name	= "vpx3220",
    551	},
    552	.probe		= vpx3220_probe,
    553	.remove		= vpx3220_remove,
    554	.id_table	= vpx3220_id,
    555};
    556
    557module_i2c_driver(vpx3220_driver);