]>
Commit | Line | Data |
---|---|---|
1a9fc855 MCC |
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 | #include "cx25821-video.h" | |
24 | #include "cx25821-video-upstream.h" | |
25 | ||
26 | #include <linux/fs.h> | |
27 | #include <linux/errno.h> | |
28 | #include <linux/kernel.h> | |
29 | #include <linux/init.h> | |
30 | #include <linux/module.h> | |
31 | #include <linux/syscalls.h> | |
32 | #include <linux/file.h> | |
33 | #include <linux/fcntl.h> | |
5a0e3ad6 | 34 | #include <linux/slab.h> |
1a9fc855 MCC |
35 | #include <asm/uaccess.h> |
36 | ||
37 | MODULE_DESCRIPTION("v4l2 driver module for cx25821 based TV cards"); | |
38 | MODULE_AUTHOR("Hiep Huynh <hiep.huynh@conexant.com>"); | |
39 | MODULE_LICENSE("GPL"); | |
40 | ||
41 | static int _intr_msk = | |
42 | FLD_VID_SRC_RISC1 | FLD_VID_SRC_UF | FLD_VID_SRC_SYNC | FLD_VID_SRC_OPC_ERR; | |
43 | ||
44 | int cx25821_sram_channel_setup_upstream(struct cx25821_dev *dev, | |
45 | struct sram_channel *ch, | |
46 | unsigned int bpl, u32 risc) | |
47 | { | |
48 | unsigned int i, lines; | |
49 | u32 cdt; | |
50 | ||
51 | if (ch->cmds_start == 0) { | |
52 | cx_write(ch->ptr1_reg, 0); | |
53 | cx_write(ch->ptr2_reg, 0); | |
54 | cx_write(ch->cnt2_reg, 0); | |
55 | cx_write(ch->cnt1_reg, 0); | |
56 | return 0; | |
57 | } | |
58 | ||
59 | bpl = (bpl + 7) & ~7; /* alignment */ | |
60 | cdt = ch->cdt; | |
61 | lines = ch->fifo_size / bpl; | |
62 | ||
63 | if (lines > 4) { | |
64 | lines = 4; | |
65 | } | |
66 | ||
67 | BUG_ON(lines < 2); | |
68 | ||
69 | /* write CDT */ | |
70 | for (i = 0; i < lines; i++) { | |
71 | cx_write(cdt + 16 * i, ch->fifo_start + bpl * i); | |
72 | cx_write(cdt + 16 * i + 4, 0); | |
73 | cx_write(cdt + 16 * i + 8, 0); | |
74 | cx_write(cdt + 16 * i + 12, 0); | |
75 | } | |
76 | ||
77 | /* write CMDS */ | |
78 | cx_write(ch->cmds_start + 0, risc); | |
79 | ||
80 | cx_write(ch->cmds_start + 4, 0); | |
81 | cx_write(ch->cmds_start + 8, cdt); | |
82 | cx_write(ch->cmds_start + 12, (lines * 16) >> 3); | |
83 | cx_write(ch->cmds_start + 16, ch->ctrl_start); | |
84 | ||
85 | cx_write(ch->cmds_start + 20, VID_IQ_SIZE_DW); | |
86 | ||
87 | for (i = 24; i < 80; i += 4) | |
88 | cx_write(ch->cmds_start + i, 0); | |
89 | ||
90 | /* fill registers */ | |
91 | cx_write(ch->ptr1_reg, ch->fifo_start); | |
92 | cx_write(ch->ptr2_reg, cdt); | |
93 | cx_write(ch->cnt2_reg, (lines * 16) >> 3); | |
94 | cx_write(ch->cnt1_reg, (bpl >> 3) - 1); | |
95 | ||
96 | return 0; | |
97 | } | |
98 | ||
99 | static __le32 *cx25821_update_riscprogram(struct cx25821_dev *dev, | |
100 | __le32 * rp, unsigned int offset, | |
101 | unsigned int bpl, u32 sync_line, | |
102 | unsigned int lines, int fifo_enable, | |
103 | int field_type) | |
104 | { | |
105 | unsigned int line, i; | |
106 | int dist_betwn_starts = bpl * 2; | |
107 | ||
108 | *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); | |
109 | ||
110 | if (USE_RISC_NOOP_VIDEO) { | |
111 | for (i = 0; i < NUM_NO_OPS; i++) { | |
112 | *(rp++) = cpu_to_le32(RISC_NOOP); | |
113 | } | |
114 | } | |
115 | ||
116 | /* scan lines */ | |
117 | for (line = 0; line < lines; line++) { | |
118 | *(rp++) = cpu_to_le32(RISC_READ | RISC_SOL | RISC_EOL | bpl); | |
119 | *(rp++) = cpu_to_le32(dev->_data_buf_phys_addr + offset); | |
120 | *(rp++) = cpu_to_le32(0); /* bits 63-32 */ | |
121 | ||
122 | if ((lines <= NTSC_FIELD_HEIGHT) | |
123 | || (line < (NTSC_FIELD_HEIGHT - 1)) || !(dev->_isNTSC)) { | |
124 | offset += dist_betwn_starts; | |
125 | } | |
126 | } | |
127 | ||
128 | return rp; | |
129 | } | |
130 | ||
131 | static __le32 *cx25821_risc_field_upstream(struct cx25821_dev *dev, __le32 * rp, | |
132 | dma_addr_t databuf_phys_addr, | |
133 | unsigned int offset, u32 sync_line, | |
134 | unsigned int bpl, unsigned int lines, | |
135 | int fifo_enable, int field_type) | |
136 | { | |
137 | unsigned int line, i; | |
138 | struct sram_channel *sram_ch = | |
139 | &dev->sram_channels[dev->_channel_upstream_select]; | |
140 | int dist_betwn_starts = bpl * 2; | |
141 | ||
142 | /* sync instruction */ | |
143 | if (sync_line != NO_SYNC_LINE) { | |
144 | *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); | |
145 | } | |
146 | ||
147 | if (USE_RISC_NOOP_VIDEO) { | |
148 | for (i = 0; i < NUM_NO_OPS; i++) { | |
149 | *(rp++) = cpu_to_le32(RISC_NOOP); | |
150 | } | |
151 | } | |
152 | ||
153 | /* scan lines */ | |
154 | for (line = 0; line < lines; line++) { | |
155 | *(rp++) = cpu_to_le32(RISC_READ | RISC_SOL | RISC_EOL | bpl); | |
156 | *(rp++) = cpu_to_le32(databuf_phys_addr + offset); | |
157 | *(rp++) = cpu_to_le32(0); /* bits 63-32 */ | |
158 | ||
159 | if ((lines <= NTSC_FIELD_HEIGHT) | |
160 | || (line < (NTSC_FIELD_HEIGHT - 1)) || !(dev->_isNTSC)) { | |
161 | offset += dist_betwn_starts; //to skip the other field line | |
162 | } | |
163 | ||
164 | // check if we need to enable the FIFO after the first 4 lines | |
165 | // For the upstream video channel, the risc engine will enable the FIFO. | |
166 | if (fifo_enable && line == 3) { | |
167 | *(rp++) = RISC_WRITECR; | |
168 | *(rp++) = sram_ch->dma_ctl; | |
169 | *(rp++) = FLD_VID_FIFO_EN; | |
170 | *(rp++) = 0x00000001; | |
171 | } | |
172 | } | |
173 | ||
174 | return rp; | |
175 | } | |
176 | ||
177 | int cx25821_risc_buffer_upstream(struct cx25821_dev *dev, | |
178 | struct pci_dev *pci, | |
179 | unsigned int top_offset, | |
180 | unsigned int bpl, unsigned int lines) | |
181 | { | |
182 | __le32 *rp; | |
183 | int fifo_enable = 0; | |
184 | int singlefield_lines = lines >> 1; //get line count for single field | |
185 | int odd_num_lines = singlefield_lines; | |
186 | int frame = 0; | |
187 | int frame_size = 0; | |
188 | int databuf_offset = 0; | |
189 | int risc_program_size = 0; | |
190 | int risc_flag = RISC_CNT_RESET; | |
191 | unsigned int bottom_offset = bpl; | |
192 | dma_addr_t risc_phys_jump_addr; | |
193 | ||
194 | if (dev->_isNTSC) { | |
195 | odd_num_lines = singlefield_lines + 1; | |
196 | risc_program_size = FRAME1_VID_PROG_SIZE; | |
197 | frame_size = | |
198 | (bpl == | |
199 | Y411_LINE_SZ) ? FRAME_SIZE_NTSC_Y411 : | |
200 | FRAME_SIZE_NTSC_Y422; | |
201 | } else { | |
202 | risc_program_size = PAL_VID_PROG_SIZE; | |
203 | frame_size = | |
204 | (bpl == | |
205 | Y411_LINE_SZ) ? FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422; | |
206 | } | |
207 | ||
208 | /* Virtual address of Risc buffer program */ | |
209 | rp = dev->_dma_virt_addr; | |
210 | ||
211 | for (frame = 0; frame < NUM_FRAMES; frame++) { | |
212 | databuf_offset = frame_size * frame; | |
213 | ||
214 | if (UNSET != top_offset) { | |
215 | fifo_enable = (frame == 0) ? FIFO_ENABLE : FIFO_DISABLE; | |
216 | rp = cx25821_risc_field_upstream(dev, rp, | |
217 | dev-> | |
218 | _data_buf_phys_addr + | |
219 | databuf_offset, | |
220 | top_offset, 0, bpl, | |
221 | odd_num_lines, | |
222 | fifo_enable, | |
223 | ODD_FIELD); | |
224 | } | |
225 | ||
226 | fifo_enable = FIFO_DISABLE; | |
227 | ||
228 | //Even Field | |
229 | rp = cx25821_risc_field_upstream(dev, rp, | |
230 | dev->_data_buf_phys_addr + | |
231 | databuf_offset, bottom_offset, | |
232 | 0x200, bpl, singlefield_lines, | |
233 | fifo_enable, EVEN_FIELD); | |
234 | ||
235 | if (frame == 0) { | |
236 | risc_flag = RISC_CNT_RESET; | |
237 | risc_phys_jump_addr = | |
238 | dev->_dma_phys_start_addr + risc_program_size; | |
239 | } else { | |
240 | risc_phys_jump_addr = dev->_dma_phys_start_addr; | |
241 | risc_flag = RISC_CNT_INC; | |
242 | } | |
243 | ||
244 | // Loop to 2ndFrameRISC or to Start of Risc program & generate IRQ | |
245 | *(rp++) = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | risc_flag); | |
246 | *(rp++) = cpu_to_le32(risc_phys_jump_addr); | |
247 | *(rp++) = cpu_to_le32(0); | |
248 | } | |
249 | ||
250 | return 0; | |
251 | } | |
252 | ||
253 | void cx25821_stop_upstream_video_ch1(struct cx25821_dev *dev) | |
254 | { | |
255 | struct sram_channel *sram_ch = | |
256 | &dev->sram_channels[VID_UPSTREAM_SRAM_CHANNEL_I]; | |
257 | u32 tmp = 0; | |
258 | ||
259 | if (!dev->_is_running) { | |
260 | printk | |
261 | ("cx25821: No video file is currently running so return!\n"); | |
262 | return; | |
263 | } | |
264 | //Disable RISC interrupts | |
265 | tmp = cx_read(sram_ch->int_msk); | |
266 | cx_write(sram_ch->int_msk, tmp & ~_intr_msk); | |
267 | ||
268 | //Turn OFF risc and fifo enable | |
269 | tmp = cx_read(sram_ch->dma_ctl); | |
270 | cx_write(sram_ch->dma_ctl, tmp & ~(FLD_VID_FIFO_EN | FLD_VID_RISC_EN)); | |
271 | ||
272 | //Clear data buffer memory | |
273 | if (dev->_data_buf_virt_addr) | |
274 | memset(dev->_data_buf_virt_addr, 0, dev->_data_buf_size); | |
275 | ||
276 | dev->_is_running = 0; | |
277 | dev->_is_first_frame = 0; | |
278 | dev->_frame_count = 0; | |
279 | dev->_file_status = END_OF_FILE; | |
280 | ||
281 | if (dev->_irq_queues) { | |
282 | kfree(dev->_irq_queues); | |
283 | dev->_irq_queues = NULL; | |
284 | } | |
285 | ||
286 | if (dev->_filename != NULL) | |
287 | kfree(dev->_filename); | |
288 | ||
289 | tmp = cx_read(VID_CH_MODE_SEL); | |
290 | cx_write(VID_CH_MODE_SEL, tmp & 0xFFFFFE00); | |
291 | } | |
292 | ||
293 | void cx25821_free_mem_upstream_ch1(struct cx25821_dev *dev) | |
294 | { | |
295 | if (dev->_is_running) { | |
296 | cx25821_stop_upstream_video_ch1(dev); | |
297 | } | |
298 | ||
299 | if (dev->_dma_virt_addr) { | |
300 | pci_free_consistent(dev->pci, dev->_risc_size, | |
301 | dev->_dma_virt_addr, dev->_dma_phys_addr); | |
302 | dev->_dma_virt_addr = NULL; | |
303 | } | |
304 | ||
305 | if (dev->_data_buf_virt_addr) { | |
306 | pci_free_consistent(dev->pci, dev->_data_buf_size, | |
307 | dev->_data_buf_virt_addr, | |
308 | dev->_data_buf_phys_addr); | |
309 | dev->_data_buf_virt_addr = NULL; | |
310 | } | |
311 | } | |
312 | ||
313 | int cx25821_get_frame(struct cx25821_dev *dev, struct sram_channel *sram_ch) | |
314 | { | |
315 | struct file *myfile; | |
316 | int frame_index_temp = dev->_frame_index; | |
317 | int i = 0; | |
318 | int line_size = | |
319 | (dev->_pixel_format == | |
320 | PIXEL_FRMT_411) ? Y411_LINE_SZ : Y422_LINE_SZ; | |
321 | int frame_size = 0; | |
322 | int frame_offset = 0; | |
323 | ssize_t vfs_read_retval = 0; | |
324 | char mybuf[line_size]; | |
325 | loff_t file_offset; | |
326 | loff_t pos; | |
327 | mm_segment_t old_fs; | |
328 | ||
329 | if (dev->_file_status == END_OF_FILE) | |
330 | return 0; | |
331 | ||
332 | if (dev->_isNTSC) { | |
333 | frame_size = | |
334 | (line_size == | |
335 | Y411_LINE_SZ) ? FRAME_SIZE_NTSC_Y411 : | |
336 | FRAME_SIZE_NTSC_Y422; | |
337 | } else { | |
338 | frame_size = | |
339 | (line_size == | |
340 | Y411_LINE_SZ) ? FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422; | |
341 | } | |
342 | ||
343 | frame_offset = (frame_index_temp > 0) ? frame_size : 0; | |
344 | file_offset = dev->_frame_count * frame_size; | |
345 | ||
346 | myfile = filp_open(dev->_filename, O_RDONLY | O_LARGEFILE, 0); | |
347 | ||
348 | if (IS_ERR(myfile)) { | |
349 | const int open_errno = -PTR_ERR(myfile); | |
350 | printk("%s(): ERROR opening file(%s) with errno = %d! \n", | |
351 | __func__, dev->_filename, open_errno); | |
352 | return PTR_ERR(myfile); | |
353 | } else { | |
354 | if (!(myfile->f_op)) { | |
355 | printk("%s: File has no file operations registered!", | |
356 | __func__); | |
357 | filp_close(myfile, NULL); | |
358 | return -EIO; | |
359 | } | |
360 | ||
361 | if (!myfile->f_op->read) { | |
362 | printk("%s: File has no READ operations registered!", | |
363 | __func__); | |
364 | filp_close(myfile, NULL); | |
365 | return -EIO; | |
366 | } | |
367 | ||
368 | pos = myfile->f_pos; | |
369 | old_fs = get_fs(); | |
370 | set_fs(KERNEL_DS); | |
371 | ||
372 | for (i = 0; i < dev->_lines_count; i++) { | |
373 | pos = file_offset; | |
374 | ||
375 | vfs_read_retval = | |
376 | vfs_read(myfile, mybuf, line_size, &pos); | |
377 | ||
378 | if (vfs_read_retval > 0 && vfs_read_retval == line_size | |
379 | && dev->_data_buf_virt_addr != NULL) { | |
380 | memcpy((void *)(dev->_data_buf_virt_addr + | |
381 | frame_offset / 4), mybuf, | |
382 | vfs_read_retval); | |
383 | } | |
384 | ||
385 | file_offset += vfs_read_retval; | |
386 | frame_offset += vfs_read_retval; | |
387 | ||
388 | if (vfs_read_retval < line_size) { | |
389 | printk(KERN_INFO | |
390 | "Done: exit %s() since no more bytes to read from Video file.\n", | |
391 | __func__); | |
392 | break; | |
393 | } | |
394 | } | |
395 | ||
396 | if (i > 0) | |
397 | dev->_frame_count++; | |
398 | ||
399 | dev->_file_status = | |
400 | (vfs_read_retval == line_size) ? IN_PROGRESS : END_OF_FILE; | |
401 | ||
402 | set_fs(old_fs); | |
403 | filp_close(myfile, NULL); | |
404 | } | |
405 | ||
406 | return 0; | |
407 | } | |
408 | ||
409 | static void cx25821_vidups_handler(struct work_struct *work) | |
410 | { | |
411 | struct cx25821_dev *dev = | |
412 | container_of(work, struct cx25821_dev, _irq_work_entry); | |
413 | ||
414 | if (!dev) { | |
415 | printk("ERROR %s(): since container_of(work_struct) FAILED! \n", | |
416 | __func__); | |
417 | return; | |
418 | } | |
419 | ||
420 | cx25821_get_frame(dev, | |
421 | &dev->sram_channels[dev->_channel_upstream_select]); | |
422 | } | |
423 | ||
424 | int cx25821_openfile(struct cx25821_dev *dev, struct sram_channel *sram_ch) | |
425 | { | |
426 | struct file *myfile; | |
427 | int i = 0, j = 0; | |
428 | int line_size = | |
429 | (dev->_pixel_format == | |
430 | PIXEL_FRMT_411) ? Y411_LINE_SZ : Y422_LINE_SZ; | |
431 | ssize_t vfs_read_retval = 0; | |
432 | char mybuf[line_size]; | |
433 | loff_t pos; | |
434 | loff_t offset = (unsigned long)0; | |
435 | mm_segment_t old_fs; | |
436 | ||
437 | myfile = filp_open(dev->_filename, O_RDONLY | O_LARGEFILE, 0); | |
438 | ||
439 | if (IS_ERR(myfile)) { | |
440 | const int open_errno = -PTR_ERR(myfile); | |
441 | printk("%s(): ERROR opening file(%s) with errno = %d! \n", | |
442 | __func__, dev->_filename, open_errno); | |
443 | return PTR_ERR(myfile); | |
444 | } else { | |
445 | if (!(myfile->f_op)) { | |
446 | printk("%s: File has no file operations registered!", | |
447 | __func__); | |
448 | filp_close(myfile, NULL); | |
449 | return -EIO; | |
450 | } | |
451 | ||
452 | if (!myfile->f_op->read) { | |
453 | printk | |
454 | ("%s: File has no READ operations registered! Returning.", | |
455 | __func__); | |
456 | filp_close(myfile, NULL); | |
457 | return -EIO; | |
458 | } | |
459 | ||
460 | pos = myfile->f_pos; | |
461 | old_fs = get_fs(); | |
462 | set_fs(KERNEL_DS); | |
463 | ||
464 | for (j = 0; j < NUM_FRAMES; j++) { | |
465 | for (i = 0; i < dev->_lines_count; i++) { | |
466 | pos = offset; | |
467 | ||
468 | vfs_read_retval = | |
469 | vfs_read(myfile, mybuf, line_size, &pos); | |
470 | ||
471 | if (vfs_read_retval > 0 | |
472 | && vfs_read_retval == line_size | |
473 | && dev->_data_buf_virt_addr != NULL) { | |
474 | memcpy((void *)(dev-> | |
475 | _data_buf_virt_addr + | |
476 | offset / 4), mybuf, | |
477 | vfs_read_retval); | |
478 | } | |
479 | ||
480 | offset += vfs_read_retval; | |
481 | ||
482 | if (vfs_read_retval < line_size) { | |
483 | printk(KERN_INFO | |
484 | "Done: exit %s() since no more bytes to read from Video file.\n", | |
485 | __func__); | |
486 | break; | |
487 | } | |
488 | } | |
489 | ||
490 | if (i > 0) | |
491 | dev->_frame_count++; | |
492 | ||
493 | if (vfs_read_retval < line_size) { | |
494 | break; | |
495 | } | |
496 | } | |
497 | ||
498 | dev->_file_status = | |
499 | (vfs_read_retval == line_size) ? IN_PROGRESS : END_OF_FILE; | |
500 | ||
501 | set_fs(old_fs); | |
502 | myfile->f_pos = 0; | |
503 | filp_close(myfile, NULL); | |
504 | } | |
505 | ||
506 | return 0; | |
507 | } | |
508 | ||
509 | int cx25821_upstream_buffer_prepare(struct cx25821_dev *dev, | |
510 | struct sram_channel *sram_ch, int bpl) | |
511 | { | |
512 | int ret = 0; | |
513 | dma_addr_t dma_addr; | |
514 | dma_addr_t data_dma_addr; | |
515 | ||
516 | if (dev->_dma_virt_addr != NULL) { | |
517 | pci_free_consistent(dev->pci, dev->upstream_riscbuf_size, | |
518 | dev->_dma_virt_addr, dev->_dma_phys_addr); | |
519 | } | |
520 | ||
521 | dev->_dma_virt_addr = | |
522 | pci_alloc_consistent(dev->pci, dev->upstream_riscbuf_size, | |
523 | &dma_addr); | |
524 | dev->_dma_virt_start_addr = dev->_dma_virt_addr; | |
525 | dev->_dma_phys_start_addr = dma_addr; | |
526 | dev->_dma_phys_addr = dma_addr; | |
527 | dev->_risc_size = dev->upstream_riscbuf_size; | |
528 | ||
529 | if (!dev->_dma_virt_addr) { | |
530 | printk | |
531 | ("cx25821: FAILED to allocate memory for Risc buffer! Returning.\n"); | |
532 | return -ENOMEM; | |
533 | } | |
534 | ||
535 | //Clear memory at address | |
536 | memset(dev->_dma_virt_addr, 0, dev->_risc_size); | |
537 | ||
538 | if (dev->_data_buf_virt_addr != NULL) { | |
539 | pci_free_consistent(dev->pci, dev->upstream_databuf_size, | |
540 | dev->_data_buf_virt_addr, | |
541 | dev->_data_buf_phys_addr); | |
542 | } | |
543 | //For Video Data buffer allocation | |
544 | dev->_data_buf_virt_addr = | |
545 | pci_alloc_consistent(dev->pci, dev->upstream_databuf_size, | |
546 | &data_dma_addr); | |
547 | dev->_data_buf_phys_addr = data_dma_addr; | |
548 | dev->_data_buf_size = dev->upstream_databuf_size; | |
549 | ||
550 | if (!dev->_data_buf_virt_addr) { | |
551 | printk | |
552 | ("cx25821: FAILED to allocate memory for data buffer! Returning.\n"); | |
553 | return -ENOMEM; | |
554 | } | |
555 | ||
556 | //Clear memory at address | |
557 | memset(dev->_data_buf_virt_addr, 0, dev->_data_buf_size); | |
558 | ||
559 | ret = cx25821_openfile(dev, sram_ch); | |
560 | if (ret < 0) | |
561 | return ret; | |
562 | ||
563 | //Create RISC programs | |
564 | ret = | |
565 | cx25821_risc_buffer_upstream(dev, dev->pci, 0, bpl, | |
566 | dev->_lines_count); | |
567 | if (ret < 0) { | |
568 | printk(KERN_INFO | |
569 | "cx25821: Failed creating Video Upstream Risc programs! \n"); | |
570 | goto error; | |
571 | } | |
572 | ||
573 | return 0; | |
574 | ||
575 | error: | |
576 | return ret; | |
577 | } | |
578 | ||
579 | int cx25821_video_upstream_irq(struct cx25821_dev *dev, int chan_num, | |
580 | u32 status) | |
581 | { | |
582 | u32 int_msk_tmp; | |
583 | struct sram_channel *channel = &dev->sram_channels[chan_num]; | |
584 | int singlefield_lines = NTSC_FIELD_HEIGHT; | |
585 | int line_size_in_bytes = Y422_LINE_SZ; | |
586 | int odd_risc_prog_size = 0; | |
587 | dma_addr_t risc_phys_jump_addr; | |
588 | __le32 *rp; | |
589 | ||
590 | if (status & FLD_VID_SRC_RISC1) { | |
591 | // We should only process one program per call | |
592 | u32 prog_cnt = cx_read(channel->gpcnt); | |
593 | ||
594 | //Since we've identified our IRQ, clear our bits from the interrupt mask and interrupt status registers | |
595 | int_msk_tmp = cx_read(channel->int_msk); | |
596 | cx_write(channel->int_msk, int_msk_tmp & ~_intr_msk); | |
597 | cx_write(channel->int_stat, _intr_msk); | |
598 | ||
599 | spin_lock(&dev->slock); | |
600 | ||
601 | dev->_frame_index = prog_cnt; | |
602 | ||
603 | queue_work(dev->_irq_queues, &dev->_irq_work_entry); | |
604 | ||
605 | if (dev->_is_first_frame) { | |
606 | dev->_is_first_frame = 0; | |
607 | ||
608 | if (dev->_isNTSC) { | |
609 | singlefield_lines += 1; | |
610 | odd_risc_prog_size = ODD_FLD_NTSC_PROG_SIZE; | |
611 | } else { | |
612 | singlefield_lines = PAL_FIELD_HEIGHT; | |
613 | odd_risc_prog_size = ODD_FLD_PAL_PROG_SIZE; | |
614 | } | |
615 | ||
616 | if (dev->_dma_virt_start_addr != NULL) { | |
617 | line_size_in_bytes = | |
618 | (dev->_pixel_format == | |
619 | PIXEL_FRMT_411) ? Y411_LINE_SZ : | |
620 | Y422_LINE_SZ; | |
621 | risc_phys_jump_addr = | |
622 | dev->_dma_phys_start_addr + | |
623 | odd_risc_prog_size; | |
624 | ||
625 | rp = cx25821_update_riscprogram(dev, | |
626 | dev-> | |
627 | _dma_virt_start_addr, | |
628 | TOP_OFFSET, | |
629 | line_size_in_bytes, | |
630 | 0x0, | |
631 | singlefield_lines, | |
632 | FIFO_DISABLE, | |
633 | ODD_FIELD); | |
634 | ||
635 | // Jump to Even Risc program of 1st Frame | |
636 | *(rp++) = cpu_to_le32(RISC_JUMP); | |
637 | *(rp++) = cpu_to_le32(risc_phys_jump_addr); | |
638 | *(rp++) = cpu_to_le32(0); | |
639 | } | |
640 | } | |
641 | ||
642 | spin_unlock(&dev->slock); | |
643 | } else { | |
644 | if (status & FLD_VID_SRC_UF) | |
645 | printk | |
646 | ("%s: Video Received Underflow Error Interrupt!\n", | |
647 | __func__); | |
648 | ||
649 | if (status & FLD_VID_SRC_SYNC) | |
650 | printk("%s: Video Received Sync Error Interrupt!\n", | |
651 | __func__); | |
652 | ||
653 | if (status & FLD_VID_SRC_OPC_ERR) | |
654 | printk("%s: Video Received OpCode Error Interrupt!\n", | |
655 | __func__); | |
656 | } | |
657 | ||
658 | if (dev->_file_status == END_OF_FILE) { | |
659 | printk("cx25821: EOF Channel 1 Framecount = %d\n", | |
660 | dev->_frame_count); | |
661 | return -1; | |
662 | } | |
663 | //ElSE, set the interrupt mask register, re-enable irq. | |
664 | int_msk_tmp = cx_read(channel->int_msk); | |
665 | cx_write(channel->int_msk, int_msk_tmp |= _intr_msk); | |
666 | ||
667 | return 0; | |
668 | } | |
669 | ||
670 | static irqreturn_t cx25821_upstream_irq(int irq, void *dev_id) | |
671 | { | |
672 | struct cx25821_dev *dev = dev_id; | |
673 | u32 msk_stat, vid_status; | |
674 | int handled = 0; | |
675 | int channel_num = 0; | |
676 | struct sram_channel *sram_ch; | |
677 | ||
678 | if (!dev) | |
679 | return -1; | |
680 | ||
681 | channel_num = VID_UPSTREAM_SRAM_CHANNEL_I; | |
682 | ||
683 | sram_ch = &dev->sram_channels[channel_num]; | |
684 | ||
685 | msk_stat = cx_read(sram_ch->int_mstat); | |
686 | vid_status = cx_read(sram_ch->int_stat); | |
687 | ||
688 | // Only deal with our interrupt | |
689 | if (vid_status) { | |
690 | handled = | |
691 | cx25821_video_upstream_irq(dev, channel_num, vid_status); | |
692 | } | |
693 | ||
694 | if (handled < 0) { | |
695 | cx25821_stop_upstream_video_ch1(dev); | |
696 | } else { | |
697 | handled += handled; | |
698 | } | |
699 | ||
700 | return IRQ_RETVAL(handled); | |
701 | } | |
702 | ||
703 | void cx25821_set_pixelengine(struct cx25821_dev *dev, struct sram_channel *ch, | |
704 | int pix_format) | |
705 | { | |
706 | int width = WIDTH_D1; | |
707 | int height = dev->_lines_count; | |
708 | int num_lines, odd_num_lines; | |
709 | u32 value; | |
710 | int vip_mode = OUTPUT_FRMT_656; | |
711 | ||
712 | value = ((pix_format & 0x3) << 12) | (vip_mode & 0x7); | |
713 | value &= 0xFFFFFFEF; | |
714 | value |= dev->_isNTSC ? 0 : 0x10; | |
715 | cx_write(ch->vid_fmt_ctl, value); | |
716 | ||
717 | // set number of active pixels in each line. Default is 720 pixels in both NTSC and PAL format | |
718 | cx_write(ch->vid_active_ctl1, width); | |
719 | ||
720 | num_lines = (height / 2) & 0x3FF; | |
721 | odd_num_lines = num_lines; | |
722 | ||
723 | if (dev->_isNTSC) { | |
724 | odd_num_lines += 1; | |
725 | } | |
726 | ||
727 | value = (num_lines << 16) | odd_num_lines; | |
728 | ||
729 | // set number of active lines in field 0 (top) and field 1 (bottom) | |
730 | cx_write(ch->vid_active_ctl2, value); | |
731 | ||
732 | cx_write(ch->vid_cdt_size, VID_CDT_SIZE >> 3); | |
733 | } | |
734 | ||
735 | int cx25821_start_video_dma_upstream(struct cx25821_dev *dev, | |
736 | struct sram_channel *sram_ch) | |
737 | { | |
738 | u32 tmp = 0; | |
739 | int err = 0; | |
740 | ||
741 | // 656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface for channel A-C | |
742 | tmp = cx_read(VID_CH_MODE_SEL); | |
743 | cx_write(VID_CH_MODE_SEL, tmp | 0x1B0001FF); | |
744 | ||
745 | // Set the physical start address of the RISC program in the initial program counter(IPC) member of the cmds. | |
746 | cx_write(sram_ch->cmds_start + 0, dev->_dma_phys_addr); | |
747 | cx_write(sram_ch->cmds_start + 4, 0); /* Risc IPC High 64 bits 63-32 */ | |
748 | ||
749 | /* reset counter */ | |
750 | cx_write(sram_ch->gpcnt_ctl, 3); | |
751 | ||
752 | // Clear our bits from the interrupt status register. | |
753 | cx_write(sram_ch->int_stat, _intr_msk); | |
754 | ||
755 | //Set the interrupt mask register, enable irq. | |
756 | cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | (1 << sram_ch->irq_bit)); | |
757 | tmp = cx_read(sram_ch->int_msk); | |
758 | cx_write(sram_ch->int_msk, tmp |= _intr_msk); | |
759 | ||
760 | err = | |
761 | request_irq(dev->pci->irq, cx25821_upstream_irq, | |
762 | IRQF_SHARED | IRQF_DISABLED, dev->name, dev); | |
763 | if (err < 0) { | |
764 | printk(KERN_ERR "%s: can't get upstream IRQ %d\n", dev->name, | |
765 | dev->pci->irq); | |
766 | goto fail_irq; | |
767 | } | |
768 | ||
769 | // Start the DMA engine | |
770 | tmp = cx_read(sram_ch->dma_ctl); | |
771 | cx_set(sram_ch->dma_ctl, tmp | FLD_VID_RISC_EN); | |
772 | ||
773 | dev->_is_running = 1; | |
774 | dev->_is_first_frame = 1; | |
775 | ||
776 | return 0; | |
777 | ||
778 | fail_irq: | |
779 | cx25821_dev_unregister(dev); | |
780 | return err; | |
781 | } | |
782 | ||
783 | int cx25821_vidupstream_init_ch1(struct cx25821_dev *dev, int channel_select, | |
784 | int pixel_format) | |
785 | { | |
786 | struct sram_channel *sram_ch; | |
787 | u32 tmp; | |
788 | int retval = 0; | |
789 | int err = 0; | |
790 | int data_frame_size = 0; | |
791 | int risc_buffer_size = 0; | |
792 | int str_length = 0; | |
793 | ||
794 | if (dev->_is_running) { | |
795 | printk("Video Channel is still running so return!\n"); | |
796 | return 0; | |
797 | } | |
798 | ||
799 | dev->_channel_upstream_select = channel_select; | |
800 | sram_ch = &dev->sram_channels[channel_select]; | |
801 | ||
802 | INIT_WORK(&dev->_irq_work_entry, cx25821_vidups_handler); | |
803 | dev->_irq_queues = create_singlethread_workqueue("cx25821_workqueue"); | |
804 | ||
805 | if (!dev->_irq_queues) { | |
806 | printk | |
807 | ("cx25821: create_singlethread_workqueue() for Video FAILED!\n"); | |
808 | return -ENOMEM; | |
809 | } | |
810 | // 656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface for channel A-C | |
811 | tmp = cx_read(VID_CH_MODE_SEL); | |
812 | cx_write(VID_CH_MODE_SEL, tmp | 0x1B0001FF); | |
813 | ||
814 | dev->_is_running = 0; | |
815 | dev->_frame_count = 0; | |
816 | dev->_file_status = RESET_STATUS; | |
817 | dev->_lines_count = dev->_isNTSC ? 480 : 576; | |
818 | dev->_pixel_format = pixel_format; | |
819 | dev->_line_size = | |
820 | (dev->_pixel_format == | |
821 | PIXEL_FRMT_422) ? (WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2; | |
822 | data_frame_size = dev->_isNTSC ? NTSC_DATA_BUF_SZ : PAL_DATA_BUF_SZ; | |
823 | risc_buffer_size = | |
824 | dev->_isNTSC ? NTSC_RISC_BUF_SIZE : PAL_RISC_BUF_SIZE; | |
825 | ||
826 | if (dev->input_filename) { | |
827 | str_length = strlen(dev->input_filename); | |
32414878 | 828 | dev->_filename = kmalloc(str_length + 1, GFP_KERNEL); |
1a9fc855 MCC |
829 | |
830 | if (!dev->_filename) | |
831 | goto error; | |
832 | ||
833 | memcpy(dev->_filename, dev->input_filename, str_length + 1); | |
834 | } else { | |
835 | str_length = strlen(dev->_defaultname); | |
32414878 | 836 | dev->_filename = kmalloc(str_length + 1, GFP_KERNEL); |
1a9fc855 MCC |
837 | |
838 | if (!dev->_filename) | |
839 | goto error; | |
840 | ||
841 | memcpy(dev->_filename, dev->_defaultname, str_length + 1); | |
842 | } | |
843 | ||
844 | //Default if filename is empty string | |
845 | if (strcmp(dev->input_filename, "") == 0) { | |
846 | if (dev->_isNTSC) { | |
847 | dev->_filename = | |
848 | (dev->_pixel_format == | |
849 | PIXEL_FRMT_411) ? "/root/vid411.yuv" : | |
850 | "/root/vidtest.yuv"; | |
851 | } else { | |
852 | dev->_filename = | |
853 | (dev->_pixel_format == | |
854 | PIXEL_FRMT_411) ? "/root/pal411.yuv" : | |
855 | "/root/pal422.yuv"; | |
856 | } | |
857 | } | |
858 | ||
859 | dev->_is_running = 0; | |
860 | dev->_frame_count = 0; | |
861 | dev->_file_status = RESET_STATUS; | |
862 | dev->_lines_count = dev->_isNTSC ? 480 : 576; | |
863 | dev->_pixel_format = pixel_format; | |
864 | dev->_line_size = | |
865 | (dev->_pixel_format == | |
866 | PIXEL_FRMT_422) ? (WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2; | |
867 | ||
868 | retval = | |
869 | cx25821_sram_channel_setup_upstream(dev, sram_ch, dev->_line_size, | |
870 | 0); | |
871 | ||
872 | /* setup fifo + format */ | |
873 | cx25821_set_pixelengine(dev, sram_ch, dev->_pixel_format); | |
874 | ||
875 | dev->upstream_riscbuf_size = risc_buffer_size * 2; | |
876 | dev->upstream_databuf_size = data_frame_size * 2; | |
877 | ||
878 | //Allocating buffers and prepare RISC program | |
879 | retval = cx25821_upstream_buffer_prepare(dev, sram_ch, dev->_line_size); | |
880 | if (retval < 0) { | |
881 | printk(KERN_ERR | |
882 | "%s: Failed to set up Video upstream buffers!\n", | |
883 | dev->name); | |
884 | goto error; | |
885 | } | |
886 | ||
887 | cx25821_start_video_dma_upstream(dev, sram_ch); | |
888 | ||
889 | return 0; | |
890 | ||
891 | error: | |
892 | cx25821_dev_unregister(dev); | |
893 | ||
894 | return err; | |
895 | } |