blob: a51a3b76b1c84a7f13125fb1ae51a3e04c3f7794 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 *
3 * device driver for Conexant 2388x based TV cards
4 * driver core
5 *
6 * (c) 2003 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
7 *
Mauro Carvalho Chehab8d87cb92007-01-20 13:58:17 -03008 * (c) 2005-2006 Mauro Carvalho Chehab <mchehab@infradead.org>
9 * - Multituner support
10 * - video_ioctl2 conversion
11 * - PAL/M fixes
12 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070013 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 */
27
28#include <linux/init.h>
29#include <linux/list.h>
30#include <linux/module.h>
31#include <linux/moduleparam.h>
32#include <linux/kernel.h>
33#include <linux/slab.h>
34#include <linux/kmod.h>
35#include <linux/sound.h>
36#include <linux/interrupt.h>
37#include <linux/pci.h>
38#include <linux/delay.h>
Mauro Carvalho Chehab98f30ed2005-11-08 21:37:17 -080039#include <linux/videodev2.h>
Ingo Molnar1e4baed2006-01-15 07:52:23 -020040#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041
42#include "cx88.h"
Michael Krufky5e453dc2006-01-09 15:32:31 -020043#include <media/v4l2-common.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070044
45MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards");
46MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
47MODULE_LICENSE("GPL");
48
49/* ------------------------------------------------------------------ */
50
51static unsigned int core_debug = 0;
52module_param(core_debug,int,0644);
53MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
54
55static unsigned int latency = UNSET;
56module_param(latency,int,0444);
57MODULE_PARM_DESC(latency,"pci latency timer");
58
59static unsigned int tuner[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
Mauro Carvalho Chehabb45009b2005-06-23 22:05:03 -070060static unsigned int radio[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
Linus Torvalds1da177e2005-04-16 15:20:36 -070061static unsigned int card[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
62
63module_param_array(tuner, int, NULL, 0444);
Mauro Carvalho Chehabb45009b2005-06-23 22:05:03 -070064module_param_array(radio, int, NULL, 0444);
Linus Torvalds1da177e2005-04-16 15:20:36 -070065module_param_array(card, int, NULL, 0444);
66
67MODULE_PARM_DESC(tuner,"tuner type");
Mauro Carvalho Chehabb45009b2005-06-23 22:05:03 -070068MODULE_PARM_DESC(radio,"radio tuner type");
Linus Torvalds1da177e2005-04-16 15:20:36 -070069MODULE_PARM_DESC(card,"card type");
70
71static unsigned int nicam = 0;
72module_param(nicam,int,0644);
73MODULE_PARM_DESC(nicam,"tv audio is nicam");
74
75static unsigned int nocomb = 0;
76module_param(nocomb,int,0644);
77MODULE_PARM_DESC(nocomb,"disable comb filter");
78
79#define dprintk(level,fmt, arg...) if (core_debug >= level) \
80 printk(KERN_DEBUG "%s: " fmt, core->name , ## arg)
81
82static unsigned int cx88_devcount;
83static LIST_HEAD(cx88_devlist);
Ingo Molnar1e4baed2006-01-15 07:52:23 -020084static DEFINE_MUTEX(devlist);
Linus Torvalds1da177e2005-04-16 15:20:36 -070085
Linus Torvalds1da177e2005-04-16 15:20:36 -070086#define NO_SYNC_LINE (-1U)
87
88static u32* cx88_risc_field(u32 *rp, struct scatterlist *sglist,
89 unsigned int offset, u32 sync_line,
90 unsigned int bpl, unsigned int padding,
91 unsigned int lines)
92{
93 struct scatterlist *sg;
94 unsigned int line,todo;
95
96 /* sync instruction */
97 if (sync_line != NO_SYNC_LINE)
98 *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line);
99
100 /* scan lines */
101 sg = sglist;
102 for (line = 0; line < lines; line++) {
103 while (offset && offset >= sg_dma_len(sg)) {
104 offset -= sg_dma_len(sg);
105 sg++;
106 }
107 if (bpl <= sg_dma_len(sg)-offset) {
108 /* fits into current chunk */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800109 *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|RISC_EOL|bpl);
110 *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
111 offset+=bpl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 } else {
Peter Naullsd1009bd2006-08-08 09:10:05 -0300113 /* scanline needs to be split */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800114 todo = bpl;
115 *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116 (sg_dma_len(sg)-offset));
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800117 *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
118 todo -= (sg_dma_len(sg)-offset);
119 offset = 0;
120 sg++;
121 while (todo > sg_dma_len(sg)) {
Mauro Carvalho Chehabf2421ca2005-11-08 21:37:45 -0800122 *(rp++)=cpu_to_le32(RISC_WRITE|
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 sg_dma_len(sg));
Mauro Carvalho Chehabf2421ca2005-11-08 21:37:45 -0800124 *(rp++)=cpu_to_le32(sg_dma_address(sg));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 todo -= sg_dma_len(sg);
126 sg++;
127 }
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800128 *(rp++)=cpu_to_le32(RISC_WRITE|RISC_EOL|todo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 *(rp++)=cpu_to_le32(sg_dma_address(sg));
130 offset += todo;
131 }
132 offset += padding;
133 }
134
135 return rp;
136}
137
138int cx88_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
139 struct scatterlist *sglist,
140 unsigned int top_offset, unsigned int bottom_offset,
141 unsigned int bpl, unsigned int padding, unsigned int lines)
142{
143 u32 instructions,fields;
144 u32 *rp;
145 int rc;
146
147 fields = 0;
148 if (UNSET != top_offset)
149 fields++;
150 if (UNSET != bottom_offset)
151 fields++;
152
153 /* estimate risc mem: worst case is one write per page border +
Duncan Sandsbba3ad72006-04-11 10:18:57 -0300154 one write per scan line + syncs + jump (all 2 dwords). Padding
155 can cause next bpl to start close to a page border. First DMA
156 region may be smaller than PAGE_SIZE */
157 instructions = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + lines);
158 instructions += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 if ((rc = btcx_riscmem_alloc(pci,risc,instructions*8)) < 0)
160 return rc;
161
162 /* write risc instructions */
163 rp = risc->cpu;
164 if (UNSET != top_offset)
165 rp = cx88_risc_field(rp, sglist, top_offset, 0,
166 bpl, padding, lines);
167 if (UNSET != bottom_offset)
168 rp = cx88_risc_field(rp, sglist, bottom_offset, 0x200,
169 bpl, padding, lines);
170
171 /* save pointer to jmp instruction address */
172 risc->jmp = rp;
Duncan Sands4a287cf2006-02-27 00:09:48 -0300173 BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 return 0;
175}
176
177int cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
178 struct scatterlist *sglist, unsigned int bpl,
179 unsigned int lines)
180{
181 u32 instructions;
182 u32 *rp;
183 int rc;
184
185 /* estimate risc mem: worst case is one write per page border +
Duncan Sandsbba3ad72006-04-11 10:18:57 -0300186 one write per scan line + syncs + jump (all 2 dwords). Here
187 there is no padding and no sync. First DMA region may be smaller
188 than PAGE_SIZE */
189 instructions = 1 + (bpl * lines) / PAGE_SIZE + lines;
190 instructions += 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191 if ((rc = btcx_riscmem_alloc(pci,risc,instructions*8)) < 0)
192 return rc;
193
194 /* write risc instructions */
195 rp = risc->cpu;
196 rp = cx88_risc_field(rp, sglist, 0, NO_SYNC_LINE, bpl, 0, lines);
197
198 /* save pointer to jmp instruction address */
199 risc->jmp = rp;
Duncan Sands4a287cf2006-02-27 00:09:48 -0300200 BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 return 0;
202}
203
204int cx88_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
205 u32 reg, u32 mask, u32 value)
206{
207 u32 *rp;
208 int rc;
209
210 if ((rc = btcx_riscmem_alloc(pci, risc, 4*16)) < 0)
211 return rc;
212
213 /* write risc instructions */
214 rp = risc->cpu;
215 *(rp++) = cpu_to_le32(RISC_WRITECR | RISC_IRQ2 | RISC_IMM);
216 *(rp++) = cpu_to_le32(reg);
217 *(rp++) = cpu_to_le32(value);
218 *(rp++) = cpu_to_le32(mask);
219 *(rp++) = cpu_to_le32(RISC_JUMP);
220 *(rp++) = cpu_to_le32(risc->dma);
221 return 0;
222}
223
224void
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -0300225cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226{
Eric Sesterhennae246012006-03-13 13:17:11 -0300227 BUG_ON(in_interrupt());
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 videobuf_waiton(&buf->vb,0,0);
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -0300229 videobuf_dma_unmap(q, &buf->vb.dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 videobuf_dma_free(&buf->vb.dma);
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -0300231 btcx_riscmem_free((struct pci_dev *)q->dev, &buf->risc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 buf->vb.state = STATE_NEEDS_INIT;
233}
234
235/* ------------------------------------------------------------------ */
236/* our SRAM memory layout */
237
238/* we are going to put all thr risc programs into host memory, so we
239 * can use the whole SDRAM for the DMA fifos. To simplify things, we
240 * use a static memory layout. That surely will waste memory in case
241 * we don't use all DMA channels at the same time (which will be the
242 * case most of the time). But that still gives us enougth FIFO space
243 * to be able to deal with insane long pci latencies ...
244 *
245 * FIFO space allocations:
246 * channel 21 (y video) - 10.0k
247 * channel 22 (u video) - 2.0k
248 * channel 23 (v video) - 2.0k
249 * channel 24 (vbi) - 4.0k
Mauro Carvalho Chehabb7f355d2006-01-09 15:32:44 -0200250 * channels 25+26 (audio) - 4.0k
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 * channel 28 (mpeg) - 4.0k
Mauro Carvalho Chehabb7f355d2006-01-09 15:32:44 -0200252 * TOTAL = 29.0k
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 *
254 * Every channel has 160 bytes control data (64 bytes instruction
255 * queue and 6 CDT entries), which is close to 2k total.
256 *
257 * Address layout:
258 * 0x0000 - 0x03ff CMDs / reserved
259 * 0x0400 - 0x0bff instruction queues + CDs
260 * 0x0c00 - FIFOs
261 */
262
263struct sram_channel cx88_sram_channels[] = {
264 [SRAM_CH21] = {
265 .name = "video y / packed",
266 .cmds_start = 0x180040,
267 .ctrl_start = 0x180400,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800268 .cdt = 0x180400 + 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 .fifo_start = 0x180c00,
270 .fifo_size = 0x002800,
271 .ptr1_reg = MO_DMA21_PTR1,
272 .ptr2_reg = MO_DMA21_PTR2,
273 .cnt1_reg = MO_DMA21_CNT1,
274 .cnt2_reg = MO_DMA21_CNT2,
275 },
276 [SRAM_CH22] = {
277 .name = "video u",
278 .cmds_start = 0x180080,
279 .ctrl_start = 0x1804a0,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800280 .cdt = 0x1804a0 + 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 .fifo_start = 0x183400,
282 .fifo_size = 0x000800,
283 .ptr1_reg = MO_DMA22_PTR1,
284 .ptr2_reg = MO_DMA22_PTR2,
285 .cnt1_reg = MO_DMA22_CNT1,
286 .cnt2_reg = MO_DMA22_CNT2,
287 },
288 [SRAM_CH23] = {
289 .name = "video v",
290 .cmds_start = 0x1800c0,
291 .ctrl_start = 0x180540,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800292 .cdt = 0x180540 + 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 .fifo_start = 0x183c00,
294 .fifo_size = 0x000800,
295 .ptr1_reg = MO_DMA23_PTR1,
296 .ptr2_reg = MO_DMA23_PTR2,
297 .cnt1_reg = MO_DMA23_CNT1,
298 .cnt2_reg = MO_DMA23_CNT2,
299 },
300 [SRAM_CH24] = {
301 .name = "vbi",
302 .cmds_start = 0x180100,
303 .ctrl_start = 0x1805e0,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800304 .cdt = 0x1805e0 + 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 .fifo_start = 0x184400,
306 .fifo_size = 0x001000,
307 .ptr1_reg = MO_DMA24_PTR1,
308 .ptr2_reg = MO_DMA24_PTR2,
309 .cnt1_reg = MO_DMA24_CNT1,
310 .cnt2_reg = MO_DMA24_CNT2,
311 },
312 [SRAM_CH25] = {
313 .name = "audio from",
314 .cmds_start = 0x180140,
315 .ctrl_start = 0x180680,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800316 .cdt = 0x180680 + 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 .fifo_start = 0x185400,
Mauro Carvalho Chehabb7f355d2006-01-09 15:32:44 -0200318 .fifo_size = 0x001000,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 .ptr1_reg = MO_DMA25_PTR1,
320 .ptr2_reg = MO_DMA25_PTR2,
321 .cnt1_reg = MO_DMA25_CNT1,
322 .cnt2_reg = MO_DMA25_CNT2,
323 },
324 [SRAM_CH26] = {
325 .name = "audio to",
326 .cmds_start = 0x180180,
327 .ctrl_start = 0x180720,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800328 .cdt = 0x180680 + 64, /* same as audio IN */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 .fifo_start = 0x185400, /* same as audio IN */
Mauro Carvalho Chehabb7f355d2006-01-09 15:32:44 -0200330 .fifo_size = 0x001000, /* same as audio IN */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331 .ptr1_reg = MO_DMA26_PTR1,
332 .ptr2_reg = MO_DMA26_PTR2,
333 .cnt1_reg = MO_DMA26_CNT1,
334 .cnt2_reg = MO_DMA26_CNT2,
335 },
336 [SRAM_CH28] = {
337 .name = "mpeg",
338 .cmds_start = 0x180200,
339 .ctrl_start = 0x1807C0,
340 .cdt = 0x1807C0 + 64,
Mauro Carvalho Chehabb7f355d2006-01-09 15:32:44 -0200341 .fifo_start = 0x186400,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 .fifo_size = 0x001000,
343 .ptr1_reg = MO_DMA28_PTR1,
344 .ptr2_reg = MO_DMA28_PTR2,
345 .cnt1_reg = MO_DMA28_CNT1,
346 .cnt2_reg = MO_DMA28_CNT2,
347 },
348};
349
350int cx88_sram_channel_setup(struct cx88_core *core,
351 struct sram_channel *ch,
352 unsigned int bpl, u32 risc)
353{
354 unsigned int i,lines;
355 u32 cdt;
356
357 bpl = (bpl + 7) & ~7; /* alignment */
358 cdt = ch->cdt;
359 lines = ch->fifo_size / bpl;
360 if (lines > 6)
361 lines = 6;
362 BUG_ON(lines < 2);
363
364 /* write CDT */
365 for (i = 0; i < lines; i++)
366 cx_write(cdt + 16*i, ch->fifo_start + bpl*i);
367
368 /* write CMDS */
369 cx_write(ch->cmds_start + 0, risc);
370 cx_write(ch->cmds_start + 4, cdt);
371 cx_write(ch->cmds_start + 8, (lines*16) >> 3);
372 cx_write(ch->cmds_start + 12, ch->ctrl_start);
373 cx_write(ch->cmds_start + 16, 64 >> 2);
374 for (i = 20; i < 64; i += 4)
375 cx_write(ch->cmds_start + i, 0);
376
377 /* fill registers */
378 cx_write(ch->ptr1_reg, ch->fifo_start);
379 cx_write(ch->ptr2_reg, cdt);
380 cx_write(ch->cnt1_reg, (bpl >> 3) -1);
381 cx_write(ch->cnt2_reg, (lines*16) >> 3);
382
383 dprintk(2,"sram setup %s: bpl=%d lines=%d\n", ch->name, bpl, lines);
384 return 0;
385}
386
387/* ------------------------------------------------------------------ */
388/* debug helper code */
389
Peter Hagervallf9e7a022005-11-08 21:36:29 -0800390static int cx88_risc_decode(u32 risc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391{
392 static char *instr[16] = {
393 [ RISC_SYNC >> 28 ] = "sync",
394 [ RISC_WRITE >> 28 ] = "write",
395 [ RISC_WRITEC >> 28 ] = "writec",
396 [ RISC_READ >> 28 ] = "read",
397 [ RISC_READC >> 28 ] = "readc",
398 [ RISC_JUMP >> 28 ] = "jump",
399 [ RISC_SKIP >> 28 ] = "skip",
400 [ RISC_WRITERM >> 28 ] = "writerm",
401 [ RISC_WRITECM >> 28 ] = "writecm",
402 [ RISC_WRITECR >> 28 ] = "writecr",
403 };
404 static int incr[16] = {
405 [ RISC_WRITE >> 28 ] = 2,
406 [ RISC_JUMP >> 28 ] = 2,
407 [ RISC_WRITERM >> 28 ] = 3,
408 [ RISC_WRITECM >> 28 ] = 3,
409 [ RISC_WRITECR >> 28 ] = 4,
410 };
411 static char *bits[] = {
412 "12", "13", "14", "resync",
413 "cnt0", "cnt1", "18", "19",
414 "20", "21", "22", "23",
415 "irq1", "irq2", "eol", "sol",
416 };
417 int i;
418
419 printk("0x%08x [ %s", risc,
420 instr[risc >> 28] ? instr[risc >> 28] : "INVALID");
421 for (i = ARRAY_SIZE(bits)-1; i >= 0; i--)
422 if (risc & (1 << (i + 12)))
423 printk(" %s",bits[i]);
424 printk(" count=%d ]\n", risc & 0xfff);
425 return incr[risc >> 28] ? incr[risc >> 28] : 1;
426}
427
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428
429void cx88_sram_channel_dump(struct cx88_core *core,
430 struct sram_channel *ch)
431{
432 static char *name[] = {
433 "initial risc",
434 "cdt base",
435 "cdt size",
436 "iq base",
437 "iq size",
438 "risc pc",
439 "iq wr ptr",
440 "iq rd ptr",
441 "cdt current",
442 "pci target",
443 "line / byte",
444 };
445 u32 risc;
446 unsigned int i,j,n;
447
448 printk("%s: %s - dma channel status dump\n",
449 core->name,ch->name);
450 for (i = 0; i < ARRAY_SIZE(name); i++)
451 printk("%s: cmds: %-12s: 0x%08x\n",
452 core->name,name[i],
453 cx_read(ch->cmds_start + 4*i));
454 for (i = 0; i < 4; i++) {
455 risc = cx_read(ch->cmds_start + 4 * (i+11));
456 printk("%s: risc%d: ", core->name, i);
457 cx88_risc_decode(risc);
458 }
459 for (i = 0; i < 16; i += n) {
460 risc = cx_read(ch->ctrl_start + 4 * i);
461 printk("%s: iq %x: ", core->name, i);
462 n = cx88_risc_decode(risc);
463 for (j = 1; j < n; j++) {
464 risc = cx_read(ch->ctrl_start + 4 * (i+j));
465 printk("%s: iq %x: 0x%08x [ arg #%d ]\n",
466 core->name, i+j, risc, j);
467 }
468 }
469
470 printk("%s: fifo: 0x%08x -> 0x%x\n",
471 core->name, ch->fifo_start, ch->fifo_start+ch->fifo_size);
472 printk("%s: ctrl: 0x%08x -> 0x%x\n",
473 core->name, ch->ctrl_start, ch->ctrl_start+6*16);
474 printk("%s: ptr1_reg: 0x%08x\n",
475 core->name,cx_read(ch->ptr1_reg));
476 printk("%s: ptr2_reg: 0x%08x\n",
477 core->name,cx_read(ch->ptr2_reg));
478 printk("%s: cnt1_reg: 0x%08x\n",
479 core->name,cx_read(ch->cnt1_reg));
480 printk("%s: cnt2_reg: 0x%08x\n",
481 core->name,cx_read(ch->cnt2_reg));
482}
483
Adrian Bunk408b6642005-05-01 08:59:29 -0700484static char *cx88_pci_irqs[32] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 "vid", "aud", "ts", "vip", "hst", "5", "6", "tm1",
486 "src_dma", "dst_dma", "risc_rd_err", "risc_wr_err",
487 "brdg_err", "src_dma_err", "dst_dma_err", "ipb_dma_err",
488 "i2c", "i2c_rack", "ir_smp", "gpio0", "gpio1"
489};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490
491void cx88_print_irqbits(char *name, char *tag, char **strings,
492 u32 bits, u32 mask)
493{
494 unsigned int i;
495
496 printk(KERN_DEBUG "%s: %s [0x%x]", name, tag, bits);
497 for (i = 0; i < 32; i++) {
498 if (!(bits & (1 << i)))
499 continue;
500 if (strings[i])
501 printk(" %s", strings[i]);
502 else
503 printk(" %d", i);
504 if (!(mask & (1 << i)))
505 continue;
506 printk("*");
507 }
508 printk("\n");
509}
510
511/* ------------------------------------------------------------------ */
512
513int cx88_core_irq(struct cx88_core *core, u32 status)
514{
515 int handled = 0;
516
517 if (status & (1<<18)) {
518 cx88_ir_irq(core);
519 handled++;
520 }
521 if (!handled)
522 cx88_print_irqbits(core->name, "irq pci",
523 cx88_pci_irqs, status,
524 core->pci_irqmask);
525 return handled;
526}
527
528void cx88_wakeup(struct cx88_core *core,
529 struct cx88_dmaqueue *q, u32 count)
530{
531 struct cx88_buffer *buf;
532 int bc;
533
534 for (bc = 0;; bc++) {
535 if (list_empty(&q->active))
536 break;
537 buf = list_entry(q->active.next,
538 struct cx88_buffer, vb.queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 /* count comes from the hw and is is 16bit wide --
540 * this trick handles wrap-arounds correctly for
541 * up to 32767 buffers in flight... */
542 if ((s16) (count - buf->count) < 0)
543 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 do_gettimeofday(&buf->vb.ts);
545 dprintk(2,"[%p/%d] wakeup reg=%d buf=%d\n",buf,buf->vb.i,
546 count, buf->count);
547 buf->vb.state = STATE_DONE;
548 list_del(&buf->vb.queue);
549 wake_up(&buf->vb.done);
550 }
551 if (list_empty(&q->active)) {
552 del_timer(&q->timeout);
553 } else {
554 mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
555 }
556 if (bc != 1)
557 printk("%s: %d buffers handled (should be 1)\n",__FUNCTION__,bc);
558}
559
560void cx88_shutdown(struct cx88_core *core)
561{
562 /* disable RISC controller + IRQs */
563 cx_write(MO_DEV_CNTRL2, 0);
564
565 /* stop dma transfers */
566 cx_write(MO_VID_DMACNTRL, 0x0);
567 cx_write(MO_AUD_DMACNTRL, 0x0);
568 cx_write(MO_TS_DMACNTRL, 0x0);
569 cx_write(MO_VIP_DMACNTRL, 0x0);
570 cx_write(MO_GPHST_DMACNTRL, 0x0);
571
572 /* stop interrupts */
573 cx_write(MO_PCI_INTMSK, 0x0);
574 cx_write(MO_VID_INTMSK, 0x0);
575 cx_write(MO_AUD_INTMSK, 0x0);
576 cx_write(MO_TS_INTMSK, 0x0);
577 cx_write(MO_VIP_INTMSK, 0x0);
578 cx_write(MO_GPHST_INTMSK, 0x0);
579
580 /* stop capturing */
581 cx_write(VID_CAPTURE_CONTROL, 0);
582}
583
584int cx88_reset(struct cx88_core *core)
585{
586 dprintk(1,"%s\n",__FUNCTION__);
587 cx88_shutdown(core);
588
589 /* clear irq status */
590 cx_write(MO_VID_INTSTAT, 0xFFFFFFFF); // Clear PIV int
591 cx_write(MO_PCI_INTSTAT, 0xFFFFFFFF); // Clear PCI int
592 cx_write(MO_INT1_STAT, 0xFFFFFFFF); // Clear RISC int
593
594 /* wait a bit */
595 msleep(100);
596
597 /* init sram */
598 cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH21], 720*4, 0);
599 cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH22], 128, 0);
600 cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH23], 128, 0);
601 cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH24], 128, 0);
602 cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH25], 128, 0);
603 cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH26], 128, 0);
604 cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH28], 188*4, 0);
605
606 /* misc init ... */
607 cx_write(MO_INPUT_FORMAT, ((1 << 13) | // agc enable
608 (1 << 12) | // agc gain
609 (1 << 11) | // adaptibe agc
610 (0 << 10) | // chroma agc
611 (0 << 9) | // ckillen
612 (7)));
613
614 /* setup image format */
615 cx_andor(MO_COLOR_CTRL, 0x4000, 0x4000);
616
617 /* setup FIFO Threshholds */
618 cx_write(MO_PDMA_STHRSH, 0x0807);
619 cx_write(MO_PDMA_DTHRSH, 0x0807);
620
621 /* fixes flashing of image */
622 cx_write(MO_AGC_SYNC_TIP1, 0x0380000F);
623 cx_write(MO_AGC_BACK_VBI, 0x00E00555);
624
625 cx_write(MO_VID_INTSTAT, 0xFFFFFFFF); // Clear PIV int
626 cx_write(MO_PCI_INTSTAT, 0xFFFFFFFF); // Clear PCI int
627 cx_write(MO_INT1_STAT, 0xFFFFFFFF); // Clear RISC int
628
629 /* Reset on-board parts */
630 cx_write(MO_SRST_IO, 0);
631 msleep(10);
632 cx_write(MO_SRST_IO, 1);
633
634 return 0;
635}
636
637/* ------------------------------------------------------------------ */
638
Mauro Carvalho Chehab8d87cb92007-01-20 13:58:17 -0300639static unsigned int inline norm_swidth(struct v4l2_tvnorm *norm)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640{
Mauro Carvalho Chehab315eb9622006-12-17 23:30:47 -0300641 return (norm->id & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 754 : 922;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642}
643
Mauro Carvalho Chehab8d87cb92007-01-20 13:58:17 -0300644static unsigned int inline norm_hdelay(struct v4l2_tvnorm *norm)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645{
Mauro Carvalho Chehab315eb9622006-12-17 23:30:47 -0300646 return (norm->id & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 135 : 186;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647}
648
Mauro Carvalho Chehab8d87cb92007-01-20 13:58:17 -0300649static unsigned int inline norm_vdelay(struct v4l2_tvnorm *norm)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650{
651 return (norm->id & V4L2_STD_625_50) ? 0x24 : 0x18;
652}
653
Mauro Carvalho Chehab8d87cb92007-01-20 13:58:17 -0300654static unsigned int inline norm_fsc8(struct v4l2_tvnorm *norm)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655{
Mauro Carvalho Chehab59dcd942005-06-23 22:04:50 -0700656 if (norm->id & V4L2_STD_PAL_M)
Mauro Carvalho Chehab315eb9622006-12-17 23:30:47 -0300657 return 28604892; // 3.575611 MHz
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658
Mauro Carvalho Chehab315eb9622006-12-17 23:30:47 -0300659 if (norm->id & (V4L2_STD_PAL_Nc))
660 return 28656448; // 3.582056 MHz
661
662 if (norm->id & V4L2_STD_NTSC) // All NTSC/M and variants
663 return 28636360; // 3.57954545 MHz +/- 10 Hz
664
665 /* SECAM have also different sub carrier for chroma,
666 but step_db and step_dr, at cx88_set_tvnorm already handles that.
667
668 The same FSC applies to PAL/BGDKIH, PAL/60, NTSC/4.43 and PAL/N
669 */
670
671 return 35468950; // 4.43361875 MHz +/- 5 Hz
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672}
673
Mauro Carvalho Chehab8d87cb92007-01-20 13:58:17 -0300674static unsigned int inline norm_htotal(struct v4l2_tvnorm *norm)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675{
Mauro Carvalho Chehab59dcd942005-06-23 22:04:50 -0700676
Mauro Carvalho Chehab315eb9622006-12-17 23:30:47 -0300677 unsigned int fsc4=norm_fsc8(norm)/2;
Mauro Carvalho Chehab59dcd942005-06-23 22:04:50 -0700678
Mauro Carvalho Chehab315eb9622006-12-17 23:30:47 -0300679 /* returns 4*FSC / vtotal / frames per seconds */
680 return (norm->id & V4L2_STD_625_50) ?
681 ((fsc4+312)/625+12)/25 :
682 ((fsc4+262)/525*1001+15000)/30000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683}
684
Mauro Carvalho Chehab8d87cb92007-01-20 13:58:17 -0300685static unsigned int inline norm_vbipack(struct v4l2_tvnorm *norm)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686{
Michael Schimek419ac5d2006-05-22 10:32:11 -0300687 return (norm->id & V4L2_STD_625_50) ? 511 : 400;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688}
689
690int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int height,
691 enum v4l2_field field)
692{
693 unsigned int swidth = norm_swidth(core->tvnorm);
694 unsigned int sheight = norm_maxh(core->tvnorm);
695 u32 value;
696
697 dprintk(1,"set_scale: %dx%d [%s%s,%s]\n", width, height,
698 V4L2_FIELD_HAS_TOP(field) ? "T" : "",
699 V4L2_FIELD_HAS_BOTTOM(field) ? "B" : "",
700 core->tvnorm->name);
701 if (!V4L2_FIELD_HAS_BOTH(field))
702 height *= 2;
703
704 // recalc H delay and scale registers
705 value = (width * norm_hdelay(core->tvnorm)) / swidth;
706 value &= 0x3fe;
707 cx_write(MO_HDELAY_EVEN, value);
708 cx_write(MO_HDELAY_ODD, value);
Mauro Carvalho Chehab315eb9622006-12-17 23:30:47 -0300709 dprintk(1,"set_scale: hdelay 0x%04x (width %d)\n", value,swidth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710
711 value = (swidth * 4096 / width) - 4096;
712 cx_write(MO_HSCALE_EVEN, value);
713 cx_write(MO_HSCALE_ODD, value);
714 dprintk(1,"set_scale: hscale 0x%04x\n", value);
715
716 cx_write(MO_HACTIVE_EVEN, width);
717 cx_write(MO_HACTIVE_ODD, width);
718 dprintk(1,"set_scale: hactive 0x%04x\n", width);
719
720 // recalc V scale Register (delay is constant)
721 cx_write(MO_VDELAY_EVEN, norm_vdelay(core->tvnorm));
722 cx_write(MO_VDELAY_ODD, norm_vdelay(core->tvnorm));
723 dprintk(1,"set_scale: vdelay 0x%04x\n", norm_vdelay(core->tvnorm));
724
725 value = (0x10000 - (sheight * 512 / height - 512)) & 0x1fff;
726 cx_write(MO_VSCALE_EVEN, value);
727 cx_write(MO_VSCALE_ODD, value);
728 dprintk(1,"set_scale: vscale 0x%04x\n", value);
729
730 cx_write(MO_VACTIVE_EVEN, sheight);
731 cx_write(MO_VACTIVE_ODD, sheight);
732 dprintk(1,"set_scale: vactive 0x%04x\n", sheight);
733
734 // setup filters
735 value = 0;
736 value |= (1 << 19); // CFILT (default)
737 if (core->tvnorm->id & V4L2_STD_SECAM) {
738 value |= (1 << 15);
739 value |= (1 << 16);
740 }
741 if (INPUT(core->input)->type == CX88_VMUX_SVIDEO)
742 value |= (1 << 13) | (1 << 5);
743 if (V4L2_FIELD_INTERLACED == field)
744 value |= (1 << 3); // VINT (interlaced vertical scaling)
745 if (width < 385)
746 value |= (1 << 0); // 3-tap interpolation
747 if (width < 193)
748 value |= (1 << 1); // 5-tap interpolation
749 if (nocomb)
750 value |= (3 << 5); // disable comb filter
751
752 cx_write(MO_FILTER_EVEN, value);
753 cx_write(MO_FILTER_ODD, value);
754 dprintk(1,"set_scale: filter 0x%04x\n", value);
755
756 return 0;
757}
758
759static const u32 xtal = 28636363;
760
761static int set_pll(struct cx88_core *core, int prescale, u32 ofreq)
762{
763 static u32 pre[] = { 0, 0, 0, 3, 2, 1 };
764 u64 pll;
765 u32 reg;
766 int i;
767
768 if (prescale < 2)
769 prescale = 2;
770 if (prescale > 5)
771 prescale = 5;
772
773 pll = ofreq * 8 * prescale * (u64)(1 << 20);
774 do_div(pll,xtal);
775 reg = (pll & 0x3ffffff) | (pre[prescale] << 26);
776 if (((reg >> 20) & 0x3f) < 14) {
777 printk("%s/0: pll out of range\n",core->name);
778 return -1;
779 }
780
781 dprintk(1,"set_pll: MO_PLL_REG 0x%08x [old=0x%08x,freq=%d]\n",
782 reg, cx_read(MO_PLL_REG), ofreq);
783 cx_write(MO_PLL_REG, reg);
784 for (i = 0; i < 100; i++) {
785 reg = cx_read(MO_DEVICE_STATUS);
786 if (reg & (1<<2)) {
787 dprintk(1,"pll locked [pre=%d,ofreq=%d]\n",
788 prescale,ofreq);
789 return 0;
790 }
791 dprintk(1,"pll not locked yet, waiting ...\n");
792 msleep(10);
793 }
794 dprintk(1,"pll NOT locked [pre=%d,ofreq=%d]\n",prescale,ofreq);
795 return -1;
796}
797
Mauro Carvalho Chehab6f502b82005-12-01 00:51:34 -0800798int cx88_start_audio_dma(struct cx88_core *core)
799{
Marcin Rudowski17801f52006-02-06 09:15:14 -0200800 /* constant 128 made buzz in analog Nicam-stereo for bigger fifo_size */
801 int bpl = cx88_sram_channels[SRAM_CH25].fifo_size/4;
Ricardo Cerqueirae738e352006-08-17 18:40:28 -0300802
803 /* If downstream RISC is enabled, bail out; ALSA is managing DMA */
804 if (cx_read(MO_AUD_DMACNTRL) & 0x10)
805 return 0;
806
Mauro Carvalho Chehab6f502b82005-12-01 00:51:34 -0800807 /* setup fifo + format */
Marcin Rudowski17801f52006-02-06 09:15:14 -0200808 cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH25], bpl, 0);
809 cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH26], bpl, 0);
Mauro Carvalho Chehab6f502b82005-12-01 00:51:34 -0800810
Marcin Rudowski17801f52006-02-06 09:15:14 -0200811 cx_write(MO_AUDD_LNGTH, bpl); /* fifo bpl size */
812 cx_write(MO_AUDR_LNGTH, bpl); /* fifo bpl size */
Mauro Carvalho Chehab6f502b82005-12-01 00:51:34 -0800813
814 /* start dma */
815 cx_write(MO_AUD_DMACNTRL, 0x0003); /* Up and Down fifo enable */
Ricardo Cerqueirae738e352006-08-17 18:40:28 -0300816
Mauro Carvalho Chehab6f502b82005-12-01 00:51:34 -0800817 return 0;
818}
819
820int cx88_stop_audio_dma(struct cx88_core *core)
821{
Ricardo Cerqueirae738e352006-08-17 18:40:28 -0300822 /* If downstream RISC is enabled, bail out; ALSA is managing DMA */
823 if (cx_read(MO_AUD_DMACNTRL) & 0x10)
824 return 0;
825
Mauro Carvalho Chehab6f502b82005-12-01 00:51:34 -0800826 /* stop dma */
827 cx_write(MO_AUD_DMACNTRL, 0x0000);
828
829 return 0;
830}
831
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832static int set_tvaudio(struct cx88_core *core)
833{
Mauro Carvalho Chehab8d87cb92007-01-20 13:58:17 -0300834 struct v4l2_tvnorm *norm = core->tvnorm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835
836 if (CX88_VMUX_TELEVISION != INPUT(core->input)->type)
837 return 0;
838
839 if (V4L2_STD_PAL_BG & norm->id) {
Torsten Seebothb1706b92005-11-08 21:36:27 -0800840 core->tvaudio = WW_BG;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841
842 } else if (V4L2_STD_PAL_DK & norm->id) {
Torsten Seebothb1706b92005-11-08 21:36:27 -0800843 core->tvaudio = WW_DK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844
845 } else if (V4L2_STD_PAL_I & norm->id) {
Torsten Seebothb1706b92005-11-08 21:36:27 -0800846 core->tvaudio = WW_I;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847
848 } else if (V4L2_STD_SECAM_L & norm->id) {
Torsten Seebothb1706b92005-11-08 21:36:27 -0800849 core->tvaudio = WW_L;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850
851 } else if (V4L2_STD_SECAM_DK & norm->id) {
Torsten Seebothb1706b92005-11-08 21:36:27 -0800852 core->tvaudio = WW_DK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853
854 } else if ((V4L2_STD_NTSC_M & norm->id) ||
855 (V4L2_STD_PAL_M & norm->id)) {
856 core->tvaudio = WW_BTSC;
857
858 } else if (V4L2_STD_NTSC_M_JP & norm->id) {
859 core->tvaudio = WW_EIAJ;
860
861 } else {
862 printk("%s/0: tvaudio support needs work for this tv norm [%s], sorry\n",
863 core->name, norm->name);
864 core->tvaudio = 0;
865 return 0;
866 }
867
868 cx_andor(MO_AFECFG_IO, 0x1f, 0x0);
869 cx88_set_tvaudio(core);
Mauro Carvalho Chehabe52e98a2005-09-09 13:03:41 -0700870 /* cx88_set_stereo(dev,V4L2_TUNER_MODE_STEREO); */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871
Mauro Carvalho Chehab6f502b82005-12-01 00:51:34 -0800872/*
873 This should be needed only on cx88-alsa. It seems that some cx88 chips have
874 bugs and does require DMA enabled for it to work.
875 */
876 cx88_start_audio_dma(core);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 return 0;
878}
879
Mauro Carvalho Chehab6f502b82005-12-01 00:51:34 -0800880
881
Mauro Carvalho Chehab8d87cb92007-01-20 13:58:17 -0300882int cx88_set_tvnorm(struct cx88_core *core, struct v4l2_tvnorm *norm)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883{
884 u32 fsc8;
885 u32 adc_clock;
886 u32 vdec_clock;
887 u32 step_db,step_dr;
888 u64 tmp64;
889 u32 bdelay,agcdelay,htotal;
Mauro Carvalho Chehab8d87cb92007-01-20 13:58:17 -0300890 u32 cxiformat, cxoformat;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891
892 core->tvnorm = norm;
893 fsc8 = norm_fsc8(norm);
894 adc_clock = xtal;
895 vdec_clock = fsc8;
896 step_db = fsc8;
897 step_dr = fsc8;
898
Mauro Carvalho Chehab8d87cb92007-01-20 13:58:17 -0300899 if (norm->id & V4L2_STD_NTSC_M_JP) {
900 cxiformat = VideoFormatNTSCJapan;
901 cxoformat = 0x181f0008;
Mauro Carvalho Chehab1427f6b2007-01-20 13:58:20 -0300902 } else if (norm->id & V4L2_STD_NTSC_443) {
903 cxiformat = VideoFormatNTSC443;
904 cxoformat = 0x181f0008;
Mauro Carvalho Chehab8d87cb92007-01-20 13:58:17 -0300905 } else if (norm->id & V4L2_STD_PAL_M) {
906 cxiformat = VideoFormatPALM;
907 cxoformat = 0x1c1f0008;
908 } else if (norm->id & V4L2_STD_PAL_N) {
909 cxiformat = VideoFormatPALN;
910 cxoformat = 0x1c1f0008;
911 } else if (norm->id & V4L2_STD_PAL_Nc) {
912 cxiformat = VideoFormatPALNC;
913 cxoformat = 0x1c1f0008;
914 } else if (norm->id & V4L2_STD_PAL_60) {
915 cxiformat = VideoFormatPAL60;
916 cxoformat = 0x181f0008;
917 } else if (norm->id & V4L2_STD_NTSC) {
918 cxiformat = VideoFormatNTSC;
919 cxoformat = 0x181f0008;
920 } else if (norm->id & V4L2_STD_SECAM) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 step_db = 4250000 * 8;
922 step_dr = 4406250 * 8;
Mauro Carvalho Chehab1427f6b2007-01-20 13:58:20 -0300923
924 cxiformat = VideoFormatSECAM;
925 cxoformat = 0x181f0008;
Mauro Carvalho Chehab8d87cb92007-01-20 13:58:17 -0300926 } else { /* PAL */
927 cxiformat = VideoFormatPAL;
928 cxoformat = 0x181f0008;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 }
930
931 dprintk(1,"set_tvnorm: \"%s\" fsc8=%d adc=%d vdec=%d db/dr=%d/%d\n",
932 norm->name, fsc8, adc_clock, vdec_clock, step_db, step_dr);
933 set_pll(core,2,vdec_clock);
934
935 dprintk(1,"set_tvnorm: MO_INPUT_FORMAT 0x%08x [old=0x%08x]\n",
Mauro Carvalho Chehab8d87cb92007-01-20 13:58:17 -0300936 cxiformat, cx_read(MO_INPUT_FORMAT) & 0x0f);
937 cx_andor(MO_INPUT_FORMAT, 0xf, cxiformat);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 // FIXME: as-is from DScaler
940 dprintk(1,"set_tvnorm: MO_OUTPUT_FORMAT 0x%08x [old=0x%08x]\n",
Mauro Carvalho Chehab8d87cb92007-01-20 13:58:17 -0300941 cxoformat, cx_read(MO_OUTPUT_FORMAT));
942 cx_write(MO_OUTPUT_FORMAT, cxoformat);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943
944 // MO_SCONV_REG = adc clock / video dec clock * 2^17
945 tmp64 = adc_clock * (u64)(1 << 17);
946 do_div(tmp64, vdec_clock);
947 dprintk(1,"set_tvnorm: MO_SCONV_REG 0x%08x [old=0x%08x]\n",
948 (u32)tmp64, cx_read(MO_SCONV_REG));
949 cx_write(MO_SCONV_REG, (u32)tmp64);
950
951 // MO_SUB_STEP = 8 * fsc / video dec clock * 2^22
952 tmp64 = step_db * (u64)(1 << 22);
953 do_div(tmp64, vdec_clock);
954 dprintk(1,"set_tvnorm: MO_SUB_STEP 0x%08x [old=0x%08x]\n",
955 (u32)tmp64, cx_read(MO_SUB_STEP));
956 cx_write(MO_SUB_STEP, (u32)tmp64);
957
958 // MO_SUB_STEP_DR = 8 * 4406250 / video dec clock * 2^22
959 tmp64 = step_dr * (u64)(1 << 22);
960 do_div(tmp64, vdec_clock);
961 dprintk(1,"set_tvnorm: MO_SUB_STEP_DR 0x%08x [old=0x%08x]\n",
962 (u32)tmp64, cx_read(MO_SUB_STEP_DR));
963 cx_write(MO_SUB_STEP_DR, (u32)tmp64);
964
965 // bdelay + agcdelay
966 bdelay = vdec_clock * 65 / 20000000 + 21;
967 agcdelay = vdec_clock * 68 / 20000000 + 15;
968 dprintk(1,"set_tvnorm: MO_AGC_BURST 0x%08x [old=0x%08x,bdelay=%d,agcdelay=%d]\n",
969 (bdelay << 8) | agcdelay, cx_read(MO_AGC_BURST), bdelay, agcdelay);
970 cx_write(MO_AGC_BURST, (bdelay << 8) | agcdelay);
971
972 // htotal
973 tmp64 = norm_htotal(norm) * (u64)vdec_clock;
974 do_div(tmp64, fsc8);
Mauro Carvalho Chehabccbf64b2006-09-29 12:39:36 -0300975 htotal = (u32)tmp64 | (HLNotchFilter4xFsc << 11);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 dprintk(1,"set_tvnorm: MO_HTOTAL 0x%08x [old=0x%08x,htotal=%d]\n",
977 htotal, cx_read(MO_HTOTAL), (u32)tmp64);
978 cx_write(MO_HTOTAL, htotal);
979
Trent Piepho3eb73172006-05-23 23:54:44 -0300980 // vbi stuff, set vbi offset to 10 (for 20 Clk*2 pixels), this makes
981 // the effective vbi offset ~244 samples, the same as the Bt8x8
982 cx_write(MO_VBI_PACKET, (10<<11) | norm_vbipack(norm));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983
984 // this is needed as well to set all tvnorm parameter
985 cx88_set_scale(core, 320, 240, V4L2_FIELD_INTERLACED);
986
987 // audio
988 set_tvaudio(core);
989
990 // tell i2c chips
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 cx88_call_i2c_clients(core,VIDIOC_S_STD,&norm->id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992
993 // done
994 return 0;
995}
996
997/* ------------------------------------------------------------------ */
998
999static int cx88_pci_quirks(char *name, struct pci_dev *pci)
1000{
1001 unsigned int lat = UNSET;
1002 u8 ctrl = 0;
1003 u8 value;
1004
1005 /* check pci quirks */
1006 if (pci_pci_problems & PCIPCI_TRITON) {
1007 printk(KERN_INFO "%s: quirk: PCIPCI_TRITON -- set TBFX\n",
1008 name);
1009 ctrl |= CX88X_EN_TBFX;
1010 }
1011 if (pci_pci_problems & PCIPCI_NATOMA) {
1012 printk(KERN_INFO "%s: quirk: PCIPCI_NATOMA -- set TBFX\n",
1013 name);
1014 ctrl |= CX88X_EN_TBFX;
1015 }
1016 if (pci_pci_problems & PCIPCI_VIAETBF) {
1017 printk(KERN_INFO "%s: quirk: PCIPCI_VIAETBF -- set TBFX\n",
1018 name);
1019 ctrl |= CX88X_EN_TBFX;
1020 }
1021 if (pci_pci_problems & PCIPCI_VSFX) {
1022 printk(KERN_INFO "%s: quirk: PCIPCI_VSFX -- set VSFX\n",
1023 name);
1024 ctrl |= CX88X_EN_VSFX;
1025 }
1026#ifdef PCIPCI_ALIMAGIK
1027 if (pci_pci_problems & PCIPCI_ALIMAGIK) {
1028 printk(KERN_INFO "%s: quirk: PCIPCI_ALIMAGIK -- latency fixup\n",
1029 name);
1030 lat = 0x0A;
1031 }
1032#endif
1033
1034 /* check insmod options */
1035 if (UNSET != latency)
1036 lat = latency;
1037
1038 /* apply stuff */
1039 if (ctrl) {
1040 pci_read_config_byte(pci, CX88X_DEVCTRL, &value);
1041 value |= ctrl;
1042 pci_write_config_byte(pci, CX88X_DEVCTRL, value);
1043 }
1044 if (UNSET != lat) {
1045 printk(KERN_INFO "%s: setting pci latency timer to %d\n",
1046 name, latency);
1047 pci_write_config_byte(pci, PCI_LATENCY_TIMER, latency);
1048 }
1049 return 0;
1050}
1051
1052/* ------------------------------------------------------------------ */
1053
1054struct video_device *cx88_vdev_init(struct cx88_core *core,
1055 struct pci_dev *pci,
1056 struct video_device *template,
1057 char *type)
1058{
1059 struct video_device *vfd;
1060
1061 vfd = video_device_alloc();
1062 if (NULL == vfd)
1063 return NULL;
1064 *vfd = *template;
1065 vfd->minor = -1;
1066 vfd->dev = &pci->dev;
1067 vfd->release = video_device_release;
1068 snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
1069 core->name, type, cx88_boards[core->board].name);
1070 return vfd;
1071}
1072
1073static int get_ressources(struct cx88_core *core, struct pci_dev *pci)
1074{
1075 if (request_mem_region(pci_resource_start(pci,0),
1076 pci_resource_len(pci,0),
1077 core->name))
1078 return 0;
Greg Kroah-Hartman228aef62006-06-12 15:16:52 -07001079 printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx\n",
1080 core->name,(unsigned long long)pci_resource_start(pci,0));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 return -EBUSY;
1082}
1083
1084struct cx88_core* cx88_core_get(struct pci_dev *pci)
1085{
1086 struct cx88_core *core;
1087 struct list_head *item;
1088 int i;
1089
Ingo Molnar1e4baed2006-01-15 07:52:23 -02001090 mutex_lock(&devlist);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 list_for_each(item,&cx88_devlist) {
1092 core = list_entry(item, struct cx88_core, devlist);
1093 if (pci->bus->number != core->pci_bus)
1094 continue;
1095 if (PCI_SLOT(pci->devfn) != core->pci_slot)
1096 continue;
1097
1098 if (0 != get_ressources(core,pci))
1099 goto fail_unlock;
1100 atomic_inc(&core->refcount);
Ingo Molnar1e4baed2006-01-15 07:52:23 -02001101 mutex_unlock(&devlist);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 return core;
1103 }
Panagiotis Issaris74081872006-01-11 19:40:56 -02001104 core = kzalloc(sizeof(*core),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 if (NULL == core)
1106 goto fail_unlock;
1107
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 atomic_inc(&core->refcount);
1109 core->pci_bus = pci->bus->number;
1110 core->pci_slot = PCI_SLOT(pci->devfn);
1111 core->pci_irqmask = 0x00fc00;
Ingo Molnar3593cab2006-02-07 06:49:14 -02001112 mutex_init(&core->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113
1114 core->nr = cx88_devcount++;
1115 sprintf(core->name,"cx88[%d]",core->nr);
1116 if (0 != get_ressources(core,pci)) {
Mauro Carvalho Chehabe52e98a2005-09-09 13:03:41 -07001117 printk(KERN_ERR "CORE %s No more PCI ressources for "
1118 "subsystem: %04x:%04x, board: %s\n",
1119 core->name,pci->subsystem_vendor,
1120 pci->subsystem_device,
1121 cx88_boards[core->board].name);
1122
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 cx88_devcount--;
1124 goto fail_free;
1125 }
1126 list_add_tail(&core->devlist,&cx88_devlist);
1127
1128 /* PCI stuff */
1129 cx88_pci_quirks(core->name, pci);
1130 core->lmmio = ioremap(pci_resource_start(pci,0),
1131 pci_resource_len(pci,0));
1132 core->bmmio = (u8 __iomem *)core->lmmio;
1133
1134 /* board config */
1135 core->board = UNSET;
1136 if (card[core->nr] < cx88_bcount)
1137 core->board = card[core->nr];
1138 for (i = 0; UNSET == core->board && i < cx88_idcount; i++)
1139 if (pci->subsystem_vendor == cx88_subids[i].subvendor &&
1140 pci->subsystem_device == cx88_subids[i].subdevice)
1141 core->board = cx88_subids[i].card;
1142 if (UNSET == core->board) {
1143 core->board = CX88_BOARD_UNKNOWN;
1144 cx88_card_list(core,pci);
1145 }
Mauro Carvalho Chehabe52e98a2005-09-09 13:03:41 -07001146 printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
1147 core->name,pci->subsystem_vendor,
1148 pci->subsystem_device,cx88_boards[core->board].name,
1149 core->board, card[core->nr] == core->board ?
1150 "insmod option" : "autodetected");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151
1152 core->tuner_type = tuner[core->nr];
Mauro Carvalho Chehabb45009b2005-06-23 22:05:03 -07001153 core->radio_type = radio[core->nr];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 if (UNSET == core->tuner_type)
1155 core->tuner_type = cx88_boards[core->board].tuner_type;
Mauro Carvalho Chehabb45009b2005-06-23 22:05:03 -07001156 if (UNSET == core->radio_type)
1157 core->radio_type = cx88_boards[core->board].radio_type;
1158 if (!core->tuner_addr)
1159 core->tuner_addr = cx88_boards[core->board].tuner_addr;
1160 if (!core->radio_addr)
1161 core->radio_addr = cx88_boards[core->board].radio_addr;
1162
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001163 printk(KERN_INFO "TV tuner %d at 0x%02x, Radio tuner %d at 0x%02x\n",
Mauro Carvalho Chehabb45009b2005-06-23 22:05:03 -07001164 core->tuner_type, core->tuner_addr<<1,
1165 core->radio_type, core->radio_addr<<1);
1166
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 core->tda9887_conf = cx88_boards[core->board].tda9887_conf;
1168
1169 /* init hardware */
1170 cx88_reset(core);
Steven Tothaa481a62006-09-14 15:41:13 -03001171 cx88_card_setup_pre_i2c(core);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 cx88_i2c_init(core,pci);
Michael Krufky87f07832005-11-08 21:36:19 -08001173 cx88_call_i2c_clients (core, TUNER_SET_STANDBY, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 cx88_card_setup(core);
1175 cx88_ir_init(core,pci);
1176
Ingo Molnar1e4baed2006-01-15 07:52:23 -02001177 mutex_unlock(&devlist);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 return core;
1179
1180fail_free:
1181 kfree(core);
1182fail_unlock:
Ingo Molnar1e4baed2006-01-15 07:52:23 -02001183 mutex_unlock(&devlist);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 return NULL;
1185}
1186
1187void cx88_core_put(struct cx88_core *core, struct pci_dev *pci)
1188{
1189 release_mem_region(pci_resource_start(pci,0),
1190 pci_resource_len(pci,0));
1191
1192 if (!atomic_dec_and_test(&core->refcount))
1193 return;
1194
Ingo Molnar1e4baed2006-01-15 07:52:23 -02001195 mutex_lock(&devlist);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196 cx88_ir_fini(core);
1197 if (0 == core->i2c_rc)
Jean Delvare32697112006-12-10 21:21:33 +01001198 i2c_del_adapter(&core->i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199 list_del(&core->devlist);
1200 iounmap(core->lmmio);
1201 cx88_devcount--;
Ingo Molnar1e4baed2006-01-15 07:52:23 -02001202 mutex_unlock(&devlist);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 kfree(core);
1204}
1205
1206/* ------------------------------------------------------------------ */
1207
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208EXPORT_SYMBOL(cx88_print_irqbits);
1209
1210EXPORT_SYMBOL(cx88_core_irq);
1211EXPORT_SYMBOL(cx88_wakeup);
1212EXPORT_SYMBOL(cx88_reset);
1213EXPORT_SYMBOL(cx88_shutdown);
1214
1215EXPORT_SYMBOL(cx88_risc_buffer);
1216EXPORT_SYMBOL(cx88_risc_databuffer);
1217EXPORT_SYMBOL(cx88_risc_stopper);
1218EXPORT_SYMBOL(cx88_free_buffer);
1219
1220EXPORT_SYMBOL(cx88_sram_channels);
1221EXPORT_SYMBOL(cx88_sram_channel_setup);
1222EXPORT_SYMBOL(cx88_sram_channel_dump);
1223
1224EXPORT_SYMBOL(cx88_set_tvnorm);
1225EXPORT_SYMBOL(cx88_set_scale);
1226
1227EXPORT_SYMBOL(cx88_vdev_init);
1228EXPORT_SYMBOL(cx88_core_get);
1229EXPORT_SYMBOL(cx88_core_put);
1230
1231/*
1232 * Local variables:
1233 * c-basic-offset: 8
1234 * End:
Mauro Carvalho Chehabe52e98a2005-09-09 13:03:41 -07001235 * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 */