1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * TW5864 driver - core functions
5 * Copyright (C) 2016 Bluecherry, LLC <maintainers@bluecherrydvr.com>
8 #include <linux/init.h>
9 #include <linux/list.h>
10 #include <linux/module.h>
11 #include <linux/kernel.h>
12 #include <linux/slab.h>
13 #include <linux/kmod.h>
14 #include <linux/sound.h>
15 #include <linux/interrupt.h>
16 #include <linux/delay.h>
17 #include <linux/dma-mapping.h>
19 #include <linux/pci_ids.h>
20 #include <linux/jiffies.h>
22 #include <media/v4l2-dev.h>
25 #include "tw5864-reg.h"
27 MODULE_DESCRIPTION("V4L2 driver module for tw5864-based multimedia capture & encoding devices");
28 MODULE_AUTHOR("Bluecherry Maintainers <maintainers@bluecherrydvr.com>");
29 MODULE_AUTHOR("Andrey Utkin <andrey.utkin@corp.bluecherry.net>");
30 MODULE_LICENSE("GPL");
33 * BEWARE OF KNOWN ISSUES WITH VIDEO QUALITY
35 * This driver was developed by Bluecherry LLC by deducing behaviour of
36 * original manufacturer's driver, from both source code and execution traces.
37 * It is known that there are some artifacts on output video with this driver:
38 * - on all known hardware samples: random pixels of wrong color (mostly
39 * white, red or blue) appearing and disappearing on sequences of P-frames;
40 * - on some hardware samples (known with H.264 core version e006:2800):
41 * total madness on P-frames: blocks of wrong luminance; blocks of wrong
42 * colors "creeping" across the picture.
43 * There is a workaround for both issues: avoid P-frames by setting GOP size
44 * to 1. To do that, run this command on device files created by this driver:
46 * v4l2-ctl --device /dev/videoX --set-ctrl=video_gop_size=1
48 * These issues are not decoding errors; all produced H.264 streams are decoded
49 * properly. Streams without P-frames don't have these artifacts so it's not
50 * analog-to-digital conversion issues nor internal memory errors; we conclude
51 * it's internal H.264 encoder issues.
52 * We cannot even check the original driver's behaviour because it has never
53 * worked properly at all in our development environment. So these issues may
54 * be actually related to firmware or hardware. However it may be that there's
55 * just some more register settings missing in the driver which would please
57 * Manufacturer didn't help much on our inquiries, but feel free to disturb
58 * again the support of Intersil (owner of former Techwell).
61 /* take first free /dev/videoX indexes by default */
62 static unsigned int video_nr
[] = {[0 ... (TW5864_INPUTS
- 1)] = -1 };
64 module_param_array(video_nr
, int, NULL
, 0444);
65 MODULE_PARM_DESC(video_nr
, "video devices numbers array");
68 * Please add any new PCI IDs to: http://pci-ids.ucw.cz. This keeps
69 * the PCI ID database up to date. Note that the entries must be
70 * added under vendor 0x1797 (Techwell Inc.) as subsystem IDs.
72 static const struct pci_device_id tw5864_pci_tbl
[] = {
73 {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL
, PCI_DEVICE_ID_TECHWELL_5864
)},
77 void tw5864_irqmask_apply(struct tw5864_dev
*dev
)
79 tw_writel(TW5864_INTR_ENABLE_L
, dev
->irqmask
& 0xffff);
80 tw_writel(TW5864_INTR_ENABLE_H
, (dev
->irqmask
>> 16));
83 static void tw5864_interrupts_disable(struct tw5864_dev
*dev
)
87 spin_lock_irqsave(&dev
->slock
, flags
);
89 tw5864_irqmask_apply(dev
);
90 spin_unlock_irqrestore(&dev
->slock
, flags
);
93 static void tw5864_timer_isr(struct tw5864_dev
*dev
);
94 static void tw5864_h264_isr(struct tw5864_dev
*dev
);
96 static irqreturn_t
tw5864_isr(int irq
, void *dev_id
)
98 struct tw5864_dev
*dev
= dev_id
;
101 status
= tw_readl(TW5864_INTR_STATUS_L
) |
102 tw_readl(TW5864_INTR_STATUS_H
) << 16;
106 tw_writel(TW5864_INTR_CLR_L
, 0xffff);
107 tw_writel(TW5864_INTR_CLR_H
, 0xffff);
109 if (status
& TW5864_INTR_VLC_DONE
)
110 tw5864_h264_isr(dev
);
112 if (status
& TW5864_INTR_TIMER
)
113 tw5864_timer_isr(dev
);
115 if (!(status
& (TW5864_INTR_TIMER
| TW5864_INTR_VLC_DONE
))) {
116 dev_dbg(&dev
->pci
->dev
, "Unknown interrupt, status 0x%08X\n",
123 static void tw5864_h264_isr(struct tw5864_dev
*dev
)
125 int channel
= tw_readl(TW5864_DSP
) & TW5864_DSP_ENC_CHN
;
126 struct tw5864_input
*input
= &dev
->inputs
[channel
];
127 int cur_frame_index
, next_frame_index
;
128 struct tw5864_h264_frame
*cur_frame
, *next_frame
;
131 spin_lock_irqsave(&dev
->slock
, flags
);
133 cur_frame_index
= dev
->h264_buf_w_index
;
134 next_frame_index
= (cur_frame_index
+ 1) % H264_BUF_CNT
;
135 cur_frame
= &dev
->h264_buf
[cur_frame_index
];
136 next_frame
= &dev
->h264_buf
[next_frame_index
];
138 if (next_frame_index
!= dev
->h264_buf_r_index
) {
139 cur_frame
->vlc_len
= tw_readl(TW5864_VLC_LENGTH
) << 2;
140 cur_frame
->checksum
= tw_readl(TW5864_VLC_CRC_REG
);
141 cur_frame
->input
= input
;
142 cur_frame
->timestamp
= ktime_get_ns();
143 cur_frame
->seqno
= input
->frame_seqno
;
144 cur_frame
->gop_seqno
= input
->frame_gop_seqno
;
146 dev
->h264_buf_w_index
= next_frame_index
;
147 tasklet_schedule(&dev
->tasklet
);
149 cur_frame
= next_frame
;
151 spin_lock(&input
->slock
);
152 input
->frame_seqno
++;
153 input
->frame_gop_seqno
++;
154 if (input
->frame_gop_seqno
>= input
->gop
)
155 input
->frame_gop_seqno
= 0;
156 spin_unlock(&input
->slock
);
158 dev_err(&dev
->pci
->dev
,
159 "Skipped frame on input %d because all buffers busy\n",
163 dev
->encoder_busy
= 0;
165 spin_unlock_irqrestore(&dev
->slock
, flags
);
167 tw_writel(TW5864_VLC_STREAM_BASE_ADDR
, cur_frame
->vlc
.dma_addr
);
168 tw_writel(TW5864_MV_STREAM_BASE_ADDR
, cur_frame
->mv
.dma_addr
);
170 /* Additional ack for this interrupt */
171 tw_writel(TW5864_VLC_DSP_INTR
, 0x00000001);
172 tw_writel(TW5864_PCI_INTR_STATUS
, TW5864_VLC_DONE_INTR
);
175 static void tw5864_input_deadline_update(struct tw5864_input
*input
)
177 input
->new_frame_deadline
= jiffies
+ msecs_to_jiffies(1000);
180 static void tw5864_timer_isr(struct tw5864_dev
*dev
)
186 /* Additional ack for this interrupt */
187 tw_writel(TW5864_PCI_INTR_STATUS
, TW5864_TIMER_INTR
);
189 spin_lock_irqsave(&dev
->slock
, flags
);
190 encoder_busy
= dev
->encoder_busy
;
191 spin_unlock_irqrestore(&dev
->slock
, flags
);
197 * Traversing inputs in round-robin fashion, starting from next to the
200 for (i
= 0; i
< TW5864_INPUTS
; i
++) {
201 int next_input
= (i
+ dev
->next_input
) % TW5864_INPUTS
;
202 struct tw5864_input
*input
= &dev
->inputs
[next_input
];
203 int raw_buf_id
; /* id of internal buf with last raw frame */
205 spin_lock_irqsave(&input
->slock
, flags
);
209 /* Check if new raw frame is available */
210 raw_buf_id
= tw_mask_shift_readl(TW5864_SENIF_ORG_FRM_PTR1
, 0x3,
213 if (input
->buf_id
!= raw_buf_id
) {
214 input
->buf_id
= raw_buf_id
;
215 tw5864_input_deadline_update(input
);
216 spin_unlock_irqrestore(&input
->slock
, flags
);
218 spin_lock_irqsave(&dev
->slock
, flags
);
219 dev
->encoder_busy
= 1;
220 dev
->next_input
= (next_input
+ 1) % TW5864_INPUTS
;
221 spin_unlock_irqrestore(&dev
->slock
, flags
);
223 tw5864_request_encoded_frame(input
);
227 /* No new raw frame; check if channel is stuck */
228 if (time_is_after_jiffies(input
->new_frame_deadline
)) {
229 /* If stuck, request new raw frames again */
230 tw_mask_shift_writel(TW5864_ENC_BUF_PTR_REC1
, 0x3,
231 2 * input
->nr
, input
->buf_id
+ 3);
232 tw5864_input_deadline_update(input
);
235 spin_unlock_irqrestore(&input
->slock
, flags
);
239 static int tw5864_initdev(struct pci_dev
*pci_dev
,
240 const struct pci_device_id
*pci_id
)
242 struct tw5864_dev
*dev
;
245 dev
= devm_kzalloc(&pci_dev
->dev
, sizeof(*dev
), GFP_KERNEL
);
249 snprintf(dev
->name
, sizeof(dev
->name
), "tw5864:%s", pci_name(pci_dev
));
251 err
= v4l2_device_register(&pci_dev
->dev
, &dev
->v4l2_dev
);
257 err
= pci_enable_device(pci_dev
);
259 dev_err(&dev
->pci
->dev
, "pci_enable_device() failed\n");
263 pci_set_master(pci_dev
);
265 err
= pci_set_dma_mask(pci_dev
, DMA_BIT_MASK(32));
267 dev_err(&dev
->pci
->dev
, "32 bit PCI DMA is not supported\n");
272 err
= pci_request_regions(pci_dev
, dev
->name
);
274 dev_err(&dev
->pci
->dev
, "Cannot request regions for MMIO\n");
277 dev
->mmio
= pci_ioremap_bar(pci_dev
, 0);
280 dev_err(&dev
->pci
->dev
, "can't ioremap() MMIO memory\n");
284 spin_lock_init(&dev
->slock
);
286 dev_info(&pci_dev
->dev
, "TW5864 hardware version: %04x\n",
287 tw_readl(TW5864_HW_VERSION
));
288 dev_info(&pci_dev
->dev
, "TW5864 H.264 core version: %04x:%04x\n",
289 tw_readl(TW5864_H264REV
),
290 tw_readl(TW5864_UNDECLARED_H264REV_PART2
));
292 err
= tw5864_video_init(dev
, video_nr
);
297 err
= devm_request_irq(&pci_dev
->dev
, pci_dev
->irq
, tw5864_isr
,
298 IRQF_SHARED
, "tw5864", dev
);
300 dev_err(&dev
->pci
->dev
, "can't get IRQ %d\n", pci_dev
->irq
);
304 dev_info(&pci_dev
->dev
, "Note: there are known video quality issues. For details\n");
305 dev_info(&pci_dev
->dev
, "see the comment in drivers/media/pci/tw5864/tw5864-core.c.\n");
310 tw5864_video_fini(dev
);
314 pci_release_regions(pci_dev
);
316 pci_disable_device(pci_dev
);
318 v4l2_device_unregister(&dev
->v4l2_dev
);
322 static void tw5864_finidev(struct pci_dev
*pci_dev
)
324 struct v4l2_device
*v4l2_dev
= pci_get_drvdata(pci_dev
);
325 struct tw5864_dev
*dev
=
326 container_of(v4l2_dev
, struct tw5864_dev
, v4l2_dev
);
328 /* shutdown subsystems */
329 tw5864_interrupts_disable(dev
);
332 tw5864_video_fini(dev
);
334 /* release resources */
336 release_mem_region(pci_resource_start(pci_dev
, 0),
337 pci_resource_len(pci_dev
, 0));
339 v4l2_device_unregister(&dev
->v4l2_dev
);
340 devm_kfree(&pci_dev
->dev
, dev
);
343 static struct pci_driver tw5864_pci_driver
= {
345 .id_table
= tw5864_pci_tbl
,
346 .probe
= tw5864_initdev
,
347 .remove
= tw5864_finidev
,
350 module_pci_driver(tw5864_pci_driver
);