]>
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. | |
1a9fc855 MCC |
17 | */ |
18 | ||
36d89f7d JP |
19 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
20 | ||
1a9fc855 MCC |
21 | #include "cx25821-video.h" |
22 | #include "cx25821-video-upstream.h" | |
23 | ||
1a9fc855 MCC |
24 | #include <linux/errno.h> |
25 | #include <linux/kernel.h> | |
26 | #include <linux/init.h> | |
27 | #include <linux/module.h> | |
5a0e3ad6 | 28 | #include <linux/slab.h> |
1a9fc855 MCC |
29 | |
30 | MODULE_DESCRIPTION("v4l2 driver module for cx25821 based TV cards"); | |
31 | MODULE_AUTHOR("Hiep Huynh <hiep.huynh@conexant.com>"); | |
32 | MODULE_LICENSE("GPL"); | |
33 | ||
2b2d0395 LF |
34 | static int _intr_msk = FLD_VID_SRC_RISC1 | FLD_VID_SRC_UF | FLD_VID_SRC_SYNC | |
35 | FLD_VID_SRC_OPC_ERR; | |
1a9fc855 MCC |
36 | |
37 | int cx25821_sram_channel_setup_upstream(struct cx25821_dev *dev, | |
bfef0d35 | 38 | const struct sram_channel *ch, |
1a9fc855 MCC |
39 | unsigned int bpl, u32 risc) |
40 | { | |
41 | unsigned int i, lines; | |
42 | u32 cdt; | |
43 | ||
44 | if (ch->cmds_start == 0) { | |
45 | cx_write(ch->ptr1_reg, 0); | |
46 | cx_write(ch->ptr2_reg, 0); | |
47 | cx_write(ch->cnt2_reg, 0); | |
48 | cx_write(ch->cnt1_reg, 0); | |
49 | return 0; | |
50 | } | |
51 | ||
52 | bpl = (bpl + 7) & ~7; /* alignment */ | |
53 | cdt = ch->cdt; | |
54 | lines = ch->fifo_size / bpl; | |
55 | ||
10991235 | 56 | if (lines > 4) |
1a9fc855 | 57 | lines = 4; |
1a9fc855 MCC |
58 | |
59 | BUG_ON(lines < 2); | |
60 | ||
61 | /* write CDT */ | |
62 | for (i = 0; i < lines; i++) { | |
63 | cx_write(cdt + 16 * i, ch->fifo_start + bpl * i); | |
64 | cx_write(cdt + 16 * i + 4, 0); | |
65 | cx_write(cdt + 16 * i + 8, 0); | |
66 | cx_write(cdt + 16 * i + 12, 0); | |
67 | } | |
68 | ||
69 | /* write CMDS */ | |
70 | cx_write(ch->cmds_start + 0, risc); | |
71 | ||
72 | cx_write(ch->cmds_start + 4, 0); | |
73 | cx_write(ch->cmds_start + 8, cdt); | |
74 | cx_write(ch->cmds_start + 12, (lines * 16) >> 3); | |
75 | cx_write(ch->cmds_start + 16, ch->ctrl_start); | |
76 | ||
77 | cx_write(ch->cmds_start + 20, VID_IQ_SIZE_DW); | |
78 | ||
79 | for (i = 24; i < 80; i += 4) | |
80 | cx_write(ch->cmds_start + i, 0); | |
81 | ||
82 | /* fill registers */ | |
83 | cx_write(ch->ptr1_reg, ch->fifo_start); | |
84 | cx_write(ch->ptr2_reg, cdt); | |
85 | cx_write(ch->cnt2_reg, (lines * 16) >> 3); | |
86 | cx_write(ch->cnt1_reg, (bpl >> 3) - 1); | |
87 | ||
88 | return 0; | |
89 | } | |
90 | ||
7087d31b | 91 | static __le32 *cx25821_update_riscprogram(struct cx25821_channel *chan, |
10991235 | 92 | __le32 *rp, unsigned int offset, |
1a9fc855 MCC |
93 | unsigned int bpl, u32 sync_line, |
94 | unsigned int lines, int fifo_enable, | |
95 | int field_type) | |
96 | { | |
7087d31b | 97 | struct cx25821_video_out_data *out = chan->out; |
1a9fc855 MCC |
98 | unsigned int line, i; |
99 | int dist_betwn_starts = bpl * 2; | |
100 | ||
101 | *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); | |
102 | ||
103 | if (USE_RISC_NOOP_VIDEO) { | |
10991235 | 104 | for (i = 0; i < NUM_NO_OPS; i++) |
1a9fc855 | 105 | *(rp++) = cpu_to_le32(RISC_NOOP); |
1a9fc855 MCC |
106 | } |
107 | ||
108 | /* scan lines */ | |
109 | for (line = 0; line < lines; line++) { | |
110 | *(rp++) = cpu_to_le32(RISC_READ | RISC_SOL | RISC_EOL | bpl); | |
7087d31b | 111 | *(rp++) = cpu_to_le32(out->_data_buf_phys_addr + offset); |
1a9fc855 MCC |
112 | *(rp++) = cpu_to_le32(0); /* bits 63-32 */ |
113 | ||
114 | if ((lines <= NTSC_FIELD_HEIGHT) | |
7087d31b | 115 | || (line < (NTSC_FIELD_HEIGHT - 1)) || !(out->is_60hz)) { |
1a9fc855 MCC |
116 | offset += dist_betwn_starts; |
117 | } | |
118 | } | |
119 | ||
120 | return rp; | |
121 | } | |
122 | ||
7087d31b | 123 | static __le32 *cx25821_risc_field_upstream(struct cx25821_channel *chan, __le32 *rp, |
1a9fc855 MCC |
124 | dma_addr_t databuf_phys_addr, |
125 | unsigned int offset, u32 sync_line, | |
126 | unsigned int bpl, unsigned int lines, | |
127 | int fifo_enable, int field_type) | |
128 | { | |
7087d31b | 129 | struct cx25821_video_out_data *out = chan->out; |
1a9fc855 | 130 | unsigned int line, i; |
7087d31b | 131 | const struct sram_channel *sram_ch = chan->sram_channels; |
1a9fc855 MCC |
132 | int dist_betwn_starts = bpl * 2; |
133 | ||
134 | /* sync instruction */ | |
10991235 | 135 | if (sync_line != NO_SYNC_LINE) |
1a9fc855 | 136 | *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); |
1a9fc855 MCC |
137 | |
138 | if (USE_RISC_NOOP_VIDEO) { | |
10991235 | 139 | for (i = 0; i < NUM_NO_OPS; i++) |
1a9fc855 | 140 | *(rp++) = cpu_to_le32(RISC_NOOP); |
1a9fc855 MCC |
141 | } |
142 | ||
143 | /* scan lines */ | |
144 | for (line = 0; line < lines; line++) { | |
145 | *(rp++) = cpu_to_le32(RISC_READ | RISC_SOL | RISC_EOL | bpl); | |
146 | *(rp++) = cpu_to_le32(databuf_phys_addr + offset); | |
147 | *(rp++) = cpu_to_le32(0); /* bits 63-32 */ | |
148 | ||
149 | if ((lines <= NTSC_FIELD_HEIGHT) | |
7087d31b | 150 | || (line < (NTSC_FIELD_HEIGHT - 1)) || !(out->is_60hz)) |
10991235 OP |
151 | /* to skip the other field line */ |
152 | offset += dist_betwn_starts; | |
1a9fc855 | 153 | |
10991235 OP |
154 | /* check if we need to enable the FIFO after the first 4 lines |
155 | * For the upstream video channel, the risc engine will enable | |
156 | * the FIFO. */ | |
1a9fc855 | 157 | if (fifo_enable && line == 3) { |
60b3b4d2 HV |
158 | *(rp++) = cpu_to_le32(RISC_WRITECR); |
159 | *(rp++) = cpu_to_le32(sram_ch->dma_ctl); | |
160 | *(rp++) = cpu_to_le32(FLD_VID_FIFO_EN); | |
161 | *(rp++) = cpu_to_le32(0x00000001); | |
1a9fc855 MCC |
162 | } |
163 | } | |
164 | ||
165 | return rp; | |
166 | } | |
167 | ||
7087d31b | 168 | static int cx25821_risc_buffer_upstream(struct cx25821_channel *chan, |
dafc456c MCC |
169 | struct pci_dev *pci, |
170 | unsigned int top_offset, | |
171 | unsigned int bpl, unsigned int lines) | |
1a9fc855 | 172 | { |
7087d31b | 173 | struct cx25821_video_out_data *out = chan->out; |
1a9fc855 MCC |
174 | __le32 *rp; |
175 | int fifo_enable = 0; | |
10991235 OP |
176 | /* get line count for single field */ |
177 | int singlefield_lines = lines >> 1; | |
1a9fc855 MCC |
178 | int odd_num_lines = singlefield_lines; |
179 | int frame = 0; | |
180 | int frame_size = 0; | |
181 | int databuf_offset = 0; | |
182 | int risc_program_size = 0; | |
183 | int risc_flag = RISC_CNT_RESET; | |
184 | unsigned int bottom_offset = bpl; | |
185 | dma_addr_t risc_phys_jump_addr; | |
186 | ||
7087d31b | 187 | if (out->is_60hz) { |
1a9fc855 MCC |
188 | odd_num_lines = singlefield_lines + 1; |
189 | risc_program_size = FRAME1_VID_PROG_SIZE; | |
8eb1fdff LF |
190 | frame_size = (bpl == Y411_LINE_SZ) ? |
191 | FRAME_SIZE_NTSC_Y411 : FRAME_SIZE_NTSC_Y422; | |
1a9fc855 MCC |
192 | } else { |
193 | risc_program_size = PAL_VID_PROG_SIZE; | |
8eb1fdff LF |
194 | frame_size = (bpl == Y411_LINE_SZ) ? |
195 | FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422; | |
1a9fc855 MCC |
196 | } |
197 | ||
198 | /* Virtual address of Risc buffer program */ | |
7087d31b | 199 | rp = out->_dma_virt_addr; |
1a9fc855 MCC |
200 | |
201 | for (frame = 0; frame < NUM_FRAMES; frame++) { | |
202 | databuf_offset = frame_size * frame; | |
203 | ||
204 | if (UNSET != top_offset) { | |
205 | fifo_enable = (frame == 0) ? FIFO_ENABLE : FIFO_DISABLE; | |
7087d31b HV |
206 | rp = cx25821_risc_field_upstream(chan, rp, |
207 | out->_data_buf_phys_addr + | |
2c68e933 LF |
208 | databuf_offset, top_offset, 0, bpl, |
209 | odd_num_lines, fifo_enable, ODD_FIELD); | |
1a9fc855 MCC |
210 | } |
211 | ||
212 | fifo_enable = FIFO_DISABLE; | |
213 | ||
10991235 | 214 | /* Even Field */ |
7087d31b HV |
215 | rp = cx25821_risc_field_upstream(chan, rp, |
216 | out->_data_buf_phys_addr + | |
1a9fc855 MCC |
217 | databuf_offset, bottom_offset, |
218 | 0x200, bpl, singlefield_lines, | |
219 | fifo_enable, EVEN_FIELD); | |
220 | ||
221 | if (frame == 0) { | |
222 | risc_flag = RISC_CNT_RESET; | |
7087d31b | 223 | risc_phys_jump_addr = out->_dma_phys_start_addr + |
8eb1fdff | 224 | risc_program_size; |
1a9fc855 | 225 | } else { |
7087d31b | 226 | risc_phys_jump_addr = out->_dma_phys_start_addr; |
1a9fc855 MCC |
227 | risc_flag = RISC_CNT_INC; |
228 | } | |
229 | ||
10991235 OP |
230 | /* Loop to 2ndFrameRISC or to Start of Risc |
231 | * program & generate IRQ | |
232 | */ | |
1a9fc855 MCC |
233 | *(rp++) = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | risc_flag); |
234 | *(rp++) = cpu_to_le32(risc_phys_jump_addr); | |
235 | *(rp++) = cpu_to_le32(0); | |
236 | } | |
237 | ||
238 | return 0; | |
239 | } | |
240 | ||
7087d31b | 241 | void cx25821_stop_upstream_video(struct cx25821_channel *chan) |
1a9fc855 | 242 | { |
7087d31b HV |
243 | struct cx25821_video_out_data *out = chan->out; |
244 | struct cx25821_dev *dev = chan->dev; | |
245 | const struct sram_channel *sram_ch = chan->sram_channels; | |
1a9fc855 MCC |
246 | u32 tmp = 0; |
247 | ||
7087d31b | 248 | if (!out->_is_running) { |
36d89f7d | 249 | pr_info("No video file is currently running so return!\n"); |
1a9fc855 MCC |
250 | return; |
251 | } | |
ea3f7ac6 HV |
252 | |
253 | /* Set the interrupt mask register, disable irq. */ | |
254 | cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) & ~(1 << sram_ch->irq_bit)); | |
255 | ||
10991235 | 256 | /* Disable RISC interrupts */ |
1a9fc855 MCC |
257 | tmp = cx_read(sram_ch->int_msk); |
258 | cx_write(sram_ch->int_msk, tmp & ~_intr_msk); | |
259 | ||
10991235 | 260 | /* Turn OFF risc and fifo enable */ |
1a9fc855 MCC |
261 | tmp = cx_read(sram_ch->dma_ctl); |
262 | cx_write(sram_ch->dma_ctl, tmp & ~(FLD_VID_FIFO_EN | FLD_VID_RISC_EN)); | |
263 | ||
ea3f7ac6 HV |
264 | free_irq(dev->pci->irq, chan); |
265 | ||
10991235 | 266 | /* Clear data buffer memory */ |
7087d31b HV |
267 | if (out->_data_buf_virt_addr) |
268 | memset(out->_data_buf_virt_addr, 0, out->_data_buf_size); | |
1a9fc855 | 269 | |
7087d31b HV |
270 | out->_is_running = 0; |
271 | out->_is_first_frame = 0; | |
272 | out->_frame_count = 0; | |
273 | out->_file_status = END_OF_FILE; | |
1a9fc855 | 274 | |
1a9fc855 MCC |
275 | tmp = cx_read(VID_CH_MODE_SEL); |
276 | cx_write(VID_CH_MODE_SEL, tmp & 0xFFFFFE00); | |
277 | } | |
278 | ||
7087d31b | 279 | void cx25821_free_mem_upstream(struct cx25821_channel *chan) |
1a9fc855 | 280 | { |
7087d31b HV |
281 | struct cx25821_video_out_data *out = chan->out; |
282 | struct cx25821_dev *dev = chan->dev; | |
1a9fc855 | 283 | |
7087d31b HV |
284 | if (out->_is_running) |
285 | cx25821_stop_upstream_video(chan); | |
286 | ||
287 | if (out->_dma_virt_addr) { | |
288 | pci_free_consistent(dev->pci, out->_risc_size, | |
289 | out->_dma_virt_addr, out->_dma_phys_addr); | |
290 | out->_dma_virt_addr = NULL; | |
1a9fc855 MCC |
291 | } |
292 | ||
7087d31b HV |
293 | if (out->_data_buf_virt_addr) { |
294 | pci_free_consistent(dev->pci, out->_data_buf_size, | |
295 | out->_data_buf_virt_addr, | |
296 | out->_data_buf_phys_addr); | |
297 | out->_data_buf_virt_addr = NULL; | |
1a9fc855 MCC |
298 | } |
299 | } | |
300 | ||
ea3f7ac6 HV |
301 | int cx25821_write_frame(struct cx25821_channel *chan, |
302 | const char __user *data, size_t count) | |
1a9fc855 | 303 | { |
7087d31b | 304 | struct cx25821_video_out_data *out = chan->out; |
7087d31b | 305 | int line_size = (out->_pixel_format == PIXEL_FRMT_411) ? |
8eb1fdff | 306 | Y411_LINE_SZ : Y422_LINE_SZ; |
1a9fc855 MCC |
307 | int frame_size = 0; |
308 | int frame_offset = 0; | |
ea3f7ac6 | 309 | int curpos = out->curpos; |
1a9fc855 | 310 | |
7087d31b | 311 | if (out->is_60hz) |
16f0fda7 LF |
312 | frame_size = (line_size == Y411_LINE_SZ) ? |
313 | FRAME_SIZE_NTSC_Y411 : FRAME_SIZE_NTSC_Y422; | |
314 | else | |
315 | frame_size = (line_size == Y411_LINE_SZ) ? | |
316 | FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422; | |
1a9fc855 | 317 | |
ea3f7ac6 HV |
318 | if (curpos == 0) { |
319 | out->cur_frame_index = out->_frame_index; | |
320 | if (wait_event_interruptible(out->waitq, out->cur_frame_index != out->_frame_index)) | |
321 | return -EINTR; | |
322 | out->cur_frame_index = out->_frame_index; | |
1a9fc855 MCC |
323 | } |
324 | ||
ea3f7ac6 | 325 | frame_offset = out->cur_frame_index ? frame_size : 0; |
1a9fc855 | 326 | |
ea3f7ac6 HV |
327 | if (frame_size - curpos < count) |
328 | count = frame_size - curpos; | |
38b2b879 HV |
329 | if (copy_from_user((__force char *)out->_data_buf_virt_addr + frame_offset + curpos, |
330 | data, count)) | |
331 | return -EFAULT; | |
ea3f7ac6 HV |
332 | curpos += count; |
333 | if (curpos == frame_size) { | |
334 | out->_frame_count++; | |
335 | curpos = 0; | |
1a9fc855 | 336 | } |
ea3f7ac6 | 337 | out->curpos = curpos; |
1a9fc855 | 338 | |
ea3f7ac6 | 339 | return count; |
1a9fc855 MCC |
340 | } |
341 | ||
7087d31b | 342 | static int cx25821_upstream_buffer_prepare(struct cx25821_channel *chan, |
bfef0d35 | 343 | const struct sram_channel *sram_ch, |
dafc456c | 344 | int bpl) |
1a9fc855 | 345 | { |
7087d31b HV |
346 | struct cx25821_video_out_data *out = chan->out; |
347 | struct cx25821_dev *dev = chan->dev; | |
1a9fc855 MCC |
348 | int ret = 0; |
349 | dma_addr_t dma_addr; | |
350 | dma_addr_t data_dma_addr; | |
351 | ||
7087d31b HV |
352 | if (out->_dma_virt_addr != NULL) |
353 | pci_free_consistent(dev->pci, out->upstream_riscbuf_size, | |
354 | out->_dma_virt_addr, out->_dma_phys_addr); | |
1a9fc855 | 355 | |
7087d31b HV |
356 | out->_dma_virt_addr = pci_alloc_consistent(dev->pci, |
357 | out->upstream_riscbuf_size, &dma_addr); | |
358 | out->_dma_virt_start_addr = out->_dma_virt_addr; | |
359 | out->_dma_phys_start_addr = dma_addr; | |
360 | out->_dma_phys_addr = dma_addr; | |
361 | out->_risc_size = out->upstream_riscbuf_size; | |
1a9fc855 | 362 | |
7087d31b | 363 | if (!out->_dma_virt_addr) { |
36d89f7d | 364 | pr_err("FAILED to allocate memory for Risc buffer! Returning\n"); |
1a9fc855 MCC |
365 | return -ENOMEM; |
366 | } | |
367 | ||
10991235 | 368 | /* Clear memory at address */ |
7087d31b | 369 | memset(out->_dma_virt_addr, 0, out->_risc_size); |
1a9fc855 | 370 | |
7087d31b HV |
371 | if (out->_data_buf_virt_addr != NULL) |
372 | pci_free_consistent(dev->pci, out->upstream_databuf_size, | |
373 | out->_data_buf_virt_addr, | |
374 | out->_data_buf_phys_addr); | |
10991235 | 375 | /* For Video Data buffer allocation */ |
7087d31b HV |
376 | out->_data_buf_virt_addr = pci_alloc_consistent(dev->pci, |
377 | out->upstream_databuf_size, &data_dma_addr); | |
378 | out->_data_buf_phys_addr = data_dma_addr; | |
379 | out->_data_buf_size = out->upstream_databuf_size; | |
1a9fc855 | 380 | |
7087d31b | 381 | if (!out->_data_buf_virt_addr) { |
36d89f7d | 382 | pr_err("FAILED to allocate memory for data buffer! Returning\n"); |
1a9fc855 MCC |
383 | return -ENOMEM; |
384 | } | |
385 | ||
10991235 | 386 | /* Clear memory at address */ |
7087d31b | 387 | memset(out->_data_buf_virt_addr, 0, out->_data_buf_size); |
1a9fc855 | 388 | |
10991235 | 389 | /* Create RISC programs */ |
7087d31b HV |
390 | ret = cx25821_risc_buffer_upstream(chan, dev->pci, 0, bpl, |
391 | out->_lines_count); | |
1a9fc855 | 392 | if (ret < 0) { |
36d89f7d | 393 | pr_info("Failed creating Video Upstream Risc programs!\n"); |
1a9fc855 MCC |
394 | goto error; |
395 | } | |
396 | ||
397 | return 0; | |
398 | ||
10991235 | 399 | error: |
1a9fc855 MCC |
400 | return ret; |
401 | } | |
402 | ||
7087d31b | 403 | static int cx25821_video_upstream_irq(struct cx25821_channel *chan, u32 status) |
1a9fc855 | 404 | { |
7087d31b HV |
405 | struct cx25821_video_out_data *out = chan->out; |
406 | struct cx25821_dev *dev = chan->dev; | |
1a9fc855 | 407 | u32 int_msk_tmp; |
7087d31b | 408 | const struct sram_channel *channel = chan->sram_channels; |
1a9fc855 MCC |
409 | int singlefield_lines = NTSC_FIELD_HEIGHT; |
410 | int line_size_in_bytes = Y422_LINE_SZ; | |
411 | int odd_risc_prog_size = 0; | |
412 | dma_addr_t risc_phys_jump_addr; | |
413 | __le32 *rp; | |
414 | ||
415 | if (status & FLD_VID_SRC_RISC1) { | |
10991235 | 416 | /* We should only process one program per call */ |
1a9fc855 MCC |
417 | u32 prog_cnt = cx_read(channel->gpcnt); |
418 | ||
10991235 OP |
419 | /* Since we've identified our IRQ, clear our bits from the |
420 | * interrupt mask and interrupt status registers */ | |
1a9fc855 MCC |
421 | int_msk_tmp = cx_read(channel->int_msk); |
422 | cx_write(channel->int_msk, int_msk_tmp & ~_intr_msk); | |
423 | cx_write(channel->int_stat, _intr_msk); | |
424 | ||
ea3f7ac6 HV |
425 | wake_up(&out->waitq); |
426 | ||
1a9fc855 MCC |
427 | spin_lock(&dev->slock); |
428 | ||
7087d31b | 429 | out->_frame_index = prog_cnt; |
1a9fc855 | 430 | |
7087d31b HV |
431 | if (out->_is_first_frame) { |
432 | out->_is_first_frame = 0; | |
1a9fc855 | 433 | |
7087d31b | 434 | if (out->is_60hz) { |
1a9fc855 MCC |
435 | singlefield_lines += 1; |
436 | odd_risc_prog_size = ODD_FLD_NTSC_PROG_SIZE; | |
437 | } else { | |
438 | singlefield_lines = PAL_FIELD_HEIGHT; | |
439 | odd_risc_prog_size = ODD_FLD_PAL_PROG_SIZE; | |
440 | } | |
441 | ||
7087d31b | 442 | if (out->_dma_virt_start_addr != NULL) { |
1a9fc855 | 443 | line_size_in_bytes = |
7087d31b | 444 | (out->_pixel_format == |
1a9fc855 MCC |
445 | PIXEL_FRMT_411) ? Y411_LINE_SZ : |
446 | Y422_LINE_SZ; | |
447 | risc_phys_jump_addr = | |
7087d31b | 448 | out->_dma_phys_start_addr + |
1a9fc855 MCC |
449 | odd_risc_prog_size; |
450 | ||
7087d31b HV |
451 | rp = cx25821_update_riscprogram(chan, |
452 | out->_dma_virt_start_addr, TOP_OFFSET, | |
2b2d0395 LF |
453 | line_size_in_bytes, 0x0, |
454 | singlefield_lines, FIFO_DISABLE, | |
455 | ODD_FIELD); | |
1a9fc855 | 456 | |
10991235 | 457 | /* Jump to Even Risc program of 1st Frame */ |
1a9fc855 MCC |
458 | *(rp++) = cpu_to_le32(RISC_JUMP); |
459 | *(rp++) = cpu_to_le32(risc_phys_jump_addr); | |
460 | *(rp++) = cpu_to_le32(0); | |
461 | } | |
462 | } | |
463 | ||
464 | spin_unlock(&dev->slock); | |
465 | } else { | |
466 | if (status & FLD_VID_SRC_UF) | |
36d89f7d JP |
467 | pr_err("%s(): Video Received Underflow Error Interrupt!\n", |
468 | __func__); | |
1a9fc855 MCC |
469 | |
470 | if (status & FLD_VID_SRC_SYNC) | |
36d89f7d JP |
471 | pr_err("%s(): Video Received Sync Error Interrupt!\n", |
472 | __func__); | |
1a9fc855 MCC |
473 | |
474 | if (status & FLD_VID_SRC_OPC_ERR) | |
36d89f7d JP |
475 | pr_err("%s(): Video Received OpCode Error Interrupt!\n", |
476 | __func__); | |
1a9fc855 MCC |
477 | } |
478 | ||
7087d31b HV |
479 | if (out->_file_status == END_OF_FILE) { |
480 | pr_err("EOF Channel 1 Framecount = %d\n", out->_frame_count); | |
1a9fc855 MCC |
481 | return -1; |
482 | } | |
10991235 | 483 | /* ElSE, set the interrupt mask register, re-enable irq. */ |
1a9fc855 MCC |
484 | int_msk_tmp = cx_read(channel->int_msk); |
485 | cx_write(channel->int_msk, int_msk_tmp |= _intr_msk); | |
486 | ||
487 | return 0; | |
488 | } | |
489 | ||
490 | static irqreturn_t cx25821_upstream_irq(int irq, void *dev_id) | |
491 | { | |
7087d31b HV |
492 | struct cx25821_channel *chan = dev_id; |
493 | struct cx25821_dev *dev = chan->dev; | |
30fdf035 | 494 | u32 vid_status; |
1a9fc855 | 495 | int handled = 0; |
bfef0d35 | 496 | const struct sram_channel *sram_ch; |
1a9fc855 MCC |
497 | |
498 | if (!dev) | |
499 | return -1; | |
500 | ||
7087d31b | 501 | sram_ch = chan->sram_channels; |
1a9fc855 | 502 | |
1a9fc855 MCC |
503 | vid_status = cx_read(sram_ch->int_stat); |
504 | ||
10991235 | 505 | /* Only deal with our interrupt */ |
16f0fda7 | 506 | if (vid_status) |
7087d31b | 507 | handled = cx25821_video_upstream_irq(chan, vid_status); |
1a9fc855 MCC |
508 | |
509 | return IRQ_RETVAL(handled); | |
510 | } | |
511 | ||
7087d31b | 512 | static void cx25821_set_pixelengine(struct cx25821_channel *chan, |
bfef0d35 | 513 | const struct sram_channel *ch, |
dafc456c | 514 | int pix_format) |
1a9fc855 | 515 | { |
7087d31b HV |
516 | struct cx25821_video_out_data *out = chan->out; |
517 | struct cx25821_dev *dev = chan->dev; | |
1a9fc855 | 518 | int width = WIDTH_D1; |
7087d31b | 519 | int height = out->_lines_count; |
1a9fc855 MCC |
520 | int num_lines, odd_num_lines; |
521 | u32 value; | |
522 | int vip_mode = OUTPUT_FRMT_656; | |
523 | ||
524 | value = ((pix_format & 0x3) << 12) | (vip_mode & 0x7); | |
525 | value &= 0xFFFFFFEF; | |
7087d31b | 526 | value |= out->is_60hz ? 0 : 0x10; |
1a9fc855 MCC |
527 | cx_write(ch->vid_fmt_ctl, value); |
528 | ||
10991235 OP |
529 | /* set number of active pixels in each line. |
530 | * Default is 720 pixels in both NTSC and PAL format */ | |
1a9fc855 MCC |
531 | cx_write(ch->vid_active_ctl1, width); |
532 | ||
533 | num_lines = (height / 2) & 0x3FF; | |
534 | odd_num_lines = num_lines; | |
535 | ||
7087d31b | 536 | if (out->is_60hz) |
1a9fc855 | 537 | odd_num_lines += 1; |
1a9fc855 MCC |
538 | |
539 | value = (num_lines << 16) | odd_num_lines; | |
540 | ||
10991235 | 541 | /* set number of active lines in field 0 (top) and field 1 (bottom) */ |
1a9fc855 MCC |
542 | cx_write(ch->vid_active_ctl2, value); |
543 | ||
544 | cx_write(ch->vid_cdt_size, VID_CDT_SIZE >> 3); | |
545 | } | |
546 | ||
7087d31b | 547 | static int cx25821_start_video_dma_upstream(struct cx25821_channel *chan, |
bfef0d35 | 548 | const struct sram_channel *sram_ch) |
1a9fc855 | 549 | { |
7087d31b HV |
550 | struct cx25821_video_out_data *out = chan->out; |
551 | struct cx25821_dev *dev = chan->dev; | |
1a9fc855 MCC |
552 | u32 tmp = 0; |
553 | int err = 0; | |
554 | ||
10991235 OP |
555 | /* 656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface for |
556 | * channel A-C | |
557 | */ | |
1a9fc855 MCC |
558 | tmp = cx_read(VID_CH_MODE_SEL); |
559 | cx_write(VID_CH_MODE_SEL, tmp | 0x1B0001FF); | |
560 | ||
10991235 OP |
561 | /* Set the physical start address of the RISC program in the initial |
562 | * program counter(IPC) member of the cmds. | |
563 | */ | |
7087d31b | 564 | cx_write(sram_ch->cmds_start + 0, out->_dma_phys_addr); |
10991235 OP |
565 | /* Risc IPC High 64 bits 63-32 */ |
566 | cx_write(sram_ch->cmds_start + 4, 0); | |
1a9fc855 MCC |
567 | |
568 | /* reset counter */ | |
569 | cx_write(sram_ch->gpcnt_ctl, 3); | |
570 | ||
10991235 | 571 | /* Clear our bits from the interrupt status register. */ |
1a9fc855 MCC |
572 | cx_write(sram_ch->int_stat, _intr_msk); |
573 | ||
10991235 | 574 | /* Set the interrupt mask register, enable irq. */ |
1a9fc855 MCC |
575 | cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | (1 << sram_ch->irq_bit)); |
576 | tmp = cx_read(sram_ch->int_msk); | |
577 | cx_write(sram_ch->int_msk, tmp |= _intr_msk); | |
578 | ||
8eb1fdff | 579 | err = request_irq(dev->pci->irq, cx25821_upstream_irq, |
7087d31b | 580 | IRQF_SHARED, dev->name, chan); |
1a9fc855 | 581 | if (err < 0) { |
36d89f7d JP |
582 | pr_err("%s: can't get upstream IRQ %d\n", |
583 | dev->name, dev->pci->irq); | |
1a9fc855 MCC |
584 | goto fail_irq; |
585 | } | |
586 | ||
10991235 | 587 | /* Start the DMA engine */ |
1a9fc855 MCC |
588 | tmp = cx_read(sram_ch->dma_ctl); |
589 | cx_set(sram_ch->dma_ctl, tmp | FLD_VID_RISC_EN); | |
590 | ||
7087d31b HV |
591 | out->_is_running = 1; |
592 | out->_is_first_frame = 1; | |
1a9fc855 MCC |
593 | |
594 | return 0; | |
595 | ||
10991235 | 596 | fail_irq: |
1a9fc855 MCC |
597 | cx25821_dev_unregister(dev); |
598 | return err; | |
599 | } | |
600 | ||
7087d31b | 601 | int cx25821_vidupstream_init(struct cx25821_channel *chan, |
1a9fc855 MCC |
602 | int pixel_format) |
603 | { | |
7087d31b HV |
604 | struct cx25821_video_out_data *out = chan->out; |
605 | struct cx25821_dev *dev = chan->dev; | |
bfef0d35 | 606 | const struct sram_channel *sram_ch; |
1a9fc855 | 607 | u32 tmp; |
1a9fc855 MCC |
608 | int err = 0; |
609 | int data_frame_size = 0; | |
610 | int risc_buffer_size = 0; | |
1a9fc855 | 611 | |
7087d31b | 612 | if (out->_is_running) { |
36d89f7d | 613 | pr_info("Video Channel is still running so return!\n"); |
1a9fc855 MCC |
614 | return 0; |
615 | } | |
616 | ||
7087d31b | 617 | sram_ch = chan->sram_channels; |
1a9fc855 | 618 | |
ea3f7ac6 | 619 | out->is_60hz = dev->tvnorm & V4L2_STD_525_60; |
1a9fc855 | 620 | |
10991235 OP |
621 | /* 656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface for |
622 | * channel A-C | |
623 | */ | |
1a9fc855 MCC |
624 | tmp = cx_read(VID_CH_MODE_SEL); |
625 | cx_write(VID_CH_MODE_SEL, tmp | 0x1B0001FF); | |
626 | ||
7087d31b HV |
627 | out->_is_running = 0; |
628 | out->_frame_count = 0; | |
629 | out->_file_status = RESET_STATUS; | |
630 | out->_lines_count = out->is_60hz ? 480 : 576; | |
631 | out->_pixel_format = pixel_format; | |
632 | out->_line_size = (out->_pixel_format == PIXEL_FRMT_422) ? | |
8eb1fdff | 633 | (WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2; |
7087d31b HV |
634 | data_frame_size = out->is_60hz ? NTSC_DATA_BUF_SZ : PAL_DATA_BUF_SZ; |
635 | risc_buffer_size = out->is_60hz ? | |
8eb1fdff | 636 | NTSC_RISC_BUF_SIZE : PAL_RISC_BUF_SIZE; |
1a9fc855 | 637 | |
7087d31b HV |
638 | out->_is_running = 0; |
639 | out->_frame_count = 0; | |
640 | out->_file_status = RESET_STATUS; | |
641 | out->_lines_count = out->is_60hz ? 480 : 576; | |
642 | out->_pixel_format = pixel_format; | |
643 | out->_line_size = (out->_pixel_format == PIXEL_FRMT_422) ? | |
8eb1fdff | 644 | (WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2; |
ea3f7ac6 HV |
645 | out->curpos = 0; |
646 | init_waitqueue_head(&out->waitq); | |
1a9fc855 | 647 | |
216f3938 | 648 | err = cx25821_sram_channel_setup_upstream(dev, sram_ch, |
7087d31b | 649 | out->_line_size, 0); |
1a9fc855 MCC |
650 | |
651 | /* setup fifo + format */ | |
7087d31b | 652 | cx25821_set_pixelengine(chan, sram_ch, out->_pixel_format); |
1a9fc855 | 653 | |
7087d31b HV |
654 | out->upstream_riscbuf_size = risc_buffer_size * 2; |
655 | out->upstream_databuf_size = data_frame_size * 2; | |
1a9fc855 | 656 | |
10991235 | 657 | /* Allocating buffers and prepare RISC program */ |
7087d31b | 658 | err = cx25821_upstream_buffer_prepare(chan, sram_ch, out->_line_size); |
216f3938 | 659 | if (err < 0) { |
36d89f7d | 660 | pr_err("%s: Failed to set up Video upstream buffers!\n", |
1a9fc855 MCC |
661 | dev->name); |
662 | goto error; | |
663 | } | |
664 | ||
7087d31b | 665 | cx25821_start_video_dma_upstream(chan, sram_ch); |
1a9fc855 MCC |
666 | |
667 | return 0; | |
668 | ||
10991235 | 669 | error: |
1a9fc855 MCC |
670 | cx25821_dev_unregister(dev); |
671 | ||
672 | return err; | |
673 | } |