brintos

brintos / linux-shallow public Read only

0
0
Text · 27.8 KiB · cdf5d73 Raw
1020 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 *  tw68 functions to handle video data4 *5 *  Much of this code is derived from the cx88 and sa7134 drivers, which6 *  were in turn derived from the bt87x driver.  The original work was by7 *  Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab,8 *  Hans Verkuil, Andy Walls and many others.  Their work is gratefully9 *  acknowledged.  Full credit goes to them - any problems within this code10 *  are mine.11 *12 *  Copyright (C) 2009  William M. Brack13 *14 *  Refactored and updated to the latest v4l core frameworks:15 *16 *  Copyright (C) 2014 Hans Verkuil <hverkuil@xs4all.nl>17 */18 19#include <linux/module.h>20#include <media/v4l2-common.h>21#include <media/v4l2-event.h>22#include <media/videobuf2-dma-sg.h>23 24#include "tw68.h"25#include "tw68-reg.h"26 27/* ------------------------------------------------------------------ */28/* data structs for video                                             */29/*30 * FIXME -31 * Note that the saa7134 has formats, e.g. YUV420, which are classified32 * as "planar".  These affect overlay mode, and are flagged with a field33 * ".planar" in the format.  Do we need to implement this in this driver?34 */35static const struct tw68_format formats[] = {36	{37		.fourcc		= V4L2_PIX_FMT_RGB555,38		.depth		= 16,39		.twformat	= ColorFormatRGB15,40	}, {41		.fourcc		= V4L2_PIX_FMT_RGB555X,42		.depth		= 16,43		.twformat	= ColorFormatRGB15 | ColorFormatBSWAP,44	}, {45		.fourcc		= V4L2_PIX_FMT_RGB565,46		.depth		= 16,47		.twformat	= ColorFormatRGB16,48	}, {49		.fourcc		= V4L2_PIX_FMT_RGB565X,50		.depth		= 16,51		.twformat	= ColorFormatRGB16 | ColorFormatBSWAP,52	}, {53		.fourcc		= V4L2_PIX_FMT_BGR24,54		.depth		= 24,55		.twformat	= ColorFormatRGB24,56	}, {57		.fourcc		= V4L2_PIX_FMT_RGB24,58		.depth		= 24,59		.twformat	= ColorFormatRGB24 | ColorFormatBSWAP,60	}, {61		.fourcc		= V4L2_PIX_FMT_BGR32,62		.depth		= 32,63		.twformat	= ColorFormatRGB32,64	}, {65		.fourcc		= V4L2_PIX_FMT_RGB32,66		.depth		= 32,67		.twformat	= ColorFormatRGB32 | ColorFormatBSWAP |68				  ColorFormatWSWAP,69	}, {70		.fourcc		= V4L2_PIX_FMT_YUYV,71		.depth		= 16,72		.twformat	= ColorFormatYUY2,73	}, {74		.fourcc		= V4L2_PIX_FMT_UYVY,75		.depth		= 16,76		.twformat	= ColorFormatYUY2 | ColorFormatBSWAP,77	}78};79#define FORMATS ARRAY_SIZE(formats)80 81#define NORM_625_50			\82		.h_delay	= 3,	\83		.h_delay0	= 133,	\84		.h_start	= 0,	\85		.h_stop		= 719,	\86		.v_delay	= 24,	\87		.vbi_v_start_0	= 7,	\88		.vbi_v_stop_0	= 22,	\89		.video_v_start	= 24,	\90		.video_v_stop	= 311,	\91		.vbi_v_start_1	= 31992 93#define NORM_525_60			\94		.h_delay	= 8,	\95		.h_delay0	= 138,	\96		.h_start	= 0,	\97		.h_stop		= 719,	\98		.v_delay	= 22,	\99		.vbi_v_start_0	= 10,	\100		.vbi_v_stop_0	= 21,	\101		.video_v_start	= 22,	\102		.video_v_stop	= 262,	\103		.vbi_v_start_1	= 273104 105/*106 * The following table is searched by tw68_s_std, first for a specific107 * match, then for an entry which contains the desired id.  The table108 * entries should therefore be ordered in ascending order of specificity.109 */110static const struct tw68_tvnorm tvnorms[] = {111	{112		.name		= "PAL", /* autodetect */113		.id		= V4L2_STD_PAL,114		NORM_625_50,115 116		.sync_control	= 0x18,117		.luma_control	= 0x40,118		.chroma_ctrl1	= 0x81,119		.chroma_gain	= 0x2a,120		.chroma_ctrl2	= 0x06,121		.vgate_misc	= 0x1c,122		.format		= VideoFormatPALBDGHI,123	}, {124		.name		= "NTSC",125		.id		= V4L2_STD_NTSC,126		NORM_525_60,127 128		.sync_control	= 0x59,129		.luma_control	= 0x40,130		.chroma_ctrl1	= 0x89,131		.chroma_gain	= 0x2a,132		.chroma_ctrl2	= 0x0e,133		.vgate_misc	= 0x18,134		.format		= VideoFormatNTSC,135	}, {136		.name		= "SECAM",137		.id		= V4L2_STD_SECAM,138		NORM_625_50,139 140		.sync_control	= 0x18,141		.luma_control	= 0x1b,142		.chroma_ctrl1	= 0xd1,143		.chroma_gain	= 0x80,144		.chroma_ctrl2	= 0x00,145		.vgate_misc	= 0x1c,146		.format		= VideoFormatSECAM,147	}, {148		.name		= "PAL-M",149		.id		= V4L2_STD_PAL_M,150		NORM_525_60,151 152		.sync_control	= 0x59,153		.luma_control	= 0x40,154		.chroma_ctrl1	= 0xb9,155		.chroma_gain	= 0x2a,156		.chroma_ctrl2	= 0x0e,157		.vgate_misc	= 0x18,158		.format		= VideoFormatPALM,159	}, {160		.name		= "PAL-Nc",161		.id		= V4L2_STD_PAL_Nc,162		NORM_625_50,163 164		.sync_control	= 0x18,165		.luma_control	= 0x40,166		.chroma_ctrl1	= 0xa1,167		.chroma_gain	= 0x2a,168		.chroma_ctrl2	= 0x06,169		.vgate_misc	= 0x1c,170		.format		= VideoFormatPALNC,171	}, {172		.name		= "PAL-60",173		.id		= V4L2_STD_PAL_60,174		.h_delay	= 186,175		.h_start	= 0,176		.h_stop		= 719,177		.v_delay	= 26,178		.video_v_start	= 23,179		.video_v_stop	= 262,180		.vbi_v_start_0	= 10,181		.vbi_v_stop_0	= 21,182		.vbi_v_start_1	= 273,183 184		.sync_control	= 0x18,185		.luma_control	= 0x40,186		.chroma_ctrl1	= 0x81,187		.chroma_gain	= 0x2a,188		.chroma_ctrl2	= 0x06,189		.vgate_misc	= 0x1c,190		.format		= VideoFormatPAL60,191	}192};193#define TVNORMS ARRAY_SIZE(tvnorms)194 195static const struct tw68_format *format_by_fourcc(unsigned int fourcc)196{197	unsigned int i;198 199	for (i = 0; i < FORMATS; i++)200		if (formats[i].fourcc == fourcc)201			return formats+i;202	return NULL;203}204 205 206/* ------------------------------------------------------------------ */207/*208 * Note that the cropping rectangles are described in terms of a single209 * frame, i.e. line positions are only 1/2 the interlaced equivalent210 */211static void set_tvnorm(struct tw68_dev *dev, const struct tw68_tvnorm *norm)212{213	if (norm != dev->tvnorm) {214		dev->width = 720;215		dev->height = (norm->id & V4L2_STD_525_60) ? 480 : 576;216		dev->tvnorm = norm;217		tw68_set_tvnorm_hw(dev);218	}219}220 221/*222 * tw68_set_scale223 *224 * Scaling and Cropping for video decoding225 *226 * We are working with 3 values for horizontal and vertical - scale,227 * delay and active.228 *229 * HACTIVE represent the actual number of pixels in the "usable" image,230 * before scaling.  HDELAY represents the number of pixels skipped231 * between the start of the horizontal sync and the start of the image.232 * HSCALE is calculated using the formula233 *	HSCALE = (HACTIVE / (#pixels desired)) * 256234 *235 * The vertical registers are similar, except based upon the total number236 * of lines in the image, and the first line of the image (i.e. ignoring237 * vertical sync and VBI).238 *239 * Note that the number of bytes reaching the FIFO (and hence needing240 * to be processed by the DMAP program) is completely dependent upon241 * these values, especially HSCALE.242 *243 * Parameters:244 *	@dev		pointer to the device structure, needed for245 *			getting current norm (as well as debug print)246 *	@width		actual image width (from user buffer)247 *	@height		actual image height248 *	@field		indicates Top, Bottom or Interlaced249 */250static int tw68_set_scale(struct tw68_dev *dev, unsigned int width,251			  unsigned int height, enum v4l2_field field)252{253	const struct tw68_tvnorm *norm = dev->tvnorm;254	/* set individually for debugging clarity */255	int hactive, hdelay, hscale;256	int vactive, vdelay, vscale;257	int comb;258 259	if (V4L2_FIELD_HAS_BOTH(field))	/* if field is interlaced */260		height /= 2;		/* we must set for 1-frame */261 262	pr_debug("%s: width=%d, height=%d, both=%d\n"263		 "  tvnorm h_delay=%d, h_start=%d, h_stop=%d, v_delay=%d, v_start=%d, v_stop=%d\n",264		__func__, width, height, V4L2_FIELD_HAS_BOTH(field),265		norm->h_delay, norm->h_start, norm->h_stop,266		norm->v_delay, norm->video_v_start,267		norm->video_v_stop);268 269	switch (dev->vdecoder) {270	case TW6800:271		hdelay = norm->h_delay0;272		break;273	default:274		hdelay = norm->h_delay;275		break;276	}277 278	hdelay += norm->h_start;279	hactive = norm->h_stop - norm->h_start + 1;280 281	hscale = (hactive * 256) / (width);282 283	vdelay = norm->v_delay;284	vactive = ((norm->id & V4L2_STD_525_60) ? 524 : 624) / 2 - norm->video_v_start;285	vscale = (vactive * 256) / height;286 287	pr_debug("%s: %dx%d [%s%s,%s]\n", __func__,288		width, height,289		V4L2_FIELD_HAS_TOP(field)    ? "T" : "",290		V4L2_FIELD_HAS_BOTTOM(field) ? "B" : "",291		v4l2_norm_to_name(dev->tvnorm->id));292	pr_debug("%s: hactive=%d, hdelay=%d, hscale=%d; vactive=%d, vdelay=%d, vscale=%d\n",293		 __func__,294		hactive, hdelay, hscale, vactive, vdelay, vscale);295 296	comb =	((vdelay & 0x300)  >> 2) |297		((vactive & 0x300) >> 4) |298		((hdelay & 0x300)  >> 6) |299		((hactive & 0x300) >> 8);300	pr_debug("%s: setting CROP_HI=%02x, VDELAY_LO=%02x, VACTIVE_LO=%02x, HDELAY_LO=%02x, HACTIVE_LO=%02x\n",301		__func__, comb, vdelay, vactive, hdelay, hactive);302	tw_writeb(TW68_CROP_HI, comb);303	tw_writeb(TW68_VDELAY_LO, vdelay & 0xff);304	tw_writeb(TW68_VACTIVE_LO, vactive & 0xff);305	tw_writeb(TW68_HDELAY_LO, hdelay & 0xff);306	tw_writeb(TW68_HACTIVE_LO, hactive & 0xff);307 308	comb = ((vscale & 0xf00) >> 4) | ((hscale & 0xf00) >> 8);309	pr_debug("%s: setting SCALE_HI=%02x, VSCALE_LO=%02x, HSCALE_LO=%02x\n",310		 __func__, comb, vscale, hscale);311	tw_writeb(TW68_SCALE_HI, comb);312	tw_writeb(TW68_VSCALE_LO, vscale);313	tw_writeb(TW68_HSCALE_LO, hscale);314 315	return 0;316}317 318/* ------------------------------------------------------------------ */319 320int tw68_video_start_dma(struct tw68_dev *dev, struct tw68_buf *buf)321{322	/* Set cropping and scaling */323	tw68_set_scale(dev, dev->width, dev->height, dev->field);324	/*325	 *  Set start address for RISC program.  Note that if the DMAP326	 *  processor is currently running, it must be stopped before327	 *  a new address can be set.328	 */329	tw_clearl(TW68_DMAC, TW68_DMAP_EN);330	tw_writel(TW68_DMAP_SA, buf->dma);331	/* Clear any pending interrupts */332	tw_writel(TW68_INTSTAT, dev->board_virqmask);333	/* Enable the risc engine and the fifo */334	tw_andorl(TW68_DMAC, 0xff, dev->fmt->twformat |335		ColorFormatGamma | TW68_DMAP_EN | TW68_FIFO_EN);336	dev->pci_irqmask |= dev->board_virqmask;337	tw_setl(TW68_INTMASK, dev->pci_irqmask);338	return 0;339}340 341/* ------------------------------------------------------------------ */342 343/* calc max # of buffers from size (must not exceed the 4MB virtual344 * address space per DMA channel) */345static int tw68_buffer_count(unsigned int size, unsigned int count)346{347	unsigned int maxcount;348 349	maxcount = (4 * 1024 * 1024) / roundup(size, PAGE_SIZE);350	if (count > maxcount)351		count = maxcount;352	return count;353}354 355/* ------------------------------------------------------------- */356/* vb2 queue operations                                          */357 358static int tw68_queue_setup(struct vb2_queue *q,359			   unsigned int *num_buffers, unsigned int *num_planes,360			   unsigned int sizes[], struct device *alloc_devs[])361{362	struct tw68_dev *dev = vb2_get_drv_priv(q);363	unsigned int q_num_bufs = vb2_get_num_buffers(q);364	unsigned int tot_bufs = q_num_bufs + *num_buffers;365	unsigned size = (dev->fmt->depth * dev->width * dev->height) >> 3;366 367	if (tot_bufs < 2)368		tot_bufs = 2;369	tot_bufs = tw68_buffer_count(size, tot_bufs);370	*num_buffers = tot_bufs - q_num_bufs;371	/*372	 * We allow create_bufs, but only if the sizeimage is >= as the373	 * current sizeimage. The tw68_buffer_count calculation becomes quite374	 * difficult otherwise.375	 */376	if (*num_planes)377		return sizes[0] < size ? -EINVAL : 0;378	*num_planes = 1;379	sizes[0] = size;380 381	return 0;382}383 384/*385 * The risc program for each buffers works as follows: it starts with a simple386 * 'JUMP to addr + 8', which is effectively a NOP. Then the program to DMA the387 * buffer follows and at the end we have a JUMP back to the start + 8 (skipping388 * the initial JUMP).389 *390 * This is the program of the first buffer to be queued if the active list is391 * empty and it just keeps DMAing this buffer without generating any interrupts.392 *393 * If a new buffer is added then the initial JUMP in the program generates an394 * interrupt as well which signals that the previous buffer has been DMAed395 * successfully and that it can be returned to userspace.396 *397 * It also sets the final jump of the previous buffer to the start of the new398 * buffer, thus chaining the new buffer into the DMA chain. This is a single399 * atomic u32 write, so there is no race condition.400 *401 * The end-result of all this that you only get an interrupt when a buffer402 * is ready, so the control flow is very easy.403 */404static void tw68_buf_queue(struct vb2_buffer *vb)405{406	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);407	struct vb2_queue *vq = vb->vb2_queue;408	struct tw68_dev *dev = vb2_get_drv_priv(vq);409	struct tw68_buf *buf = container_of(vbuf, struct tw68_buf, vb);410	struct tw68_buf *prev;411	unsigned long flags;412 413	spin_lock_irqsave(&dev->slock, flags);414 415	/* append a 'JUMP to start of buffer' to the buffer risc program */416	buf->jmp[0] = cpu_to_le32(RISC_JUMP);417	buf->jmp[1] = cpu_to_le32(buf->dma + 8);418 419	if (!list_empty(&dev->active)) {420		prev = list_entry(dev->active.prev, struct tw68_buf, list);421		buf->cpu[0] |= cpu_to_le32(RISC_INT_BIT);422		prev->jmp[1] = cpu_to_le32(buf->dma);423	}424	list_add_tail(&buf->list, &dev->active);425	spin_unlock_irqrestore(&dev->slock, flags);426}427 428/*429 * buffer_prepare430 *431 * Set the ancillary information into the buffer structure.  This432 * includes generating the necessary risc program if it hasn't already433 * been done for the current buffer format.434 * The structure fh contains the details of the format requested by the435 * user - type, width, height and #fields.  This is compared with the436 * last format set for the current buffer.  If they differ, the risc437 * code (which controls the filling of the buffer) is (re-)generated.438 */439static int tw68_buf_prepare(struct vb2_buffer *vb)440{441	int ret;442	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);443	struct vb2_queue *vq = vb->vb2_queue;444	struct tw68_dev *dev = vb2_get_drv_priv(vq);445	struct tw68_buf *buf = container_of(vbuf, struct tw68_buf, vb);446	struct sg_table *dma = vb2_dma_sg_plane_desc(vb, 0);447	unsigned size, bpl;448 449	size = (dev->width * dev->height * dev->fmt->depth) >> 3;450	if (vb2_plane_size(vb, 0) < size)451		return -EINVAL;452	vb2_set_plane_payload(vb, 0, size);453 454	bpl = (dev->width * dev->fmt->depth) >> 3;455	switch (dev->field) {456	case V4L2_FIELD_TOP:457		ret = tw68_risc_buffer(dev->pci, buf, dma->sgl,458				 0, UNSET, bpl, 0, dev->height);459		break;460	case V4L2_FIELD_BOTTOM:461		ret = tw68_risc_buffer(dev->pci, buf, dma->sgl,462				 UNSET, 0, bpl, 0, dev->height);463		break;464	case V4L2_FIELD_SEQ_TB:465		ret = tw68_risc_buffer(dev->pci, buf, dma->sgl,466				 0, bpl * (dev->height >> 1),467				 bpl, 0, dev->height >> 1);468		break;469	case V4L2_FIELD_SEQ_BT:470		ret = tw68_risc_buffer(dev->pci, buf, dma->sgl,471				 bpl * (dev->height >> 1), 0,472				 bpl, 0, dev->height >> 1);473		break;474	case V4L2_FIELD_INTERLACED:475	default:476		ret = tw68_risc_buffer(dev->pci, buf, dma->sgl,477				 0, bpl, bpl, bpl, dev->height >> 1);478		break;479	}480	return ret;481}482 483static void tw68_buf_finish(struct vb2_buffer *vb)484{485	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);486	struct vb2_queue *vq = vb->vb2_queue;487	struct tw68_dev *dev = vb2_get_drv_priv(vq);488	struct tw68_buf *buf = container_of(vbuf, struct tw68_buf, vb);489 490	if (buf->cpu)491		dma_free_coherent(&dev->pci->dev, buf->size, buf->cpu, buf->dma);492}493 494static int tw68_start_streaming(struct vb2_queue *q, unsigned int count)495{496	struct tw68_dev *dev = vb2_get_drv_priv(q);497	struct tw68_buf *buf =498		container_of(dev->active.next, struct tw68_buf, list);499 500	dev->seqnr = 0;501	tw68_video_start_dma(dev, buf);502	return 0;503}504 505static void tw68_stop_streaming(struct vb2_queue *q)506{507	struct tw68_dev *dev = vb2_get_drv_priv(q);508 509	/* Stop risc & fifo */510	tw_clearl(TW68_DMAC, TW68_DMAP_EN | TW68_FIFO_EN);511	while (!list_empty(&dev->active)) {512		struct tw68_buf *buf =513			container_of(dev->active.next, struct tw68_buf, list);514 515		list_del(&buf->list);516		vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);517	}518}519 520static const struct vb2_ops tw68_video_qops = {521	.queue_setup	= tw68_queue_setup,522	.buf_queue	= tw68_buf_queue,523	.buf_prepare	= tw68_buf_prepare,524	.buf_finish	= tw68_buf_finish,525	.start_streaming = tw68_start_streaming,526	.stop_streaming = tw68_stop_streaming,527	.wait_prepare	= vb2_ops_wait_prepare,528	.wait_finish	= vb2_ops_wait_finish,529};530 531/* ------------------------------------------------------------------ */532 533static int tw68_s_ctrl(struct v4l2_ctrl *ctrl)534{535	struct tw68_dev *dev =536		container_of(ctrl->handler, struct tw68_dev, hdl);537 538	switch (ctrl->id) {539	case V4L2_CID_BRIGHTNESS:540		tw_writeb(TW68_BRIGHT, ctrl->val);541		break;542	case V4L2_CID_HUE:543		tw_writeb(TW68_HUE, ctrl->val);544		break;545	case V4L2_CID_CONTRAST:546		tw_writeb(TW68_CONTRAST, ctrl->val);547		break;548	case V4L2_CID_SATURATION:549		tw_writeb(TW68_SAT_U, ctrl->val);550		tw_writeb(TW68_SAT_V, ctrl->val);551		break;552	case V4L2_CID_COLOR_KILLER:553		if (ctrl->val)554			tw_andorb(TW68_MISC2, 0xe0, 0xe0);555		else556			tw_andorb(TW68_MISC2, 0xe0, 0x00);557		break;558	case V4L2_CID_CHROMA_AGC:559		if (ctrl->val)560			tw_andorb(TW68_LOOP, 0x30, 0x20);561		else562			tw_andorb(TW68_LOOP, 0x30, 0x00);563		break;564	}565	return 0;566}567 568/* ------------------------------------------------------------------ */569 570/*571 * Note that this routine returns what is stored in the fh structure, and572 * does not interrogate any of the device registers.573 */574static int tw68_g_fmt_vid_cap(struct file *file, void *priv,575				struct v4l2_format *f)576{577	struct tw68_dev *dev = video_drvdata(file);578 579	f->fmt.pix.width        = dev->width;580	f->fmt.pix.height       = dev->height;581	f->fmt.pix.field        = dev->field;582	f->fmt.pix.pixelformat  = dev->fmt->fourcc;583	f->fmt.pix.bytesperline =584		(f->fmt.pix.width * (dev->fmt->depth)) >> 3;585	f->fmt.pix.sizeimage =586		f->fmt.pix.height * f->fmt.pix.bytesperline;587	f->fmt.pix.colorspace	= V4L2_COLORSPACE_SMPTE170M;588	return 0;589}590 591static int tw68_try_fmt_vid_cap(struct file *file, void *priv,592						struct v4l2_format *f)593{594	struct tw68_dev *dev = video_drvdata(file);595	const struct tw68_format *fmt;596	enum v4l2_field field;597	unsigned int maxh;598 599	fmt = format_by_fourcc(f->fmt.pix.pixelformat);600	if (NULL == fmt)601		return -EINVAL;602 603	field = f->fmt.pix.field;604	maxh  = (dev->tvnorm->id & V4L2_STD_525_60) ? 480 : 576;605 606	switch (field) {607	case V4L2_FIELD_TOP:608	case V4L2_FIELD_BOTTOM:609		break;610	case V4L2_FIELD_INTERLACED:611	case V4L2_FIELD_SEQ_BT:612	case V4L2_FIELD_SEQ_TB:613		maxh = maxh * 2;614		break;615	default:616		field = (f->fmt.pix.height > maxh / 2)617			? V4L2_FIELD_INTERLACED618			: V4L2_FIELD_BOTTOM;619		break;620	}621 622	f->fmt.pix.field = field;623	if (f->fmt.pix.width  < 48)624		f->fmt.pix.width  = 48;625	if (f->fmt.pix.height < 32)626		f->fmt.pix.height = 32;627	if (f->fmt.pix.width > 720)628		f->fmt.pix.width = 720;629	if (f->fmt.pix.height > maxh)630		f->fmt.pix.height = maxh;631	f->fmt.pix.width &= ~0x03;632	f->fmt.pix.bytesperline =633		(f->fmt.pix.width * (fmt->depth)) >> 3;634	f->fmt.pix.sizeimage =635		f->fmt.pix.height * f->fmt.pix.bytesperline;636	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;637	return 0;638}639 640/*641 * Note that tw68_s_fmt_vid_cap sets the information into the fh structure,642 * and it will be used for all future new buffers.  However, there could be643 * some number of buffers on the "active" chain which will be filled before644 * the change takes place.645 */646static int tw68_s_fmt_vid_cap(struct file *file, void *priv,647					struct v4l2_format *f)648{649	struct tw68_dev *dev = video_drvdata(file);650	int err;651 652	err = tw68_try_fmt_vid_cap(file, priv, f);653	if (0 != err)654		return err;655 656	dev->fmt = format_by_fourcc(f->fmt.pix.pixelformat);657	dev->width = f->fmt.pix.width;658	dev->height = f->fmt.pix.height;659	dev->field = f->fmt.pix.field;660	return 0;661}662 663static int tw68_enum_input(struct file *file, void *priv,664					struct v4l2_input *i)665{666	struct tw68_dev *dev = video_drvdata(file);667	unsigned int n;668 669	n = i->index;670	if (n >= TW68_INPUT_MAX)671		return -EINVAL;672	i->index = n;673	i->type = V4L2_INPUT_TYPE_CAMERA;674	snprintf(i->name, sizeof(i->name), "Composite %d", n);675 676	/* If the query is for the current input, get live data */677	if (n == dev->input) {678		int v1 = tw_readb(TW68_STATUS1);679		int v2 = tw_readb(TW68_MVSN);680 681		if (0 != (v1 & (1 << 7)))682			i->status |= V4L2_IN_ST_NO_SYNC;683		if (0 != (v1 & (1 << 6)))684			i->status |= V4L2_IN_ST_NO_H_LOCK;685		if (0 != (v1 & (1 << 2)))686			i->status |= V4L2_IN_ST_NO_SIGNAL;687		if (0 != (v1 & 1 << 1))688			i->status |= V4L2_IN_ST_NO_COLOR;689		if (0 != (v2 & (1 << 2)))690			i->status |= V4L2_IN_ST_MACROVISION;691	}692	i->std = video_devdata(file)->tvnorms;693	return 0;694}695 696static int tw68_g_input(struct file *file, void *priv, unsigned int *i)697{698	struct tw68_dev *dev = video_drvdata(file);699 700	*i = dev->input;701	return 0;702}703 704static int tw68_s_input(struct file *file, void *priv, unsigned int i)705{706	struct tw68_dev *dev = video_drvdata(file);707 708	if (i >= TW68_INPUT_MAX)709		return -EINVAL;710	dev->input = i;711	tw_andorb(TW68_INFORM, 0x03 << 2, dev->input << 2);712	return 0;713}714 715static int tw68_querycap(struct file *file, void  *priv,716					struct v4l2_capability *cap)717{718	strscpy(cap->driver, "tw68", sizeof(cap->driver));719	strscpy(cap->card, "Techwell Capture Card",720		sizeof(cap->card));721	return 0;722}723 724static int tw68_s_std(struct file *file, void *priv, v4l2_std_id id)725{726	struct tw68_dev *dev = video_drvdata(file);727	unsigned int i;728 729	if (vb2_is_busy(&dev->vidq))730		return -EBUSY;731 732	/* Look for match on complete norm id (may have mult bits) */733	for (i = 0; i < TVNORMS; i++) {734		if (id == tvnorms[i].id)735			break;736	}737 738	/* If no exact match, look for norm which contains this one */739	if (i == TVNORMS) {740		for (i = 0; i < TVNORMS; i++)741			if (id & tvnorms[i].id)742				break;743	}744	/* If still not matched, give up */745	if (i == TVNORMS)746		return -EINVAL;747 748	set_tvnorm(dev, &tvnorms[i]);	/* do the actual setting */749	return 0;750}751 752static int tw68_g_std(struct file *file, void *priv, v4l2_std_id *id)753{754	struct tw68_dev *dev = video_drvdata(file);755 756	*id = dev->tvnorm->id;757	return 0;758}759 760static int tw68_enum_fmt_vid_cap(struct file *file, void  *priv,761					struct v4l2_fmtdesc *f)762{763	if (f->index >= FORMATS)764		return -EINVAL;765 766	f->pixelformat = formats[f->index].fourcc;767 768	return 0;769}770 771/*772 * Used strictly for internal development and debugging, this routine773 * prints out the current register contents for the tw68xx device.774 */775static void tw68_dump_regs(struct tw68_dev *dev)776{777	unsigned char line[80];778	int i, j, k;779	unsigned char *cptr;780 781	pr_info("Full dump of TW68 registers:\n");782	/* First we do the PCI regs, 8 4-byte regs per line */783	for (i = 0; i < 0x100; i += 32) {784		cptr = line;785		cptr += sprintf(cptr, "%03x  ", i);786		/* j steps through the next 4 words */787		for (j = i; j < i + 16; j += 4)788			cptr += sprintf(cptr, "%08x ", tw_readl(j));789		*cptr++ = ' ';790		for (; j < i + 32; j += 4)791			cptr += sprintf(cptr, "%08x ", tw_readl(j));792		*cptr++ = '\n';793		*cptr = 0;794		pr_info("%s", line);795	}796	/* Next the control regs, which are single-byte, address mod 4 */797	while (i < 0x400) {798		cptr = line;799		cptr += sprintf(cptr, "%03x ", i);800		/* Print out 4 groups of 4 bytes */801		for (j = 0; j < 4; j++) {802			for (k = 0; k < 4; k++) {803				cptr += sprintf(cptr, "%02x ",804					tw_readb(i));805				i += 4;806			}807			*cptr++ = ' ';808		}809		*cptr++ = '\n';810		*cptr = 0;811		pr_info("%s", line);812	}813}814 815static int vidioc_log_status(struct file *file, void *priv)816{817	struct tw68_dev *dev = video_drvdata(file);818 819	tw68_dump_regs(dev);820	return v4l2_ctrl_log_status(file, priv);821}822 823#ifdef CONFIG_VIDEO_ADV_DEBUG824static int vidioc_g_register(struct file *file, void *priv,825			      struct v4l2_dbg_register *reg)826{827	struct tw68_dev *dev = video_drvdata(file);828 829	if (reg->size == 1)830		reg->val = tw_readb(reg->reg);831	else832		reg->val = tw_readl(reg->reg);833	return 0;834}835 836static int vidioc_s_register(struct file *file, void *priv,837				const struct v4l2_dbg_register *reg)838{839	struct tw68_dev *dev = video_drvdata(file);840 841	if (reg->size == 1)842		tw_writeb(reg->reg, reg->val);843	else844		tw_writel(reg->reg & 0xffff, reg->val);845	return 0;846}847#endif848 849static const struct v4l2_ctrl_ops tw68_ctrl_ops = {850	.s_ctrl = tw68_s_ctrl,851};852 853static const struct v4l2_file_operations video_fops = {854	.owner			= THIS_MODULE,855	.open			= v4l2_fh_open,856	.release		= vb2_fop_release,857	.read			= vb2_fop_read,858	.poll			= vb2_fop_poll,859	.mmap			= vb2_fop_mmap,860	.unlocked_ioctl		= video_ioctl2,861};862 863static const struct v4l2_ioctl_ops video_ioctl_ops = {864	.vidioc_querycap		= tw68_querycap,865	.vidioc_enum_fmt_vid_cap	= tw68_enum_fmt_vid_cap,866	.vidioc_reqbufs			= vb2_ioctl_reqbufs,867	.vidioc_create_bufs		= vb2_ioctl_create_bufs,868	.vidioc_querybuf		= vb2_ioctl_querybuf,869	.vidioc_qbuf			= vb2_ioctl_qbuf,870	.vidioc_dqbuf			= vb2_ioctl_dqbuf,871	.vidioc_s_std			= tw68_s_std,872	.vidioc_g_std			= tw68_g_std,873	.vidioc_enum_input		= tw68_enum_input,874	.vidioc_g_input			= tw68_g_input,875	.vidioc_s_input			= tw68_s_input,876	.vidioc_streamon		= vb2_ioctl_streamon,877	.vidioc_streamoff		= vb2_ioctl_streamoff,878	.vidioc_g_fmt_vid_cap		= tw68_g_fmt_vid_cap,879	.vidioc_try_fmt_vid_cap		= tw68_try_fmt_vid_cap,880	.vidioc_s_fmt_vid_cap		= tw68_s_fmt_vid_cap,881	.vidioc_log_status		= vidioc_log_status,882	.vidioc_subscribe_event		= v4l2_ctrl_subscribe_event,883	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,884#ifdef CONFIG_VIDEO_ADV_DEBUG885	.vidioc_g_register              = vidioc_g_register,886	.vidioc_s_register              = vidioc_s_register,887#endif888};889 890static const struct video_device tw68_video_template = {891	.name			= "tw68_video",892	.fops			= &video_fops,893	.ioctl_ops		= &video_ioctl_ops,894	.release		= video_device_release_empty,895	.tvnorms		= TW68_NORMS,896	.device_caps		= V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |897				  V4L2_CAP_STREAMING,898};899 900/* ------------------------------------------------------------------ */901/* exported stuff                                                     */902void tw68_set_tvnorm_hw(struct tw68_dev *dev)903{904	tw_andorb(TW68_SDT, 0x07, dev->tvnorm->format);905}906 907int tw68_video_init1(struct tw68_dev *dev)908{909	struct v4l2_ctrl_handler *hdl = &dev->hdl;910 911	v4l2_ctrl_handler_init(hdl, 6);912	v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops,913			V4L2_CID_BRIGHTNESS, -128, 127, 1, 20);914	v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops,915			V4L2_CID_CONTRAST, 0, 255, 1, 100);916	v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops,917			V4L2_CID_SATURATION, 0, 255, 1, 128);918	/* NTSC only */919	v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops,920			V4L2_CID_HUE, -128, 127, 1, 0);921	v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops,922			V4L2_CID_COLOR_KILLER, 0, 1, 1, 0);923	v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops,924			V4L2_CID_CHROMA_AGC, 0, 1, 1, 1);925	if (hdl->error) {926		v4l2_ctrl_handler_free(hdl);927		return hdl->error;928	}929	dev->v4l2_dev.ctrl_handler = hdl;930	v4l2_ctrl_handler_setup(hdl);931	return 0;932}933 934int tw68_video_init2(struct tw68_dev *dev, int video_nr)935{936	int ret;937 938	set_tvnorm(dev, &tvnorms[0]);939 940	dev->fmt      = format_by_fourcc(V4L2_PIX_FMT_BGR24);941	dev->width    = 720;942	dev->height   = 576;943	dev->field    = V4L2_FIELD_INTERLACED;944 945	INIT_LIST_HEAD(&dev->active);946	dev->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;947	dev->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;948	dev->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ | VB2_DMABUF;949	dev->vidq.ops = &tw68_video_qops;950	dev->vidq.mem_ops = &vb2_dma_sg_memops;951	dev->vidq.drv_priv = dev;952	dev->vidq.gfp_flags = __GFP_DMA32 | __GFP_KSWAPD_RECLAIM;953	dev->vidq.buf_struct_size = sizeof(struct tw68_buf);954	dev->vidq.lock = &dev->lock;955	dev->vidq.min_queued_buffers = 2;956	dev->vidq.dev = &dev->pci->dev;957	ret = vb2_queue_init(&dev->vidq);958	if (ret)959		return ret;960	dev->vdev = tw68_video_template;961	dev->vdev.v4l2_dev = &dev->v4l2_dev;962	dev->vdev.lock = &dev->lock;963	dev->vdev.queue = &dev->vidq;964	video_set_drvdata(&dev->vdev, dev);965	return video_register_device(&dev->vdev, VFL_TYPE_VIDEO, video_nr);966}967 968/*969 * tw68_irq_video_done970 */971void tw68_irq_video_done(struct tw68_dev *dev, unsigned long status)972{973	__u32 reg;974 975	/* reset interrupts handled by this routine */976	tw_writel(TW68_INTSTAT, status);977	/*978	 * Check most likely first979	 *980	 * DMAPI shows we have reached the end of the risc code981	 * for the current buffer.982	 */983	if (status & TW68_DMAPI) {984		struct tw68_buf *buf;985 986		spin_lock(&dev->slock);987		buf = list_entry(dev->active.next, struct tw68_buf, list);988		list_del(&buf->list);989		spin_unlock(&dev->slock);990		buf->vb.vb2_buf.timestamp = ktime_get_ns();991		buf->vb.field = dev->field;992		buf->vb.sequence = dev->seqnr++;993		vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);994		status &= ~(TW68_DMAPI);995		if (0 == status)996			return;997	}998	if (status & (TW68_VLOCK | TW68_HLOCK))999		dev_dbg(&dev->pci->dev, "Lost sync\n");1000	if (status & TW68_PABORT)1001		dev_err(&dev->pci->dev, "PABORT interrupt\n");1002	if (status & TW68_DMAPERR)1003		dev_err(&dev->pci->dev, "DMAPERR interrupt\n");1004	/*1005	 * On TW6800, FDMIS is apparently generated if video input is switched1006	 * during operation.  Therefore, it is not enabled for that chip.1007	 */1008	if (status & TW68_FDMIS)1009		dev_dbg(&dev->pci->dev, "FDMIS interrupt\n");1010	if (status & TW68_FFOF) {1011		/* probably a logic error */1012		reg = tw_readl(TW68_DMAC) & TW68_FIFO_EN;1013		tw_clearl(TW68_DMAC, TW68_FIFO_EN);1014		dev_dbg(&dev->pci->dev, "FFOF interrupt\n");1015		tw_setl(TW68_DMAC, reg);1016	}1017	if (status & TW68_FFERR)1018		dev_dbg(&dev->pci->dev, "FFERR interrupt\n");1019}1020