brintos

brintos / linux-shallow public Read only

0
0
Text · 10.6 KiB · 4b328ad Raw
407 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Zoran ZR36016 basic configuration functions4 *5 * Copyright (C) 2001 Wolfgang Scherr <scherr@net4you.at>6 */7 8#include <linux/module.h>9#include <linux/init.h>10#include <linux/slab.h>11 12/* headerfile of this module */13#include "zr36016.h"14 15/* codec io API */16#include "videocodec.h"17 18/*19 * it doesn't make sense to have more than 20 or so,20 * just to prevent some unwanted loops21 */22#define MAX_CODECS 2023 24/* amount of chips attached via this driver */25static int zr36016_codecs;26 27/*28 * Local hardware I/O functions: read/write via codec layer29 * (registers are located in the master device)30 */31 32/* read and write functions */33static u8 zr36016_read(struct zr36016 *ptr, u16 reg)34{35	u8 value = 0;36	struct zoran *zr = videocodec_to_zoran(ptr->codec);37 38	/* just in case something is wrong... */39	if (ptr->codec->master_data->readreg)40		value = (ptr->codec->master_data->readreg(ptr->codec, reg)) & 0xFF;41	else42		zrdev_err(zr, "%s: invalid I/O setup, nothing read!\n", ptr->name);43 44	zrdev_dbg(zr, "%s: reading from 0x%04x: %02x\n", ptr->name, reg, value);45 46	return value;47}48 49static void zr36016_write(struct zr36016 *ptr, u16 reg, u8 value)50{51	struct zoran *zr = videocodec_to_zoran(ptr->codec);52 53	zrdev_dbg(zr, "%s: writing 0x%02x to 0x%04x\n", ptr->name, value, reg);54 55	// just in case something is wrong...56	if (ptr->codec->master_data->writereg)57		ptr->codec->master_data->writereg(ptr->codec, reg, value);58	else59		zrdev_err(zr, "%s: invalid I/O setup, nothing written!\n", ptr->name);60}61 62/*63 * indirect read and write functions64 *65 * the 016 supports auto-addr-increment, but66 * writing it all time cost not much and is safer...67 */68static u8 zr36016_readi(struct zr36016 *ptr, u16 reg)69{70	u8 value = 0;71	struct zoran *zr = videocodec_to_zoran(ptr->codec);72 73	/* just in case something is wrong... */74	if ((ptr->codec->master_data->writereg) && (ptr->codec->master_data->readreg)) {75		ptr->codec->master_data->writereg(ptr->codec, ZR016_IADDR, reg & 0x0F);76		value = (ptr->codec->master_data->readreg(ptr->codec, ZR016_IDATA)) & 0xFF;77	} else {78		zrdev_err(zr, "%s: invalid I/O setup, nothing read (i)!\n", ptr->name);79	}80 81	zrdev_dbg(zr, "%s: reading indirect from 0x%04x: %02x\n",82		  ptr->name, reg, value);83	return value;84}85 86static void zr36016_writei(struct zr36016 *ptr, u16 reg, u8 value)87{88	struct zoran *zr = videocodec_to_zoran(ptr->codec);89 90	zrdev_dbg(zr, "%s: writing indirect 0x%02x to 0x%04x\n", ptr->name,91		  value, reg);92 93	/* just in case something is wrong... */94	if (ptr->codec->master_data->writereg) {95		ptr->codec->master_data->writereg(ptr->codec, ZR016_IADDR, reg & 0x0F);96		ptr->codec->master_data->writereg(ptr->codec, ZR016_IDATA, value & 0x0FF);97	} else {98		zrdev_err(zr, "%s: invalid I/O setup, nothing written (i)!\n", ptr->name);99	}100}101 102/* Local helper function: version read */103 104/* version kept in datastructure */105static u8 zr36016_read_version(struct zr36016 *ptr)106{107	ptr->version = zr36016_read(ptr, 0) >> 4;108	return ptr->version;109}110 111/*112 * Local helper function: basic test of "connectivity", writes/reads113 * to/from PAX-Lo register114 */115 116static int zr36016_basic_test(struct zr36016 *ptr)117{118	struct zoran *zr = videocodec_to_zoran(ptr->codec);119 120	if (*KERN_INFO <= CONSOLE_LOGLEVEL_DEFAULT) {121		int i;122 123		zr36016_writei(ptr, ZR016I_PAX_LO, 0x55);124		zrdev_dbg(zr, "%s: registers: ", ptr->name);125		for (i = 0; i <= 0x0b; i++)126			zrdev_dbg(zr, "%02x ", zr36016_readi(ptr, i));127		zrdev_dbg(zr, "\n");128	}129	// for testing just write 0, then the default value to a register and read130	// it back in both cases131	zr36016_writei(ptr, ZR016I_PAX_LO, 0x00);132	if (zr36016_readi(ptr, ZR016I_PAX_LO) != 0x0) {133		zrdev_err(zr, "%s: attach failed, can't connect to vfe processor!\n", ptr->name);134		return -ENXIO;135	}136	zr36016_writei(ptr, ZR016I_PAX_LO, 0x0d0);137	if (zr36016_readi(ptr, ZR016I_PAX_LO) != 0x0d0) {138		zrdev_err(zr, "%s: attach failed, can't connect to vfe processor!\n", ptr->name);139		return -ENXIO;140	}141	// we allow version numbers from 0-3, should be enough, though142	zr36016_read_version(ptr);143	if (ptr->version & 0x0c) {144		zrdev_err(zr, "%s: attach failed, suspicious version %d found...\n", ptr->name,145			  ptr->version);146		return -ENXIO;147	}148 149	return 0;		/* looks good! */150}151 152/* Basic datasets & init */153 154static void zr36016_init(struct zr36016 *ptr)155{156	// stop any processing157	zr36016_write(ptr, ZR016_GOSTOP, 0);158 159	// mode setup (yuv422 in and out, compression/expansuon due to mode)160	zr36016_write(ptr, ZR016_MODE,161		      ZR016_YUV422 | ZR016_YUV422_YUV422 |162		      (ptr->mode == CODEC_DO_COMPRESSION ?163		       ZR016_COMPRESSION : ZR016_EXPANSION));164 165	// misc setup166	zr36016_writei(ptr, ZR016I_SETUP1,167		       (ptr->xdec ? (ZR016_HRFL | ZR016_HORZ) : 0) |168		       (ptr->ydec ? ZR016_VERT : 0) | ZR016_CNTI);169	zr36016_writei(ptr, ZR016I_SETUP2, ZR016_CCIR);170 171	// Window setup172	// (no extra offset for now, norm defines offset, default width height)173	zr36016_writei(ptr, ZR016I_PAX_HI, ptr->width >> 8);174	zr36016_writei(ptr, ZR016I_PAX_LO, ptr->width & 0xFF);175	zr36016_writei(ptr, ZR016I_PAY_HI, ptr->height >> 8);176	zr36016_writei(ptr, ZR016I_PAY_LO, ptr->height & 0xFF);177	zr36016_writei(ptr, ZR016I_NAX_HI, ptr->xoff >> 8);178	zr36016_writei(ptr, ZR016I_NAX_LO, ptr->xoff & 0xFF);179	zr36016_writei(ptr, ZR016I_NAY_HI, ptr->yoff >> 8);180	zr36016_writei(ptr, ZR016I_NAY_LO, ptr->yoff & 0xFF);181 182	/* shall we continue now, please? */183	zr36016_write(ptr, ZR016_GOSTOP, 1);184}185 186/*187 * CODEC API FUNCTIONS188 *189 * These functions are accessed by the master via the API structure190 */191 192/*193 * set compression/expansion mode and launches codec -194 * this should be the last call from the master before starting processing195 */196static int zr36016_set_mode(struct videocodec *codec, int mode)197{198	struct zr36016 *ptr = (struct zr36016 *)codec->data;199	struct zoran *zr = videocodec_to_zoran(codec);200 201	zrdev_dbg(zr, "%s: set_mode %d call\n", ptr->name, mode);202 203	if ((mode != CODEC_DO_EXPANSION) && (mode != CODEC_DO_COMPRESSION))204		return -EINVAL;205 206	ptr->mode = mode;207	zr36016_init(ptr);208 209	return 0;210}211 212/* set picture size */213static int zr36016_set_video(struct videocodec *codec, const struct tvnorm *norm,214			     struct vfe_settings *cap, struct vfe_polarity *pol)215{216	struct zr36016 *ptr = (struct zr36016 *)codec->data;217	struct zoran *zr = videocodec_to_zoran(codec);218 219	zrdev_dbg(zr, "%s: set_video %d.%d, %d/%d-%dx%d (0x%x) call\n",220		  ptr->name, norm->h_start, norm->v_start,221		  cap->x, cap->y, cap->width, cap->height,222		  cap->decimation);223 224	/*225	 * if () return -EINVAL;226	 * trust the master driver that it knows what it does - so227	 * we allow invalid startx/y for now ...228	 */229	ptr->width = cap->width;230	ptr->height = cap->height;231	/*232	 * (Ronald) This is ugly. zoran_device.c, line 387233	 * already mentions what happens if h_start is even234	 * (blue faces, etc., cr/cb inversed). There's probably235	 * some good reason why h_start is 0 instead of 1, so I'm236	 * leaving it to this for now, but really... This can be237	 * done a lot simpler238	 */239	ptr->xoff = (norm->h_start ? norm->h_start : 1) + cap->x;240	/*241	 * Something to note here (I don't understand it), setting242	 * v_start too high will cause the codec to 'not work'. I243	 * really don't get it. values of 16 (v_start) already break244	 * it here. Just '0' seems to work. More testing needed!245	 */246	ptr->yoff = norm->v_start + cap->y;247	/* (Ronald) dzjeeh, can't this thing do hor_decimation = 4? */248	ptr->xdec = ((cap->decimation & 0xff) == 1) ? 0 : 1;249	ptr->ydec = (((cap->decimation >> 8) & 0xff) == 1) ? 0 : 1;250 251	return 0;252}253 254/* additional control functions */255static int zr36016_control(struct videocodec *codec, int type, int size, void *data)256{257	struct zr36016 *ptr = (struct zr36016 *)codec->data;258	struct zoran *zr = videocodec_to_zoran(codec);259	int *ival = (int *)data;260 261	zrdev_dbg(zr, "%s: control %d call with %d byte\n",262		  ptr->name, type, size);263 264	switch (type) {265	case CODEC_G_STATUS:	/* get last status - we don't know it ... */266		if (size != sizeof(int))267			return -EFAULT;268		*ival = 0;269		break;270 271	case CODEC_G_CODEC_MODE:272		if (size != sizeof(int))273			return -EFAULT;274		*ival = 0;275		break;276 277	case CODEC_S_CODEC_MODE:278		if (size != sizeof(int))279			return -EFAULT;280		if (*ival != 0)281			return -EINVAL;282		/* not needed, do nothing */283		return 0;284 285	case CODEC_G_VFE:286	case CODEC_S_VFE:287		return 0;288 289	case CODEC_S_MMAP:290		/* not available, give an error */291		return -ENXIO;292 293	default:294		return -EINVAL;295	}296 297	return size;298}299 300/*301 * Exit and unregister function:302 *303 * Deinitializes Zoran's JPEG processor304 */305 306static int zr36016_unset(struct videocodec *codec)307{308	struct zr36016 *ptr = codec->data;309	struct zoran *zr = videocodec_to_zoran(codec);310 311	if (ptr) {312		/* do wee need some codec deinit here, too ???? */313 314		zrdev_dbg(zr, "%s: finished codec #%d\n", ptr->name, ptr->num);315		kfree(ptr);316		codec->data = NULL;317 318		zr36016_codecs--;319		return 0;320	}321 322	return -EFAULT;323}324 325/*326 * Setup and registry function:327 *328 * Initializes Zoran's JPEG processor329 *330 * Also sets pixel size, average code size, mode (compr./decompr.)331 * (the given size is determined by the processor with the video interface)332 */333 334static int zr36016_setup(struct videocodec *codec)335{336	struct zr36016 *ptr;337	struct zoran *zr = videocodec_to_zoran(codec);338	int res;339 340	zrdev_dbg(zr, "zr36016: initializing VFE subsystem #%d.\n", zr36016_codecs);341 342	if (zr36016_codecs == MAX_CODECS) {343		zrdev_err(zr, "zr36016: Can't attach more codecs!\n");344		return -ENOSPC;345	}346	//mem structure init347	ptr = kzalloc(sizeof(*ptr), GFP_KERNEL);348	codec->data = ptr;349	if (!ptr)350		return -ENOMEM;351 352	snprintf(ptr->name, sizeof(ptr->name), "zr36016[%d]", zr36016_codecs);353	ptr->num = zr36016_codecs++;354	ptr->codec = codec;355 356	//testing357	res = zr36016_basic_test(ptr);358	if (res < 0) {359		zr36016_unset(codec);360		return res;361	}362	//final setup363	ptr->mode = CODEC_DO_COMPRESSION;364	ptr->width = 768;365	ptr->height = 288;366	ptr->xdec = 1;367	ptr->ydec = 0;368	zr36016_init(ptr);369 370	zrdev_dbg(zr, "%s: codec v%d attached and running\n",371		  ptr->name, ptr->version);372 373	return 0;374}375 376static const struct videocodec zr36016_codec = {377	.name = "zr36016",378	.magic = 0L,		/* magic not used */379	.flags =380	    CODEC_FLAG_HARDWARE | CODEC_FLAG_VFE | CODEC_FLAG_ENCODER |381	    CODEC_FLAG_DECODER,382	.type = CODEC_TYPE_ZR36016,383	.setup = zr36016_setup,	/* functionality */384	.unset = zr36016_unset,385	.set_mode = zr36016_set_mode,386	.set_video = zr36016_set_video,387	.control = zr36016_control,388	/* others are not used */389};390 391/* HOOK IN DRIVER AS KERNEL MODULE */392 393int zr36016_init_module(void)394{395	zr36016_codecs = 0;396	return videocodec_register(&zr36016_codec);397}398 399void zr36016_cleanup_module(void)400{401	if (zr36016_codecs) {402		pr_debug("zr36016: something's wrong - %d codecs left somehow.\n",403			 zr36016_codecs);404	}405	videocodec_unregister(&zr36016_codec);406}407