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