diff options
Diffstat (limited to 'drivers/media/pci/cx25821/cx25821-video-upstream-ch2.c')
-rw-r--r-- | drivers/media/pci/cx25821/cx25821-video-upstream-ch2.c | 802 |
1 files changed, 802 insertions, 0 deletions
diff --git a/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.c b/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.c new file mode 100644 index 000000000000..c8c94fbf5d8d --- /dev/null +++ b/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.c | |||
@@ -0,0 +1,802 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX25821 PCIe bridge | ||
3 | * | ||
4 | * Copyright (C) 2009 Conexant Systems Inc. | ||
5 | * Authors <hiep.huynh@conexant.com>, <shu.lin@conexant.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | */ | ||
22 | |||
23 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
24 | |||
25 | #include "cx25821-video.h" | ||
26 | #include "cx25821-video-upstream-ch2.h" | ||
27 | |||
28 | #include <linux/fs.h> | ||
29 | #include <linux/errno.h> | ||
30 | #include <linux/kernel.h> | ||
31 | #include <linux/init.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <linux/syscalls.h> | ||
34 | #include <linux/file.h> | ||
35 | #include <linux/fcntl.h> | ||
36 | #include <linux/slab.h> | ||
37 | #include <linux/uaccess.h> | ||
38 | |||
39 | MODULE_DESCRIPTION("v4l2 driver module for cx25821 based TV cards"); | ||
40 | MODULE_AUTHOR("Hiep Huynh <hiep.huynh@conexant.com>"); | ||
41 | MODULE_LICENSE("GPL"); | ||
42 | |||
43 | static int _intr_msk = FLD_VID_SRC_RISC1 | FLD_VID_SRC_UF | FLD_VID_SRC_SYNC | | ||
44 | FLD_VID_SRC_OPC_ERR; | ||
45 | |||
46 | static __le32 *cx25821_update_riscprogram_ch2(struct cx25821_dev *dev, | ||
47 | __le32 *rp, unsigned int offset, | ||
48 | unsigned int bpl, u32 sync_line, | ||
49 | unsigned int lines, | ||
50 | int fifo_enable, int field_type) | ||
51 | { | ||
52 | unsigned int line, i; | ||
53 | int dist_betwn_starts = bpl * 2; | ||
54 | |||
55 | *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); | ||
56 | |||
57 | if (USE_RISC_NOOP_VIDEO) { | ||
58 | for (i = 0; i < NUM_NO_OPS; i++) | ||
59 | *(rp++) = cpu_to_le32(RISC_NOOP); | ||
60 | } | ||
61 | |||
62 | /* scan lines */ | ||
63 | for (line = 0; line < lines; line++) { | ||
64 | *(rp++) = cpu_to_le32(RISC_READ | RISC_SOL | RISC_EOL | bpl); | ||
65 | *(rp++) = cpu_to_le32(dev->_data_buf_phys_addr_ch2 + offset); | ||
66 | *(rp++) = cpu_to_le32(0); /* bits 63-32 */ | ||
67 | |||
68 | if ((lines <= NTSC_FIELD_HEIGHT) || | ||
69 | (line < (NTSC_FIELD_HEIGHT - 1)) || !(dev->_isNTSC_ch2)) { | ||
70 | offset += dist_betwn_starts; | ||
71 | } | ||
72 | } | ||
73 | |||
74 | return rp; | ||
75 | } | ||
76 | |||
77 | static __le32 *cx25821_risc_field_upstream_ch2(struct cx25821_dev *dev, | ||
78 | __le32 *rp, | ||
79 | dma_addr_t databuf_phys_addr, | ||
80 | unsigned int offset, | ||
81 | u32 sync_line, unsigned int bpl, | ||
82 | unsigned int lines, | ||
83 | int fifo_enable, int field_type) | ||
84 | { | ||
85 | unsigned int line, i; | ||
86 | struct sram_channel *sram_ch = | ||
87 | dev->channels[dev->_channel2_upstream_select].sram_channels; | ||
88 | int dist_betwn_starts = bpl * 2; | ||
89 | |||
90 | /* sync instruction */ | ||
91 | if (sync_line != NO_SYNC_LINE) | ||
92 | *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); | ||
93 | |||
94 | if (USE_RISC_NOOP_VIDEO) { | ||
95 | for (i = 0; i < NUM_NO_OPS; i++) | ||
96 | *(rp++) = cpu_to_le32(RISC_NOOP); | ||
97 | } | ||
98 | |||
99 | /* scan lines */ | ||
100 | for (line = 0; line < lines; line++) { | ||
101 | *(rp++) = cpu_to_le32(RISC_READ | RISC_SOL | RISC_EOL | bpl); | ||
102 | *(rp++) = cpu_to_le32(databuf_phys_addr + offset); | ||
103 | *(rp++) = cpu_to_le32(0); /* bits 63-32 */ | ||
104 | |||
105 | if ((lines <= NTSC_FIELD_HEIGHT) || | ||
106 | (line < (NTSC_FIELD_HEIGHT - 1)) || !(dev->_isNTSC_ch2)) { | ||
107 | offset += dist_betwn_starts; | ||
108 | } | ||
109 | |||
110 | /* | ||
111 | check if we need to enable the FIFO after the first 4 lines | ||
112 | For the upstream video channel, the risc engine will enable | ||
113 | the FIFO. | ||
114 | */ | ||
115 | if (fifo_enable && line == 3) { | ||
116 | *(rp++) = RISC_WRITECR; | ||
117 | *(rp++) = sram_ch->dma_ctl; | ||
118 | *(rp++) = FLD_VID_FIFO_EN; | ||
119 | *(rp++) = 0x00000001; | ||
120 | } | ||
121 | } | ||
122 | |||
123 | return rp; | ||
124 | } | ||
125 | |||
126 | int cx25821_risc_buffer_upstream_ch2(struct cx25821_dev *dev, | ||
127 | struct pci_dev *pci, | ||
128 | unsigned int top_offset, unsigned int bpl, | ||
129 | unsigned int lines) | ||
130 | { | ||
131 | __le32 *rp; | ||
132 | int fifo_enable = 0; | ||
133 | int singlefield_lines = lines >> 1; /*get line count for single field */ | ||
134 | int odd_num_lines = singlefield_lines; | ||
135 | int frame = 0; | ||
136 | int frame_size = 0; | ||
137 | int databuf_offset = 0; | ||
138 | int risc_program_size = 0; | ||
139 | int risc_flag = RISC_CNT_RESET; | ||
140 | unsigned int bottom_offset = bpl; | ||
141 | dma_addr_t risc_phys_jump_addr; | ||
142 | |||
143 | if (dev->_isNTSC_ch2) { | ||
144 | odd_num_lines = singlefield_lines + 1; | ||
145 | risc_program_size = FRAME1_VID_PROG_SIZE; | ||
146 | if (bpl == Y411_LINE_SZ) | ||
147 | frame_size = FRAME_SIZE_NTSC_Y411; | ||
148 | else | ||
149 | frame_size = FRAME_SIZE_NTSC_Y422; | ||
150 | } else { | ||
151 | risc_program_size = PAL_VID_PROG_SIZE; | ||
152 | if (bpl == Y411_LINE_SZ) | ||
153 | frame_size = FRAME_SIZE_PAL_Y411; | ||
154 | else | ||
155 | frame_size = FRAME_SIZE_PAL_Y422; | ||
156 | } | ||
157 | |||
158 | /* Virtual address of Risc buffer program */ | ||
159 | rp = dev->_dma_virt_addr_ch2; | ||
160 | |||
161 | for (frame = 0; frame < NUM_FRAMES; frame++) { | ||
162 | databuf_offset = frame_size * frame; | ||
163 | |||
164 | if (UNSET != top_offset) { | ||
165 | fifo_enable = (frame == 0) ? FIFO_ENABLE : FIFO_DISABLE; | ||
166 | rp = cx25821_risc_field_upstream_ch2(dev, rp, | ||
167 | dev->_data_buf_phys_addr_ch2 + databuf_offset, | ||
168 | top_offset, 0, bpl, odd_num_lines, fifo_enable, | ||
169 | ODD_FIELD); | ||
170 | } | ||
171 | |||
172 | fifo_enable = FIFO_DISABLE; | ||
173 | |||
174 | /* Even field */ | ||
175 | rp = cx25821_risc_field_upstream_ch2(dev, rp, | ||
176 | dev->_data_buf_phys_addr_ch2 + databuf_offset, | ||
177 | bottom_offset, 0x200, bpl, singlefield_lines, | ||
178 | fifo_enable, EVEN_FIELD); | ||
179 | |||
180 | if (frame == 0) { | ||
181 | risc_flag = RISC_CNT_RESET; | ||
182 | risc_phys_jump_addr = dev->_dma_phys_start_addr_ch2 + | ||
183 | risc_program_size; | ||
184 | } else { | ||
185 | risc_flag = RISC_CNT_INC; | ||
186 | risc_phys_jump_addr = dev->_dma_phys_start_addr_ch2; | ||
187 | } | ||
188 | |||
189 | /* | ||
190 | * Loop to 2ndFrameRISC or to Start of | ||
191 | * Risc program & generate IRQ | ||
192 | */ | ||
193 | *(rp++) = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | risc_flag); | ||
194 | *(rp++) = cpu_to_le32(risc_phys_jump_addr); | ||
195 | *(rp++) = cpu_to_le32(0); | ||
196 | } | ||
197 | |||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | void cx25821_stop_upstream_video_ch2(struct cx25821_dev *dev) | ||
202 | { | ||
203 | struct sram_channel *sram_ch = | ||
204 | dev->channels[VID_UPSTREAM_SRAM_CHANNEL_J].sram_channels; | ||
205 | u32 tmp = 0; | ||
206 | |||
207 | if (!dev->_is_running_ch2) { | ||
208 | pr_info("No video file is currently running so return!\n"); | ||
209 | return; | ||
210 | } | ||
211 | /* Disable RISC interrupts */ | ||
212 | tmp = cx_read(sram_ch->int_msk); | ||
213 | cx_write(sram_ch->int_msk, tmp & ~_intr_msk); | ||
214 | |||
215 | /* Turn OFF risc and fifo */ | ||
216 | tmp = cx_read(sram_ch->dma_ctl); | ||
217 | cx_write(sram_ch->dma_ctl, tmp & ~(FLD_VID_FIFO_EN | FLD_VID_RISC_EN)); | ||
218 | |||
219 | /* Clear data buffer memory */ | ||
220 | if (dev->_data_buf_virt_addr_ch2) | ||
221 | memset(dev->_data_buf_virt_addr_ch2, 0, | ||
222 | dev->_data_buf_size_ch2); | ||
223 | |||
224 | dev->_is_running_ch2 = 0; | ||
225 | dev->_is_first_frame_ch2 = 0; | ||
226 | dev->_frame_count_ch2 = 0; | ||
227 | dev->_file_status_ch2 = END_OF_FILE; | ||
228 | |||
229 | kfree(dev->_irq_queues_ch2); | ||
230 | dev->_irq_queues_ch2 = NULL; | ||
231 | |||
232 | kfree(dev->_filename_ch2); | ||
233 | |||
234 | tmp = cx_read(VID_CH_MODE_SEL); | ||
235 | cx_write(VID_CH_MODE_SEL, tmp & 0xFFFFFE00); | ||
236 | } | ||
237 | |||
238 | void cx25821_free_mem_upstream_ch2(struct cx25821_dev *dev) | ||
239 | { | ||
240 | if (dev->_is_running_ch2) | ||
241 | cx25821_stop_upstream_video_ch2(dev); | ||
242 | |||
243 | if (dev->_dma_virt_addr_ch2) { | ||
244 | pci_free_consistent(dev->pci, dev->_risc_size_ch2, | ||
245 | dev->_dma_virt_addr_ch2, | ||
246 | dev->_dma_phys_addr_ch2); | ||
247 | dev->_dma_virt_addr_ch2 = NULL; | ||
248 | } | ||
249 | |||
250 | if (dev->_data_buf_virt_addr_ch2) { | ||
251 | pci_free_consistent(dev->pci, dev->_data_buf_size_ch2, | ||
252 | dev->_data_buf_virt_addr_ch2, | ||
253 | dev->_data_buf_phys_addr_ch2); | ||
254 | dev->_data_buf_virt_addr_ch2 = NULL; | ||
255 | } | ||
256 | } | ||
257 | |||
258 | int cx25821_get_frame_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch) | ||
259 | { | ||
260 | struct file *myfile; | ||
261 | int frame_index_temp = dev->_frame_index_ch2; | ||
262 | int i = 0; | ||
263 | int line_size = (dev->_pixel_format_ch2 == PIXEL_FRMT_411) ? | ||
264 | Y411_LINE_SZ : Y422_LINE_SZ; | ||
265 | int frame_size = 0; | ||
266 | int frame_offset = 0; | ||
267 | ssize_t vfs_read_retval = 0; | ||
268 | char mybuf[line_size]; | ||
269 | loff_t file_offset; | ||
270 | loff_t pos; | ||
271 | mm_segment_t old_fs; | ||
272 | |||
273 | if (dev->_file_status_ch2 == END_OF_FILE) | ||
274 | return 0; | ||
275 | |||
276 | if (dev->_isNTSC_ch2) { | ||
277 | frame_size = (line_size == Y411_LINE_SZ) ? | ||
278 | FRAME_SIZE_NTSC_Y411 : FRAME_SIZE_NTSC_Y422; | ||
279 | } else { | ||
280 | frame_size = (line_size == Y411_LINE_SZ) ? | ||
281 | FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422; | ||
282 | } | ||
283 | |||
284 | frame_offset = (frame_index_temp > 0) ? frame_size : 0; | ||
285 | file_offset = dev->_frame_count_ch2 * frame_size; | ||
286 | |||
287 | myfile = filp_open(dev->_filename_ch2, O_RDONLY | O_LARGEFILE, 0); | ||
288 | if (IS_ERR(myfile)) { | ||
289 | const int open_errno = -PTR_ERR(myfile); | ||
290 | pr_err("%s(): ERROR opening file(%s) with errno = %d!\n", | ||
291 | __func__, dev->_filename_ch2, open_errno); | ||
292 | return PTR_ERR(myfile); | ||
293 | } else { | ||
294 | if (!(myfile->f_op)) { | ||
295 | pr_err("%s(): File has no file operations registered!\n", | ||
296 | __func__); | ||
297 | filp_close(myfile, NULL); | ||
298 | return -EIO; | ||
299 | } | ||
300 | |||
301 | if (!myfile->f_op->read) { | ||
302 | pr_err("%s(): File has no READ operations registered!\n", | ||
303 | __func__); | ||
304 | filp_close(myfile, NULL); | ||
305 | return -EIO; | ||
306 | } | ||
307 | |||
308 | pos = myfile->f_pos; | ||
309 | old_fs = get_fs(); | ||
310 | set_fs(KERNEL_DS); | ||
311 | |||
312 | for (i = 0; i < dev->_lines_count_ch2; i++) { | ||
313 | pos = file_offset; | ||
314 | |||
315 | vfs_read_retval = vfs_read(myfile, mybuf, line_size, | ||
316 | &pos); | ||
317 | |||
318 | if (vfs_read_retval > 0 && vfs_read_retval == line_size | ||
319 | && dev->_data_buf_virt_addr_ch2 != NULL) { | ||
320 | memcpy((void *)(dev->_data_buf_virt_addr_ch2 + | ||
321 | frame_offset / 4), mybuf, | ||
322 | vfs_read_retval); | ||
323 | } | ||
324 | |||
325 | file_offset += vfs_read_retval; | ||
326 | frame_offset += vfs_read_retval; | ||
327 | |||
328 | if (vfs_read_retval < line_size) { | ||
329 | pr_info("Done: exit %s() since no more bytes to read from Video file\n", | ||
330 | __func__); | ||
331 | break; | ||
332 | } | ||
333 | } | ||
334 | |||
335 | if (i > 0) | ||
336 | dev->_frame_count_ch2++; | ||
337 | |||
338 | dev->_file_status_ch2 = (vfs_read_retval == line_size) ? | ||
339 | IN_PROGRESS : END_OF_FILE; | ||
340 | |||
341 | set_fs(old_fs); | ||
342 | filp_close(myfile, NULL); | ||
343 | } | ||
344 | |||
345 | return 0; | ||
346 | } | ||
347 | |||
348 | static void cx25821_vidups_handler_ch2(struct work_struct *work) | ||
349 | { | ||
350 | struct cx25821_dev *dev = container_of(work, struct cx25821_dev, | ||
351 | _irq_work_entry_ch2); | ||
352 | |||
353 | if (!dev) { | ||
354 | pr_err("ERROR %s(): since container_of(work_struct) FAILED!\n", | ||
355 | __func__); | ||
356 | return; | ||
357 | } | ||
358 | |||
359 | cx25821_get_frame_ch2(dev, dev->channels[dev-> | ||
360 | _channel2_upstream_select].sram_channels); | ||
361 | } | ||
362 | |||
363 | int cx25821_openfile_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch) | ||
364 | { | ||
365 | struct file *myfile; | ||
366 | int i = 0, j = 0; | ||
367 | int line_size = (dev->_pixel_format_ch2 == PIXEL_FRMT_411) ? | ||
368 | Y411_LINE_SZ : Y422_LINE_SZ; | ||
369 | ssize_t vfs_read_retval = 0; | ||
370 | char mybuf[line_size]; | ||
371 | loff_t pos; | ||
372 | loff_t offset = (unsigned long)0; | ||
373 | mm_segment_t old_fs; | ||
374 | |||
375 | myfile = filp_open(dev->_filename_ch2, O_RDONLY | O_LARGEFILE, 0); | ||
376 | |||
377 | if (IS_ERR(myfile)) { | ||
378 | const int open_errno = -PTR_ERR(myfile); | ||
379 | pr_err("%s(): ERROR opening file(%s) with errno = %d!\n", | ||
380 | __func__, dev->_filename_ch2, open_errno); | ||
381 | return PTR_ERR(myfile); | ||
382 | } else { | ||
383 | if (!(myfile->f_op)) { | ||
384 | pr_err("%s(): File has no file operations registered!\n", | ||
385 | __func__); | ||
386 | filp_close(myfile, NULL); | ||
387 | return -EIO; | ||
388 | } | ||
389 | |||
390 | if (!myfile->f_op->read) { | ||
391 | pr_err("%s(): File has no READ operations registered! Returning\n", | ||
392 | __func__); | ||
393 | filp_close(myfile, NULL); | ||
394 | return -EIO; | ||
395 | } | ||
396 | |||
397 | pos = myfile->f_pos; | ||
398 | old_fs = get_fs(); | ||
399 | set_fs(KERNEL_DS); | ||
400 | |||
401 | for (j = 0; j < NUM_FRAMES; j++) { | ||
402 | for (i = 0; i < dev->_lines_count_ch2; i++) { | ||
403 | pos = offset; | ||
404 | |||
405 | vfs_read_retval = vfs_read(myfile, mybuf, | ||
406 | line_size, &pos); | ||
407 | |||
408 | if (vfs_read_retval > 0 && | ||
409 | vfs_read_retval == line_size && | ||
410 | dev->_data_buf_virt_addr_ch2 != NULL) { | ||
411 | memcpy((void *)(dev-> | ||
412 | _data_buf_virt_addr_ch2 | ||
413 | + offset / 4), mybuf, | ||
414 | vfs_read_retval); | ||
415 | } | ||
416 | |||
417 | offset += vfs_read_retval; | ||
418 | |||
419 | if (vfs_read_retval < line_size) { | ||
420 | pr_info("Done: exit %s() since no more bytes to read from Video file\n", | ||
421 | __func__); | ||
422 | break; | ||
423 | } | ||
424 | } | ||
425 | |||
426 | if (i > 0) | ||
427 | dev->_frame_count_ch2++; | ||
428 | |||
429 | if (vfs_read_retval < line_size) | ||
430 | break; | ||
431 | } | ||
432 | |||
433 | dev->_file_status_ch2 = (vfs_read_retval == line_size) ? | ||
434 | IN_PROGRESS : END_OF_FILE; | ||
435 | |||
436 | set_fs(old_fs); | ||
437 | myfile->f_pos = 0; | ||
438 | filp_close(myfile, NULL); | ||
439 | } | ||
440 | |||
441 | return 0; | ||
442 | } | ||
443 | |||
444 | static int cx25821_upstream_buffer_prepare_ch2(struct cx25821_dev *dev, | ||
445 | struct sram_channel *sram_ch, | ||
446 | int bpl) | ||
447 | { | ||
448 | int ret = 0; | ||
449 | dma_addr_t dma_addr; | ||
450 | dma_addr_t data_dma_addr; | ||
451 | |||
452 | if (dev->_dma_virt_addr_ch2 != NULL) { | ||
453 | pci_free_consistent(dev->pci, dev->upstream_riscbuf_size_ch2, | ||
454 | dev->_dma_virt_addr_ch2, | ||
455 | dev->_dma_phys_addr_ch2); | ||
456 | } | ||
457 | |||
458 | dev->_dma_virt_addr_ch2 = pci_alloc_consistent(dev->pci, | ||
459 | dev->upstream_riscbuf_size_ch2, &dma_addr); | ||
460 | dev->_dma_virt_start_addr_ch2 = dev->_dma_virt_addr_ch2; | ||
461 | dev->_dma_phys_start_addr_ch2 = dma_addr; | ||
462 | dev->_dma_phys_addr_ch2 = dma_addr; | ||
463 | dev->_risc_size_ch2 = dev->upstream_riscbuf_size_ch2; | ||
464 | |||
465 | if (!dev->_dma_virt_addr_ch2) { | ||
466 | pr_err("FAILED to allocate memory for Risc buffer! Returning\n"); | ||
467 | return -ENOMEM; | ||
468 | } | ||
469 | |||
470 | /* Iniitize at this address until n bytes to 0 */ | ||
471 | memset(dev->_dma_virt_addr_ch2, 0, dev->_risc_size_ch2); | ||
472 | |||
473 | if (dev->_data_buf_virt_addr_ch2 != NULL) { | ||
474 | pci_free_consistent(dev->pci, dev->upstream_databuf_size_ch2, | ||
475 | dev->_data_buf_virt_addr_ch2, | ||
476 | dev->_data_buf_phys_addr_ch2); | ||
477 | } | ||
478 | /* For Video Data buffer allocation */ | ||
479 | dev->_data_buf_virt_addr_ch2 = pci_alloc_consistent(dev->pci, | ||
480 | dev->upstream_databuf_size_ch2, &data_dma_addr); | ||
481 | dev->_data_buf_phys_addr_ch2 = data_dma_addr; | ||
482 | dev->_data_buf_size_ch2 = dev->upstream_databuf_size_ch2; | ||
483 | |||
484 | if (!dev->_data_buf_virt_addr_ch2) { | ||
485 | pr_err("FAILED to allocate memory for data buffer! Returning\n"); | ||
486 | return -ENOMEM; | ||
487 | } | ||
488 | |||
489 | /* Initialize at this address until n bytes to 0 */ | ||
490 | memset(dev->_data_buf_virt_addr_ch2, 0, dev->_data_buf_size_ch2); | ||
491 | |||
492 | ret = cx25821_openfile_ch2(dev, sram_ch); | ||
493 | if (ret < 0) | ||
494 | return ret; | ||
495 | |||
496 | /* Creating RISC programs */ | ||
497 | ret = cx25821_risc_buffer_upstream_ch2(dev, dev->pci, 0, bpl, | ||
498 | dev->_lines_count_ch2); | ||
499 | if (ret < 0) { | ||
500 | pr_info("Failed creating Video Upstream Risc programs!\n"); | ||
501 | goto error; | ||
502 | } | ||
503 | |||
504 | return 0; | ||
505 | |||
506 | error: | ||
507 | return ret; | ||
508 | } | ||
509 | |||
510 | int cx25821_video_upstream_irq_ch2(struct cx25821_dev *dev, int chan_num, | ||
511 | u32 status) | ||
512 | { | ||
513 | u32 int_msk_tmp; | ||
514 | struct sram_channel *channel = dev->channels[chan_num].sram_channels; | ||
515 | int singlefield_lines = NTSC_FIELD_HEIGHT; | ||
516 | int line_size_in_bytes = Y422_LINE_SZ; | ||
517 | int odd_risc_prog_size = 0; | ||
518 | dma_addr_t risc_phys_jump_addr; | ||
519 | __le32 *rp; | ||
520 | |||
521 | if (status & FLD_VID_SRC_RISC1) { | ||
522 | /* We should only process one program per call */ | ||
523 | u32 prog_cnt = cx_read(channel->gpcnt); | ||
524 | |||
525 | /* | ||
526 | * Since we've identified our IRQ, clear our bits from the | ||
527 | * interrupt mask and interrupt status registers | ||
528 | */ | ||
529 | int_msk_tmp = cx_read(channel->int_msk); | ||
530 | cx_write(channel->int_msk, int_msk_tmp & ~_intr_msk); | ||
531 | cx_write(channel->int_stat, _intr_msk); | ||
532 | |||
533 | spin_lock(&dev->slock); | ||
534 | |||
535 | dev->_frame_index_ch2 = prog_cnt; | ||
536 | |||
537 | queue_work(dev->_irq_queues_ch2, &dev->_irq_work_entry_ch2); | ||
538 | |||
539 | if (dev->_is_first_frame_ch2) { | ||
540 | dev->_is_first_frame_ch2 = 0; | ||
541 | |||
542 | if (dev->_isNTSC_ch2) { | ||
543 | singlefield_lines += 1; | ||
544 | odd_risc_prog_size = ODD_FLD_NTSC_PROG_SIZE; | ||
545 | } else { | ||
546 | singlefield_lines = PAL_FIELD_HEIGHT; | ||
547 | odd_risc_prog_size = ODD_FLD_PAL_PROG_SIZE; | ||
548 | } | ||
549 | |||
550 | if (dev->_dma_virt_start_addr_ch2 != NULL) { | ||
551 | if (dev->_pixel_format_ch2 == PIXEL_FRMT_411) | ||
552 | line_size_in_bytes = Y411_LINE_SZ; | ||
553 | else | ||
554 | line_size_in_bytes = Y422_LINE_SZ; | ||
555 | risc_phys_jump_addr = | ||
556 | dev->_dma_phys_start_addr_ch2 + | ||
557 | odd_risc_prog_size; | ||
558 | |||
559 | rp = cx25821_update_riscprogram_ch2(dev, | ||
560 | dev->_dma_virt_start_addr_ch2, | ||
561 | TOP_OFFSET, line_size_in_bytes, | ||
562 | 0x0, singlefield_lines, | ||
563 | FIFO_DISABLE, ODD_FIELD); | ||
564 | |||
565 | /* Jump to Even Risc program of 1st Frame */ | ||
566 | *(rp++) = cpu_to_le32(RISC_JUMP); | ||
567 | *(rp++) = cpu_to_le32(risc_phys_jump_addr); | ||
568 | *(rp++) = cpu_to_le32(0); | ||
569 | } | ||
570 | } | ||
571 | |||
572 | spin_unlock(&dev->slock); | ||
573 | } | ||
574 | |||
575 | if (dev->_file_status_ch2 == END_OF_FILE) { | ||
576 | pr_info("EOF Channel 2 Framecount = %d\n", | ||
577 | dev->_frame_count_ch2); | ||
578 | return -1; | ||
579 | } | ||
580 | /* ElSE, set the interrupt mask register, re-enable irq. */ | ||
581 | int_msk_tmp = cx_read(channel->int_msk); | ||
582 | cx_write(channel->int_msk, int_msk_tmp |= _intr_msk); | ||
583 | |||
584 | return 0; | ||
585 | } | ||
586 | |||
587 | static irqreturn_t cx25821_upstream_irq_ch2(int irq, void *dev_id) | ||
588 | { | ||
589 | struct cx25821_dev *dev = dev_id; | ||
590 | u32 vid_status; | ||
591 | int handled = 0; | ||
592 | int channel_num = 0; | ||
593 | struct sram_channel *sram_ch; | ||
594 | |||
595 | if (!dev) | ||
596 | return -1; | ||
597 | |||
598 | channel_num = VID_UPSTREAM_SRAM_CHANNEL_J; | ||
599 | sram_ch = dev->channels[channel_num].sram_channels; | ||
600 | |||
601 | vid_status = cx_read(sram_ch->int_stat); | ||
602 | |||
603 | /* Only deal with our interrupt */ | ||
604 | if (vid_status) | ||
605 | handled = cx25821_video_upstream_irq_ch2(dev, channel_num, | ||
606 | vid_status); | ||
607 | |||
608 | if (handled < 0) | ||
609 | cx25821_stop_upstream_video_ch2(dev); | ||
610 | else | ||
611 | handled += handled; | ||
612 | |||
613 | return IRQ_RETVAL(handled); | ||
614 | } | ||
615 | |||
616 | static void cx25821_set_pixelengine_ch2(struct cx25821_dev *dev, | ||
617 | struct sram_channel *ch, int pix_format) | ||
618 | { | ||
619 | int width = WIDTH_D1; | ||
620 | int height = dev->_lines_count_ch2; | ||
621 | int num_lines, odd_num_lines; | ||
622 | u32 value; | ||
623 | int vip_mode = PIXEL_ENGINE_VIP1; | ||
624 | |||
625 | value = ((pix_format & 0x3) << 12) | (vip_mode & 0x7); | ||
626 | value &= 0xFFFFFFEF; | ||
627 | value |= dev->_isNTSC_ch2 ? 0 : 0x10; | ||
628 | cx_write(ch->vid_fmt_ctl, value); | ||
629 | |||
630 | /* | ||
631 | * set number of active pixels in each line. Default is 720 | ||
632 | * pixels in both NTSC and PAL format | ||
633 | */ | ||
634 | cx_write(ch->vid_active_ctl1, width); | ||
635 | |||
636 | num_lines = (height / 2) & 0x3FF; | ||
637 | odd_num_lines = num_lines; | ||
638 | |||
639 | if (dev->_isNTSC_ch2) | ||
640 | odd_num_lines += 1; | ||
641 | |||
642 | value = (num_lines << 16) | odd_num_lines; | ||
643 | |||
644 | /* set number of active lines in field 0 (top) and field 1 (bottom) */ | ||
645 | cx_write(ch->vid_active_ctl2, value); | ||
646 | |||
647 | cx_write(ch->vid_cdt_size, VID_CDT_SIZE >> 3); | ||
648 | } | ||
649 | |||
650 | int cx25821_start_video_dma_upstream_ch2(struct cx25821_dev *dev, | ||
651 | struct sram_channel *sram_ch) | ||
652 | { | ||
653 | u32 tmp = 0; | ||
654 | int err = 0; | ||
655 | |||
656 | /* | ||
657 | * 656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface | ||
658 | * for channel A-C | ||
659 | */ | ||
660 | tmp = cx_read(VID_CH_MODE_SEL); | ||
661 | cx_write(VID_CH_MODE_SEL, tmp | 0x1B0001FF); | ||
662 | |||
663 | /* | ||
664 | * Set the physical start address of the RISC program in the initial | ||
665 | * program counter(IPC) member of the cmds. | ||
666 | */ | ||
667 | cx_write(sram_ch->cmds_start + 0, dev->_dma_phys_addr_ch2); | ||
668 | cx_write(sram_ch->cmds_start + 4, 0); /* Risc IPC High 64 bits 63-32 */ | ||
669 | |||
670 | /* reset counter */ | ||
671 | cx_write(sram_ch->gpcnt_ctl, 3); | ||
672 | |||
673 | /* Clear our bits from the interrupt status register. */ | ||
674 | cx_write(sram_ch->int_stat, _intr_msk); | ||
675 | |||
676 | /* Set the interrupt mask register, enable irq. */ | ||
677 | cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | (1 << sram_ch->irq_bit)); | ||
678 | tmp = cx_read(sram_ch->int_msk); | ||
679 | cx_write(sram_ch->int_msk, tmp |= _intr_msk); | ||
680 | |||
681 | err = request_irq(dev->pci->irq, cx25821_upstream_irq_ch2, | ||
682 | IRQF_SHARED, dev->name, dev); | ||
683 | if (err < 0) { | ||
684 | pr_err("%s: can't get upstream IRQ %d\n", | ||
685 | dev->name, dev->pci->irq); | ||
686 | goto fail_irq; | ||
687 | } | ||
688 | /* Start the DMA engine */ | ||
689 | tmp = cx_read(sram_ch->dma_ctl); | ||
690 | cx_set(sram_ch->dma_ctl, tmp | FLD_VID_RISC_EN); | ||
691 | |||
692 | dev->_is_running_ch2 = 1; | ||
693 | dev->_is_first_frame_ch2 = 1; | ||
694 | |||
695 | return 0; | ||
696 | |||
697 | fail_irq: | ||
698 | cx25821_dev_unregister(dev); | ||
699 | return err; | ||
700 | } | ||
701 | |||
702 | int cx25821_vidupstream_init_ch2(struct cx25821_dev *dev, int channel_select, | ||
703 | int pixel_format) | ||
704 | { | ||
705 | struct sram_channel *sram_ch; | ||
706 | u32 tmp; | ||
707 | int retval = 0; | ||
708 | int err = 0; | ||
709 | int data_frame_size = 0; | ||
710 | int risc_buffer_size = 0; | ||
711 | int str_length = 0; | ||
712 | |||
713 | if (dev->_is_running_ch2) { | ||
714 | pr_info("Video Channel is still running so return!\n"); | ||
715 | return 0; | ||
716 | } | ||
717 | |||
718 | dev->_channel2_upstream_select = channel_select; | ||
719 | sram_ch = dev->channels[channel_select].sram_channels; | ||
720 | |||
721 | INIT_WORK(&dev->_irq_work_entry_ch2, cx25821_vidups_handler_ch2); | ||
722 | dev->_irq_queues_ch2 = | ||
723 | create_singlethread_workqueue("cx25821_workqueue2"); | ||
724 | |||
725 | if (!dev->_irq_queues_ch2) { | ||
726 | pr_err("create_singlethread_workqueue() for Video FAILED!\n"); | ||
727 | return -ENOMEM; | ||
728 | } | ||
729 | /* | ||
730 | * 656/VIP SRC Upstream Channel I & J and 7 - | ||
731 | * Host Bus Interface for channel A-C | ||
732 | */ | ||
733 | tmp = cx_read(VID_CH_MODE_SEL); | ||
734 | cx_write(VID_CH_MODE_SEL, tmp | 0x1B0001FF); | ||
735 | |||
736 | dev->_is_running_ch2 = 0; | ||
737 | dev->_frame_count_ch2 = 0; | ||
738 | dev->_file_status_ch2 = RESET_STATUS; | ||
739 | dev->_lines_count_ch2 = dev->_isNTSC_ch2 ? 480 : 576; | ||
740 | dev->_pixel_format_ch2 = pixel_format; | ||
741 | dev->_line_size_ch2 = (dev->_pixel_format_ch2 == PIXEL_FRMT_422) ? | ||
742 | (WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2; | ||
743 | data_frame_size = dev->_isNTSC_ch2 ? NTSC_DATA_BUF_SZ : PAL_DATA_BUF_SZ; | ||
744 | risc_buffer_size = dev->_isNTSC_ch2 ? | ||
745 | NTSC_RISC_BUF_SIZE : PAL_RISC_BUF_SIZE; | ||
746 | |||
747 | if (dev->input_filename_ch2) { | ||
748 | str_length = strlen(dev->input_filename_ch2); | ||
749 | dev->_filename_ch2 = kmemdup(dev->input_filename_ch2, | ||
750 | str_length + 1, GFP_KERNEL); | ||
751 | |||
752 | if (!dev->_filename_ch2) | ||
753 | goto error; | ||
754 | } else { | ||
755 | str_length = strlen(dev->_defaultname_ch2); | ||
756 | dev->_filename_ch2 = kmemdup(dev->_defaultname_ch2, | ||
757 | str_length + 1, GFP_KERNEL); | ||
758 | |||
759 | if (!dev->_filename_ch2) | ||
760 | goto error; | ||
761 | } | ||
762 | |||
763 | /* Default if filename is empty string */ | ||
764 | if (strcmp(dev->input_filename_ch2, "") == 0) { | ||
765 | if (dev->_isNTSC_ch2) { | ||
766 | dev->_filename_ch2 = (dev->_pixel_format_ch2 == | ||
767 | PIXEL_FRMT_411) ? "/root/vid411.yuv" : | ||
768 | "/root/vidtest.yuv"; | ||
769 | } else { | ||
770 | dev->_filename_ch2 = (dev->_pixel_format_ch2 == | ||
771 | PIXEL_FRMT_411) ? "/root/pal411.yuv" : | ||
772 | "/root/pal422.yuv"; | ||
773 | } | ||
774 | } | ||
775 | |||
776 | retval = cx25821_sram_channel_setup_upstream(dev, sram_ch, | ||
777 | dev->_line_size_ch2, 0); | ||
778 | |||
779 | /* setup fifo + format */ | ||
780 | cx25821_set_pixelengine_ch2(dev, sram_ch, dev->_pixel_format_ch2); | ||
781 | |||
782 | dev->upstream_riscbuf_size_ch2 = risc_buffer_size * 2; | ||
783 | dev->upstream_databuf_size_ch2 = data_frame_size * 2; | ||
784 | |||
785 | /* Allocating buffers and prepare RISC program */ | ||
786 | retval = cx25821_upstream_buffer_prepare_ch2(dev, sram_ch, | ||
787 | dev->_line_size_ch2); | ||
788 | if (retval < 0) { | ||
789 | pr_err("%s: Failed to set up Video upstream buffers!\n", | ||
790 | dev->name); | ||
791 | goto error; | ||
792 | } | ||
793 | |||
794 | cx25821_start_video_dma_upstream_ch2(dev, sram_ch); | ||
795 | |||
796 | return 0; | ||
797 | |||
798 | error: | ||
799 | cx25821_dev_unregister(dev); | ||
800 | |||
801 | return err; | ||
802 | } | ||