]>
Commit | Line | Data |
---|---|---|
704a84cc EG |
1 | /* |
2 | * Copyright (C) 2015 VanguardiaSur - www.vanguardiasur.com.ar | |
3 | * | |
4 | * Based on original driver by Krzysztof Ha?asa: | |
5 | * Copyright (C) 2015 Industrial Research Institute for Automation | |
6 | * and Measurements PIAP | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify it | |
9 | * under the terms of version 2 of the GNU General Public License | |
10 | * as published by the Free Software Foundation. | |
11 | * | |
12 | * Notes | |
13 | * ----- | |
14 | * | |
15 | * 1. Under stress-testing, it has been observed that the PCIe link | |
16 | * goes down, without reason. Therefore, the driver takes special care | |
17 | * to allow device hot-unplugging. | |
18 | * | |
19 | * 2. TW686X devices are capable of setting a few different DMA modes, | |
20 | * including: scatter-gather, field and frame modes. However, | |
21 | * under stress testings it has been found that the machine can | |
22 | * freeze completely if DMA registers are programmed while streaming | |
23 | * is active. | |
f8afaa8d EG |
24 | * |
25 | * Therefore, driver implements a dma_mode called 'memcpy' which | |
26 | * avoids cycling the DMA buffers, and insteads allocates extra DMA buffers | |
27 | * and then copies into vmalloc'ed user buffers. | |
28 | * | |
29 | * In addition to this, when streaming is on, the driver tries to access | |
30 | * hardware registers as infrequently as possible. This is done by using | |
31 | * a timer to limit the rate at which DMA is reset on DMA channels error. | |
704a84cc EG |
32 | */ |
33 | ||
34 | #include <linux/init.h> | |
35 | #include <linux/interrupt.h> | |
36 | #include <linux/delay.h> | |
37 | #include <linux/kernel.h> | |
38 | #include <linux/module.h> | |
39 | #include <linux/pci_ids.h> | |
40 | #include <linux/slab.h> | |
41 | #include <linux/timer.h> | |
42 | ||
43 | #include "tw686x.h" | |
44 | #include "tw686x-regs.h" | |
45 | ||
46 | /* | |
47 | * This module parameter allows to control the DMA_TIMER_INTERVAL value. | |
48 | * The DMA_TIMER_INTERVAL register controls the minimum DMA interrupt | |
49 | * time span (iow, the maximum DMA interrupt rate) thus allowing for | |
50 | * IRQ coalescing. | |
51 | * | |
52 | * The chip datasheet does not mention a time unit for this value, so | |
53 | * users wanting fine-grain control over the interrupt rate should | |
54 | * determine the desired value through testing. | |
55 | */ | |
56 | static u32 dma_interval = 0x00098968; | |
57 | module_param(dma_interval, int, 0444); | |
58 | MODULE_PARM_DESC(dma_interval, "Minimum time span for DMA interrupting host"); | |
59 | ||
f8afaa8d EG |
60 | static unsigned int dma_mode = TW686X_DMA_MODE_MEMCPY; |
61 | static const char *dma_mode_name(unsigned int mode) | |
62 | { | |
63 | switch (mode) { | |
64 | case TW686X_DMA_MODE_MEMCPY: | |
65 | return "memcpy"; | |
11a16974 EG |
66 | case TW686X_DMA_MODE_CONTIG: |
67 | return "contig"; | |
34e2acc8 EG |
68 | case TW686X_DMA_MODE_SG: |
69 | return "sg"; | |
f8afaa8d EG |
70 | default: |
71 | return "unknown"; | |
72 | } | |
73 | } | |
74 | ||
75 | static int tw686x_dma_mode_get(char *buffer, struct kernel_param *kp) | |
76 | { | |
92fbeb40 | 77 | return sprintf(buffer, "%s", dma_mode_name(dma_mode)); |
f8afaa8d EG |
78 | } |
79 | ||
80 | static int tw686x_dma_mode_set(const char *val, struct kernel_param *kp) | |
81 | { | |
82 | if (!strcasecmp(val, dma_mode_name(TW686X_DMA_MODE_MEMCPY))) | |
83 | dma_mode = TW686X_DMA_MODE_MEMCPY; | |
11a16974 EG |
84 | else if (!strcasecmp(val, dma_mode_name(TW686X_DMA_MODE_CONTIG))) |
85 | dma_mode = TW686X_DMA_MODE_CONTIG; | |
34e2acc8 EG |
86 | else if (!strcasecmp(val, dma_mode_name(TW686X_DMA_MODE_SG))) |
87 | dma_mode = TW686X_DMA_MODE_SG; | |
f8afaa8d EG |
88 | else |
89 | return -EINVAL; | |
90 | return 0; | |
91 | } | |
92 | module_param_call(dma_mode, tw686x_dma_mode_set, tw686x_dma_mode_get, | |
93 | &dma_mode, S_IRUGO|S_IWUSR); | |
c2b40111 | 94 | MODULE_PARM_DESC(dma_mode, "DMA operation mode (memcpy/contig/sg, default=memcpy)"); |
f8afaa8d | 95 | |
704a84cc EG |
96 | void tw686x_disable_channel(struct tw686x_dev *dev, unsigned int channel) |
97 | { | |
98 | u32 dma_en = reg_read(dev, DMA_CHANNEL_ENABLE); | |
99 | u32 dma_cmd = reg_read(dev, DMA_CMD); | |
100 | ||
101 | dma_en &= ~BIT(channel); | |
102 | dma_cmd &= ~BIT(channel); | |
103 | ||
104 | /* Must remove it from pending too */ | |
105 | dev->pending_dma_en &= ~BIT(channel); | |
106 | dev->pending_dma_cmd &= ~BIT(channel); | |
107 | ||
108 | /* Stop DMA if no channels are enabled */ | |
109 | if (!dma_en) | |
110 | dma_cmd = 0; | |
111 | reg_write(dev, DMA_CHANNEL_ENABLE, dma_en); | |
112 | reg_write(dev, DMA_CMD, dma_cmd); | |
113 | } | |
114 | ||
115 | void tw686x_enable_channel(struct tw686x_dev *dev, unsigned int channel) | |
116 | { | |
117 | u32 dma_en = reg_read(dev, DMA_CHANNEL_ENABLE); | |
118 | u32 dma_cmd = reg_read(dev, DMA_CMD); | |
119 | ||
120 | dev->pending_dma_en |= dma_en | BIT(channel); | |
121 | dev->pending_dma_cmd |= dma_cmd | DMA_CMD_ENABLE | BIT(channel); | |
122 | } | |
123 | ||
124 | /* | |
125 | * The purpose of this awful hack is to avoid enabling the DMA | |
126 | * channels "too fast" which makes some TW686x devices very | |
127 | * angry and freeze the CPU (see note 1). | |
128 | */ | |
129 | static void tw686x_dma_delay(unsigned long data) | |
130 | { | |
131 | struct tw686x_dev *dev = (struct tw686x_dev *)data; | |
132 | unsigned long flags; | |
133 | ||
134 | spin_lock_irqsave(&dev->lock, flags); | |
135 | ||
136 | reg_write(dev, DMA_CHANNEL_ENABLE, dev->pending_dma_en); | |
137 | reg_write(dev, DMA_CMD, dev->pending_dma_cmd); | |
138 | dev->pending_dma_en = 0; | |
139 | dev->pending_dma_cmd = 0; | |
140 | ||
141 | spin_unlock_irqrestore(&dev->lock, flags); | |
142 | } | |
143 | ||
144 | static void tw686x_reset_channels(struct tw686x_dev *dev, unsigned int ch_mask) | |
145 | { | |
146 | u32 dma_en, dma_cmd; | |
147 | ||
148 | dma_en = reg_read(dev, DMA_CHANNEL_ENABLE); | |
149 | dma_cmd = reg_read(dev, DMA_CMD); | |
150 | ||
151 | /* | |
152 | * Save pending register status, the timer will | |
153 | * restore them. | |
154 | */ | |
155 | dev->pending_dma_en |= dma_en; | |
156 | dev->pending_dma_cmd |= dma_cmd; | |
157 | ||
158 | /* Disable the reset channels */ | |
159 | reg_write(dev, DMA_CHANNEL_ENABLE, dma_en & ~ch_mask); | |
160 | ||
161 | if ((dma_en & ~ch_mask) == 0) { | |
162 | dev_dbg(&dev->pci_dev->dev, "reset: stopping DMA\n"); | |
163 | dma_cmd &= ~DMA_CMD_ENABLE; | |
164 | } | |
165 | reg_write(dev, DMA_CMD, dma_cmd & ~ch_mask); | |
166 | } | |
167 | ||
168 | static irqreturn_t tw686x_irq(int irq, void *dev_id) | |
169 | { | |
170 | struct tw686x_dev *dev = (struct tw686x_dev *)dev_id; | |
171 | unsigned int video_requests, audio_requests, reset_ch; | |
172 | u32 fifo_status, fifo_signal, fifo_ov, fifo_bad, fifo_errors; | |
173 | u32 int_status, dma_en, video_en, pb_status; | |
174 | unsigned long flags; | |
175 | ||
176 | int_status = reg_read(dev, INT_STATUS); /* cleared on read */ | |
177 | fifo_status = reg_read(dev, VIDEO_FIFO_STATUS); | |
178 | ||
179 | /* INT_STATUS does not include FIFO_STATUS errors! */ | |
180 | if (!int_status && !TW686X_FIFO_ERROR(fifo_status)) | |
181 | return IRQ_NONE; | |
182 | ||
183 | if (int_status & INT_STATUS_DMA_TOUT) { | |
184 | dev_dbg(&dev->pci_dev->dev, | |
185 | "DMA timeout. Resetting DMA for all channels\n"); | |
186 | reset_ch = ~0; | |
187 | goto reset_channels; | |
188 | } | |
189 | ||
190 | spin_lock_irqsave(&dev->lock, flags); | |
191 | dma_en = reg_read(dev, DMA_CHANNEL_ENABLE); | |
192 | spin_unlock_irqrestore(&dev->lock, flags); | |
193 | ||
194 | video_en = dma_en & 0xff; | |
195 | fifo_signal = ~(fifo_status & 0xff) & video_en; | |
196 | fifo_ov = fifo_status >> 24; | |
197 | fifo_bad = fifo_status >> 16; | |
198 | ||
199 | /* Mask of channels with signal and FIFO errors */ | |
200 | fifo_errors = fifo_signal & (fifo_ov | fifo_bad); | |
201 | ||
202 | reset_ch = 0; | |
203 | pb_status = reg_read(dev, PB_STATUS); | |
204 | ||
205 | /* Coalesce video frame/error events */ | |
206 | video_requests = (int_status & video_en) | fifo_errors; | |
207 | audio_requests = (int_status & dma_en) >> 8; | |
208 | ||
209 | if (video_requests) | |
210 | tw686x_video_irq(dev, video_requests, pb_status, | |
211 | fifo_status, &reset_ch); | |
212 | if (audio_requests) | |
213 | tw686x_audio_irq(dev, audio_requests, pb_status); | |
214 | ||
215 | reset_channels: | |
216 | if (reset_ch) { | |
217 | spin_lock_irqsave(&dev->lock, flags); | |
218 | tw686x_reset_channels(dev, reset_ch); | |
219 | spin_unlock_irqrestore(&dev->lock, flags); | |
220 | mod_timer(&dev->dma_delay_timer, | |
221 | jiffies + msecs_to_jiffies(100)); | |
222 | } | |
223 | ||
224 | return IRQ_HANDLED; | |
225 | } | |
226 | ||
227 | static void tw686x_dev_release(struct v4l2_device *v4l2_dev) | |
228 | { | |
229 | struct tw686x_dev *dev = container_of(v4l2_dev, struct tw686x_dev, | |
230 | v4l2_dev); | |
231 | unsigned int ch; | |
232 | ||
233 | for (ch = 0; ch < max_channels(dev); ch++) | |
234 | v4l2_ctrl_handler_free(&dev->video_channels[ch].ctrl_handler); | |
235 | ||
236 | v4l2_device_unregister(&dev->v4l2_dev); | |
237 | ||
238 | kfree(dev->audio_channels); | |
239 | kfree(dev->video_channels); | |
240 | kfree(dev); | |
241 | } | |
242 | ||
243 | static int tw686x_probe(struct pci_dev *pci_dev, | |
244 | const struct pci_device_id *pci_id) | |
245 | { | |
246 | struct tw686x_dev *dev; | |
247 | int err; | |
248 | ||
249 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | |
250 | if (!dev) | |
251 | return -ENOMEM; | |
252 | dev->type = pci_id->driver_data; | |
f8afaa8d | 253 | dev->dma_mode = dma_mode; |
704a84cc EG |
254 | sprintf(dev->name, "tw%04X", pci_dev->device); |
255 | ||
256 | dev->video_channels = kcalloc(max_channels(dev), | |
257 | sizeof(*dev->video_channels), GFP_KERNEL); | |
258 | if (!dev->video_channels) { | |
259 | err = -ENOMEM; | |
260 | goto free_dev; | |
261 | } | |
262 | ||
263 | dev->audio_channels = kcalloc(max_channels(dev), | |
264 | sizeof(*dev->audio_channels), GFP_KERNEL); | |
265 | if (!dev->audio_channels) { | |
266 | err = -ENOMEM; | |
267 | goto free_video; | |
268 | } | |
269 | ||
f8afaa8d | 270 | pr_info("%s: PCI %s, IRQ %d, MMIO 0x%lx (%s mode)\n", dev->name, |
704a84cc | 271 | pci_name(pci_dev), pci_dev->irq, |
f8afaa8d EG |
272 | (unsigned long)pci_resource_start(pci_dev, 0), |
273 | dma_mode_name(dma_mode)); | |
704a84cc EG |
274 | |
275 | dev->pci_dev = pci_dev; | |
276 | if (pci_enable_device(pci_dev)) { | |
277 | err = -EIO; | |
278 | goto free_audio; | |
279 | } | |
280 | ||
281 | pci_set_master(pci_dev); | |
282 | err = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32)); | |
283 | if (err) { | |
284 | dev_err(&pci_dev->dev, "32-bit PCI DMA not supported\n"); | |
285 | err = -EIO; | |
286 | goto disable_pci; | |
287 | } | |
288 | ||
289 | err = pci_request_regions(pci_dev, dev->name); | |
290 | if (err) { | |
291 | dev_err(&pci_dev->dev, "unable to request PCI region\n"); | |
292 | goto disable_pci; | |
293 | } | |
294 | ||
295 | dev->mmio = pci_ioremap_bar(pci_dev, 0); | |
296 | if (!dev->mmio) { | |
297 | dev_err(&pci_dev->dev, "unable to remap PCI region\n"); | |
298 | err = -ENOMEM; | |
299 | goto free_region; | |
300 | } | |
301 | ||
302 | /* Reset all subsystems */ | |
303 | reg_write(dev, SYS_SOFT_RST, 0x0f); | |
304 | mdelay(1); | |
305 | ||
306 | reg_write(dev, SRST[0], 0x3f); | |
307 | if (max_channels(dev) > 4) | |
308 | reg_write(dev, SRST[1], 0x3f); | |
309 | ||
310 | /* Disable the DMA engine */ | |
311 | reg_write(dev, DMA_CMD, 0); | |
312 | reg_write(dev, DMA_CHANNEL_ENABLE, 0); | |
313 | ||
314 | /* Enable DMA FIFO overflow and pointer check */ | |
315 | reg_write(dev, DMA_CONFIG, 0xffffff04); | |
316 | reg_write(dev, DMA_CHANNEL_TIMEOUT, 0x140c8584); | |
317 | reg_write(dev, DMA_TIMER_INTERVAL, dma_interval); | |
318 | ||
319 | spin_lock_init(&dev->lock); | |
320 | ||
321 | err = request_irq(pci_dev->irq, tw686x_irq, IRQF_SHARED, | |
322 | dev->name, dev); | |
323 | if (err < 0) { | |
324 | dev_err(&pci_dev->dev, "unable to request interrupt\n"); | |
325 | goto iounmap; | |
326 | } | |
327 | ||
328 | setup_timer(&dev->dma_delay_timer, | |
329 | tw686x_dma_delay, (unsigned long) dev); | |
330 | ||
331 | /* | |
332 | * This must be set right before initializing v4l2_dev. | |
333 | * It's used to release resources after the last handle | |
334 | * held is released. | |
335 | */ | |
336 | dev->v4l2_dev.release = tw686x_dev_release; | |
337 | err = tw686x_video_init(dev); | |
338 | if (err) { | |
339 | dev_err(&pci_dev->dev, "can't register video\n"); | |
340 | goto free_irq; | |
341 | } | |
342 | ||
343 | err = tw686x_audio_init(dev); | |
344 | if (err) | |
345 | dev_warn(&pci_dev->dev, "can't register audio\n"); | |
346 | ||
347 | pci_set_drvdata(pci_dev, dev); | |
348 | return 0; | |
349 | ||
350 | free_irq: | |
351 | free_irq(pci_dev->irq, dev); | |
352 | iounmap: | |
353 | pci_iounmap(pci_dev, dev->mmio); | |
354 | free_region: | |
355 | pci_release_regions(pci_dev); | |
356 | disable_pci: | |
357 | pci_disable_device(pci_dev); | |
358 | free_audio: | |
359 | kfree(dev->audio_channels); | |
360 | free_video: | |
361 | kfree(dev->video_channels); | |
362 | free_dev: | |
363 | kfree(dev); | |
364 | return err; | |
365 | } | |
366 | ||
367 | static void tw686x_remove(struct pci_dev *pci_dev) | |
368 | { | |
369 | struct tw686x_dev *dev = pci_get_drvdata(pci_dev); | |
370 | unsigned long flags; | |
371 | ||
372 | /* This guarantees the IRQ handler is no longer running, | |
373 | * which means we can kiss good-bye some resources. | |
374 | */ | |
375 | free_irq(pci_dev->irq, dev); | |
376 | ||
377 | tw686x_video_free(dev); | |
378 | tw686x_audio_free(dev); | |
379 | del_timer_sync(&dev->dma_delay_timer); | |
380 | ||
381 | pci_iounmap(pci_dev, dev->mmio); | |
382 | pci_release_regions(pci_dev); | |
383 | pci_disable_device(pci_dev); | |
384 | ||
385 | /* | |
386 | * Setting pci_dev to NULL allows to detect hardware is no longer | |
387 | * available and will be used by vb2_ops. This is required because | |
388 | * the device sometimes hot-unplugs itself as the result of a PCIe | |
389 | * link down. | |
390 | * The lock is really important here. | |
391 | */ | |
392 | spin_lock_irqsave(&dev->lock, flags); | |
393 | dev->pci_dev = NULL; | |
394 | spin_unlock_irqrestore(&dev->lock, flags); | |
395 | ||
396 | /* | |
397 | * This calls tw686x_dev_release if it's the last reference. | |
398 | * Otherwise, release is postponed until there are no users left. | |
399 | */ | |
400 | v4l2_device_put(&dev->v4l2_dev); | |
401 | } | |
402 | ||
403 | /* | |
404 | * On TW6864 and TW6868, all channels share the pair of video DMA SG tables, | |
405 | * with 10-bit start_idx and end_idx determining start and end of frame buffer | |
406 | * for particular channel. | |
407 | * TW6868 with all its 8 channels would be problematic (only 127 SG entries per | |
408 | * channel) but we support only 4 channels on this chip anyway (the first | |
409 | * 4 channels are driven with internal video decoder, the other 4 would require | |
410 | * an external TW286x part). | |
411 | * | |
412 | * On TW6865 and TW6869, each channel has its own DMA SG table, with indexes | |
413 | * starting with 0. Both chips have complete sets of internal video decoders | |
414 | * (respectively 4 or 8-channel). | |
415 | * | |
416 | * All chips have separate SG tables for two video frames. | |
417 | */ | |
418 | ||
419 | /* driver_data is number of A/V channels */ | |
420 | static const struct pci_device_id tw686x_pci_tbl[] = { | |
421 | { | |
422 | PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, 0x6864), | |
423 | .driver_data = 4 | |
424 | }, | |
425 | { | |
426 | PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, 0x6865), /* not tested */ | |
427 | .driver_data = 4 | TYPE_SECOND_GEN | |
428 | }, | |
429 | /* | |
430 | * TW6868 supports 8 A/V channels with an external TW2865 chip; | |
431 | * not supported by the driver. | |
432 | */ | |
433 | { | |
434 | PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, 0x6868), /* not tested */ | |
435 | .driver_data = 4 | |
436 | }, | |
437 | { | |
438 | PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, 0x6869), | |
439 | .driver_data = 8 | TYPE_SECOND_GEN}, | |
440 | {} | |
441 | }; | |
442 | MODULE_DEVICE_TABLE(pci, tw686x_pci_tbl); | |
443 | ||
444 | static struct pci_driver tw686x_pci_driver = { | |
445 | .name = "tw686x", | |
446 | .id_table = tw686x_pci_tbl, | |
447 | .probe = tw686x_probe, | |
448 | .remove = tw686x_remove, | |
449 | }; | |
450 | module_pci_driver(tw686x_pci_driver); | |
451 | ||
452 | MODULE_DESCRIPTION("Driver for video frame grabber cards based on Intersil/Techwell TW686[4589]"); | |
453 | MODULE_AUTHOR("Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>"); | |
454 | MODULE_AUTHOR("Krzysztof Ha?asa <khalasa@piap.pl>"); | |
455 | MODULE_LICENSE("GPL v2"); |