0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/init.h>
0009 #include <linux/list.h>
0010 #include <linux/module.h>
0011 #include <linux/kernel.h>
0012 #include <linux/slab.h>
0013 #include <linux/kmod.h>
0014 #include <linux/sound.h>
0015 #include <linux/interrupt.h>
0016 #include <linux/delay.h>
0017 #include <linux/dma-mapping.h>
0018 #include <linux/pm.h>
0019 #include <linux/pci_ids.h>
0020 #include <linux/jiffies.h>
0021 #include <asm/dma.h>
0022 #include <media/v4l2-dev.h>
0023
0024 #include "tw5864.h"
0025 #include "tw5864-reg.h"
0026
0027 MODULE_DESCRIPTION("V4L2 driver module for tw5864-based multimedia capture & encoding devices");
0028 MODULE_AUTHOR("Bluecherry Maintainers <maintainers@bluecherrydvr.com>");
0029 MODULE_AUTHOR("Andrey Utkin <andrey.utkin@corp.bluecherry.net>");
0030 MODULE_LICENSE("GPL");
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062 static unsigned int video_nr[] = {[0 ... (TW5864_INPUTS - 1)] = -1 };
0063
0064 module_param_array(video_nr, int, NULL, 0444);
0065 MODULE_PARM_DESC(video_nr, "video devices numbers array");
0066
0067
0068
0069
0070
0071
0072 static const struct pci_device_id tw5864_pci_tbl[] = {
0073 {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_TECHWELL_5864)},
0074 {0,}
0075 };
0076
0077 void tw5864_irqmask_apply(struct tw5864_dev *dev)
0078 {
0079 tw_writel(TW5864_INTR_ENABLE_L, dev->irqmask & 0xffff);
0080 tw_writel(TW5864_INTR_ENABLE_H, (dev->irqmask >> 16));
0081 }
0082
0083 static void tw5864_interrupts_disable(struct tw5864_dev *dev)
0084 {
0085 unsigned long flags;
0086
0087 spin_lock_irqsave(&dev->slock, flags);
0088 dev->irqmask = 0;
0089 tw5864_irqmask_apply(dev);
0090 spin_unlock_irqrestore(&dev->slock, flags);
0091 }
0092
0093 static void tw5864_timer_isr(struct tw5864_dev *dev);
0094 static void tw5864_h264_isr(struct tw5864_dev *dev);
0095
0096 static irqreturn_t tw5864_isr(int irq, void *dev_id)
0097 {
0098 struct tw5864_dev *dev = dev_id;
0099 u32 status;
0100
0101 status = tw_readl(TW5864_INTR_STATUS_L) |
0102 tw_readl(TW5864_INTR_STATUS_H) << 16;
0103 if (!status)
0104 return IRQ_NONE;
0105
0106 tw_writel(TW5864_INTR_CLR_L, 0xffff);
0107 tw_writel(TW5864_INTR_CLR_H, 0xffff);
0108
0109 if (status & TW5864_INTR_VLC_DONE)
0110 tw5864_h264_isr(dev);
0111
0112 if (status & TW5864_INTR_TIMER)
0113 tw5864_timer_isr(dev);
0114
0115 if (!(status & (TW5864_INTR_TIMER | TW5864_INTR_VLC_DONE))) {
0116 dev_dbg(&dev->pci->dev, "Unknown interrupt, status 0x%08X\n",
0117 status);
0118 }
0119
0120 return IRQ_HANDLED;
0121 }
0122
0123 static void tw5864_h264_isr(struct tw5864_dev *dev)
0124 {
0125 int channel = tw_readl(TW5864_DSP) & TW5864_DSP_ENC_CHN;
0126 struct tw5864_input *input = &dev->inputs[channel];
0127 int cur_frame_index, next_frame_index;
0128 struct tw5864_h264_frame *cur_frame, *next_frame;
0129 unsigned long flags;
0130
0131 spin_lock_irqsave(&dev->slock, flags);
0132
0133 cur_frame_index = dev->h264_buf_w_index;
0134 next_frame_index = (cur_frame_index + 1) % H264_BUF_CNT;
0135 cur_frame = &dev->h264_buf[cur_frame_index];
0136 next_frame = &dev->h264_buf[next_frame_index];
0137
0138 if (next_frame_index != dev->h264_buf_r_index) {
0139 cur_frame->vlc_len = tw_readl(TW5864_VLC_LENGTH) << 2;
0140 cur_frame->checksum = tw_readl(TW5864_VLC_CRC_REG);
0141 cur_frame->input = input;
0142 cur_frame->timestamp = ktime_get_ns();
0143 cur_frame->seqno = input->frame_seqno;
0144 cur_frame->gop_seqno = input->frame_gop_seqno;
0145
0146 dev->h264_buf_w_index = next_frame_index;
0147 tasklet_schedule(&dev->tasklet);
0148
0149 cur_frame = next_frame;
0150
0151 spin_lock(&input->slock);
0152 input->frame_seqno++;
0153 input->frame_gop_seqno++;
0154 if (input->frame_gop_seqno >= input->gop)
0155 input->frame_gop_seqno = 0;
0156 spin_unlock(&input->slock);
0157 } else {
0158 dev_err(&dev->pci->dev,
0159 "Skipped frame on input %d because all buffers busy\n",
0160 channel);
0161 }
0162
0163 dev->encoder_busy = 0;
0164
0165 spin_unlock_irqrestore(&dev->slock, flags);
0166
0167 tw_writel(TW5864_VLC_STREAM_BASE_ADDR, cur_frame->vlc.dma_addr);
0168 tw_writel(TW5864_MV_STREAM_BASE_ADDR, cur_frame->mv.dma_addr);
0169
0170
0171 tw_writel(TW5864_VLC_DSP_INTR, 0x00000001);
0172 tw_writel(TW5864_PCI_INTR_STATUS, TW5864_VLC_DONE_INTR);
0173 }
0174
0175 static void tw5864_input_deadline_update(struct tw5864_input *input)
0176 {
0177 input->new_frame_deadline = jiffies + msecs_to_jiffies(1000);
0178 }
0179
0180 static void tw5864_timer_isr(struct tw5864_dev *dev)
0181 {
0182 unsigned long flags;
0183 int i;
0184 int encoder_busy;
0185
0186
0187 tw_writel(TW5864_PCI_INTR_STATUS, TW5864_TIMER_INTR);
0188
0189 spin_lock_irqsave(&dev->slock, flags);
0190 encoder_busy = dev->encoder_busy;
0191 spin_unlock_irqrestore(&dev->slock, flags);
0192
0193 if (encoder_busy)
0194 return;
0195
0196
0197
0198
0199
0200 for (i = 0; i < TW5864_INPUTS; i++) {
0201 int next_input = (i + dev->next_input) % TW5864_INPUTS;
0202 struct tw5864_input *input = &dev->inputs[next_input];
0203 int raw_buf_id;
0204
0205 spin_lock_irqsave(&input->slock, flags);
0206 if (!input->enabled)
0207 goto next;
0208
0209
0210 raw_buf_id = tw_mask_shift_readl(TW5864_SENIF_ORG_FRM_PTR1, 0x3,
0211 2 * input->nr);
0212
0213 if (input->buf_id != raw_buf_id) {
0214 input->buf_id = raw_buf_id;
0215 tw5864_input_deadline_update(input);
0216 spin_unlock_irqrestore(&input->slock, flags);
0217
0218 spin_lock_irqsave(&dev->slock, flags);
0219 dev->encoder_busy = 1;
0220 dev->next_input = (next_input + 1) % TW5864_INPUTS;
0221 spin_unlock_irqrestore(&dev->slock, flags);
0222
0223 tw5864_request_encoded_frame(input);
0224 break;
0225 }
0226
0227
0228 if (time_is_after_jiffies(input->new_frame_deadline)) {
0229
0230 tw_mask_shift_writel(TW5864_ENC_BUF_PTR_REC1, 0x3,
0231 2 * input->nr, input->buf_id + 3);
0232 tw5864_input_deadline_update(input);
0233 }
0234 next:
0235 spin_unlock_irqrestore(&input->slock, flags);
0236 }
0237 }
0238
0239 static int tw5864_initdev(struct pci_dev *pci_dev,
0240 const struct pci_device_id *pci_id)
0241 {
0242 struct tw5864_dev *dev;
0243 int err;
0244
0245 dev = devm_kzalloc(&pci_dev->dev, sizeof(*dev), GFP_KERNEL);
0246 if (!dev)
0247 return -ENOMEM;
0248
0249 snprintf(dev->name, sizeof(dev->name), "tw5864:%s", pci_name(pci_dev));
0250
0251 err = v4l2_device_register(&pci_dev->dev, &dev->v4l2_dev);
0252 if (err)
0253 return err;
0254
0255
0256 dev->pci = pci_dev;
0257 err = pcim_enable_device(pci_dev);
0258 if (err) {
0259 dev_err(&dev->pci->dev, "pcim_enable_device() failed\n");
0260 goto unreg_v4l2;
0261 }
0262
0263 pci_set_master(pci_dev);
0264
0265 err = dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(32));
0266 if (err) {
0267 dev_err(&dev->pci->dev, "32 bit PCI DMA is not supported\n");
0268 goto unreg_v4l2;
0269 }
0270
0271
0272 err = pcim_iomap_regions(pci_dev, BIT(0), dev->name);
0273 if (err) {
0274 dev_err(&dev->pci->dev, "Cannot request regions for MMIO\n");
0275 goto unreg_v4l2;
0276 }
0277 dev->mmio = pcim_iomap_table(pci_dev)[0];
0278
0279 spin_lock_init(&dev->slock);
0280
0281 dev_info(&pci_dev->dev, "TW5864 hardware version: %04x\n",
0282 tw_readl(TW5864_HW_VERSION));
0283 dev_info(&pci_dev->dev, "TW5864 H.264 core version: %04x:%04x\n",
0284 tw_readl(TW5864_H264REV),
0285 tw_readl(TW5864_UNDECLARED_H264REV_PART2));
0286
0287 err = tw5864_video_init(dev, video_nr);
0288 if (err)
0289 goto unreg_v4l2;
0290
0291
0292 err = devm_request_irq(&pci_dev->dev, pci_dev->irq, tw5864_isr,
0293 IRQF_SHARED, "tw5864", dev);
0294 if (err < 0) {
0295 dev_err(&dev->pci->dev, "can't get IRQ %d\n", pci_dev->irq);
0296 goto fini_video;
0297 }
0298
0299 dev_info(&pci_dev->dev, "Note: there are known video quality issues. For details\n");
0300 dev_info(&pci_dev->dev, "see the comment in drivers/media/pci/tw5864/tw5864-core.c.\n");
0301
0302 return 0;
0303
0304 fini_video:
0305 tw5864_video_fini(dev);
0306 unreg_v4l2:
0307 v4l2_device_unregister(&dev->v4l2_dev);
0308 return err;
0309 }
0310
0311 static void tw5864_finidev(struct pci_dev *pci_dev)
0312 {
0313 struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
0314 struct tw5864_dev *dev =
0315 container_of(v4l2_dev, struct tw5864_dev, v4l2_dev);
0316
0317
0318 tw5864_interrupts_disable(dev);
0319
0320
0321 tw5864_video_fini(dev);
0322
0323 v4l2_device_unregister(&dev->v4l2_dev);
0324 }
0325
0326 static struct pci_driver tw5864_pci_driver = {
0327 .name = "tw5864",
0328 .id_table = tw5864_pci_tbl,
0329 .probe = tw5864_initdev,
0330 .remove = tw5864_finidev,
0331 };
0332
0333 module_pci_driver(tw5864_pci_driver);