blob: 18997361c75ab574e9807d5918e999625e91d069 [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 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23#include <linux/init.h>
24#include <linux/list.h>
25#include <linux/module.h>
26#include <linux/moduleparam.h>
27#include <linux/kernel.h>
28#include <linux/slab.h>
29#include <linux/kmod.h>
30#include <linux/sound.h>
31#include <linux/interrupt.h>
32#include <linux/pci.h>
33#include <linux/delay.h>
Mauro Carvalho Chehab98f30ed2005-11-08 21:37:17 -080034#include <linux/videodev2.h>
Ingo Molnar1e4baed2006-01-15 07:52:23 -020035#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036
37#include "cx88.h"
Michael Krufky5e453dc2006-01-09 15:32:31 -020038#include <media/v4l2-common.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039
40MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards");
41MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
42MODULE_LICENSE("GPL");
43
44/* ------------------------------------------------------------------ */
45
46static unsigned int core_debug = 0;
47module_param(core_debug,int,0644);
48MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
49
50static unsigned int latency = UNSET;
51module_param(latency,int,0444);
52MODULE_PARM_DESC(latency,"pci latency timer");
53
54static unsigned int tuner[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
Mauro Carvalho Chehabb45009b2005-06-23 22:05:03 -070055static unsigned int radio[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
Linus Torvalds1da177e2005-04-16 15:20:36 -070056static unsigned int card[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
57
58module_param_array(tuner, int, NULL, 0444);
Mauro Carvalho Chehabb45009b2005-06-23 22:05:03 -070059module_param_array(radio, int, NULL, 0444);
Linus Torvalds1da177e2005-04-16 15:20:36 -070060module_param_array(card, int, NULL, 0444);
61
62MODULE_PARM_DESC(tuner,"tuner type");
Mauro Carvalho Chehabb45009b2005-06-23 22:05:03 -070063MODULE_PARM_DESC(radio,"radio tuner type");
Linus Torvalds1da177e2005-04-16 15:20:36 -070064MODULE_PARM_DESC(card,"card type");
65
66static unsigned int nicam = 0;
67module_param(nicam,int,0644);
68MODULE_PARM_DESC(nicam,"tv audio is nicam");
69
70static unsigned int nocomb = 0;
71module_param(nocomb,int,0644);
72MODULE_PARM_DESC(nocomb,"disable comb filter");
73
74#define dprintk(level,fmt, arg...) if (core_debug >= level) \
75 printk(KERN_DEBUG "%s: " fmt, core->name , ## arg)
76
77static unsigned int cx88_devcount;
78static LIST_HEAD(cx88_devlist);
Ingo Molnar1e4baed2006-01-15 07:52:23 -020079static DEFINE_MUTEX(devlist);
Linus Torvalds1da177e2005-04-16 15:20:36 -070080
Linus Torvalds1da177e2005-04-16 15:20:36 -070081#define NO_SYNC_LINE (-1U)
82
83static u32* cx88_risc_field(u32 *rp, struct scatterlist *sglist,
84 unsigned int offset, u32 sync_line,
85 unsigned int bpl, unsigned int padding,
86 unsigned int lines)
87{
88 struct scatterlist *sg;
89 unsigned int line,todo;
90
91 /* sync instruction */
92 if (sync_line != NO_SYNC_LINE)
93 *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line);
94
95 /* scan lines */
96 sg = sglist;
97 for (line = 0; line < lines; line++) {
98 while (offset && offset >= sg_dma_len(sg)) {
99 offset -= sg_dma_len(sg);
100 sg++;
101 }
102 if (bpl <= sg_dma_len(sg)-offset) {
103 /* fits into current chunk */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800104 *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|RISC_EOL|bpl);
105 *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
106 offset+=bpl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 } else {
Peter Naullsd1009bd2006-08-08 09:10:05 -0300108 /* scanline needs to be split */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800109 todo = bpl;
110 *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 (sg_dma_len(sg)-offset));
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800112 *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
113 todo -= (sg_dma_len(sg)-offset);
114 offset = 0;
115 sg++;
116 while (todo > sg_dma_len(sg)) {
Mauro Carvalho Chehabf2421ca2005-11-08 21:37:45 -0800117 *(rp++)=cpu_to_le32(RISC_WRITE|
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118 sg_dma_len(sg));
Mauro Carvalho Chehabf2421ca2005-11-08 21:37:45 -0800119 *(rp++)=cpu_to_le32(sg_dma_address(sg));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120 todo -= sg_dma_len(sg);
121 sg++;
122 }
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800123 *(rp++)=cpu_to_le32(RISC_WRITE|RISC_EOL|todo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124 *(rp++)=cpu_to_le32(sg_dma_address(sg));
125 offset += todo;
126 }
127 offset += padding;
128 }
129
130 return rp;
131}
132
133int cx88_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
134 struct scatterlist *sglist,
135 unsigned int top_offset, unsigned int bottom_offset,
136 unsigned int bpl, unsigned int padding, unsigned int lines)
137{
138 u32 instructions,fields;
139 u32 *rp;
140 int rc;
141
142 fields = 0;
143 if (UNSET != top_offset)
144 fields++;
145 if (UNSET != bottom_offset)
146 fields++;
147
148 /* estimate risc mem: worst case is one write per page border +
Duncan Sandsbba3ad72006-04-11 10:18:57 -0300149 one write per scan line + syncs + jump (all 2 dwords). Padding
150 can cause next bpl to start close to a page border. First DMA
151 region may be smaller than PAGE_SIZE */
152 instructions = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + lines);
153 instructions += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 if ((rc = btcx_riscmem_alloc(pci,risc,instructions*8)) < 0)
155 return rc;
156
157 /* write risc instructions */
158 rp = risc->cpu;
159 if (UNSET != top_offset)
160 rp = cx88_risc_field(rp, sglist, top_offset, 0,
161 bpl, padding, lines);
162 if (UNSET != bottom_offset)
163 rp = cx88_risc_field(rp, sglist, bottom_offset, 0x200,
164 bpl, padding, lines);
165
166 /* save pointer to jmp instruction address */
167 risc->jmp = rp;
Duncan Sands4a287cf2006-02-27 00:09:48 -0300168 BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169 return 0;
170}
171
172int cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
173 struct scatterlist *sglist, unsigned int bpl,
174 unsigned int lines)
175{
176 u32 instructions;
177 u32 *rp;
178 int rc;
179
180 /* estimate risc mem: worst case is one write per page border +
Duncan Sandsbba3ad72006-04-11 10:18:57 -0300181 one write per scan line + syncs + jump (all 2 dwords). Here
182 there is no padding and no sync. First DMA region may be smaller
183 than PAGE_SIZE */
184 instructions = 1 + (bpl * lines) / PAGE_SIZE + lines;
185 instructions += 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186 if ((rc = btcx_riscmem_alloc(pci,risc,instructions*8)) < 0)
187 return rc;
188
189 /* write risc instructions */
190 rp = risc->cpu;
191 rp = cx88_risc_field(rp, sglist, 0, NO_SYNC_LINE, bpl, 0, lines);
192
193 /* save pointer to jmp instruction address */
194 risc->jmp = rp;
Duncan Sands4a287cf2006-02-27 00:09:48 -0300195 BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 return 0;
197}
198
199int cx88_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
200 u32 reg, u32 mask, u32 value)
201{
202 u32 *rp;
203 int rc;
204
205 if ((rc = btcx_riscmem_alloc(pci, risc, 4*16)) < 0)
206 return rc;
207
208 /* write risc instructions */
209 rp = risc->cpu;
210 *(rp++) = cpu_to_le32(RISC_WRITECR | RISC_IRQ2 | RISC_IMM);
211 *(rp++) = cpu_to_le32(reg);
212 *(rp++) = cpu_to_le32(value);
213 *(rp++) = cpu_to_le32(mask);
214 *(rp++) = cpu_to_le32(RISC_JUMP);
215 *(rp++) = cpu_to_le32(risc->dma);
216 return 0;
217}
218
219void
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -0300220cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221{
Eric Sesterhennae246012006-03-13 13:17:11 -0300222 BUG_ON(in_interrupt());
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 videobuf_waiton(&buf->vb,0,0);
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -0300224 videobuf_dma_unmap(q, &buf->vb.dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 videobuf_dma_free(&buf->vb.dma);
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -0300226 btcx_riscmem_free((struct pci_dev *)q->dev, &buf->risc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 buf->vb.state = STATE_NEEDS_INIT;
228}
229
230/* ------------------------------------------------------------------ */
231/* our SRAM memory layout */
232
233/* we are going to put all thr risc programs into host memory, so we
234 * can use the whole SDRAM for the DMA fifos. To simplify things, we
235 * use a static memory layout. That surely will waste memory in case
236 * we don't use all DMA channels at the same time (which will be the
237 * case most of the time). But that still gives us enougth FIFO space
238 * to be able to deal with insane long pci latencies ...
239 *
240 * FIFO space allocations:
241 * channel 21 (y video) - 10.0k
242 * channel 22 (u video) - 2.0k
243 * channel 23 (v video) - 2.0k
244 * channel 24 (vbi) - 4.0k
Mauro Carvalho Chehabb7f355d2006-01-09 15:32:44 -0200245 * channels 25+26 (audio) - 4.0k
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 * channel 28 (mpeg) - 4.0k
Mauro Carvalho Chehabb7f355d2006-01-09 15:32:44 -0200247 * TOTAL = 29.0k
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 *
249 * Every channel has 160 bytes control data (64 bytes instruction
250 * queue and 6 CDT entries), which is close to 2k total.
251 *
252 * Address layout:
253 * 0x0000 - 0x03ff CMDs / reserved
254 * 0x0400 - 0x0bff instruction queues + CDs
255 * 0x0c00 - FIFOs
256 */
257
258struct sram_channel cx88_sram_channels[] = {
259 [SRAM_CH21] = {
260 .name = "video y / packed",
261 .cmds_start = 0x180040,
262 .ctrl_start = 0x180400,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800263 .cdt = 0x180400 + 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 .fifo_start = 0x180c00,
265 .fifo_size = 0x002800,
266 .ptr1_reg = MO_DMA21_PTR1,
267 .ptr2_reg = MO_DMA21_PTR2,
268 .cnt1_reg = MO_DMA21_CNT1,
269 .cnt2_reg = MO_DMA21_CNT2,
270 },
271 [SRAM_CH22] = {
272 .name = "video u",
273 .cmds_start = 0x180080,
274 .ctrl_start = 0x1804a0,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800275 .cdt = 0x1804a0 + 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 .fifo_start = 0x183400,
277 .fifo_size = 0x000800,
278 .ptr1_reg = MO_DMA22_PTR1,
279 .ptr2_reg = MO_DMA22_PTR2,
280 .cnt1_reg = MO_DMA22_CNT1,
281 .cnt2_reg = MO_DMA22_CNT2,
282 },
283 [SRAM_CH23] = {
284 .name = "video v",
285 .cmds_start = 0x1800c0,
286 .ctrl_start = 0x180540,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800287 .cdt = 0x180540 + 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 .fifo_start = 0x183c00,
289 .fifo_size = 0x000800,
290 .ptr1_reg = MO_DMA23_PTR1,
291 .ptr2_reg = MO_DMA23_PTR2,
292 .cnt1_reg = MO_DMA23_CNT1,
293 .cnt2_reg = MO_DMA23_CNT2,
294 },
295 [SRAM_CH24] = {
296 .name = "vbi",
297 .cmds_start = 0x180100,
298 .ctrl_start = 0x1805e0,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800299 .cdt = 0x1805e0 + 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 .fifo_start = 0x184400,
301 .fifo_size = 0x001000,
302 .ptr1_reg = MO_DMA24_PTR1,
303 .ptr2_reg = MO_DMA24_PTR2,
304 .cnt1_reg = MO_DMA24_CNT1,
305 .cnt2_reg = MO_DMA24_CNT2,
306 },
307 [SRAM_CH25] = {
308 .name = "audio from",
309 .cmds_start = 0x180140,
310 .ctrl_start = 0x180680,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800311 .cdt = 0x180680 + 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 .fifo_start = 0x185400,
Mauro Carvalho Chehabb7f355d2006-01-09 15:32:44 -0200313 .fifo_size = 0x001000,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 .ptr1_reg = MO_DMA25_PTR1,
315 .ptr2_reg = MO_DMA25_PTR2,
316 .cnt1_reg = MO_DMA25_CNT1,
317 .cnt2_reg = MO_DMA25_CNT2,
318 },
319 [SRAM_CH26] = {
320 .name = "audio to",
321 .cmds_start = 0x180180,
322 .ctrl_start = 0x180720,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800323 .cdt = 0x180680 + 64, /* same as audio IN */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 .fifo_start = 0x185400, /* same as audio IN */
Mauro Carvalho Chehabb7f355d2006-01-09 15:32:44 -0200325 .fifo_size = 0x001000, /* same as audio IN */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 .ptr1_reg = MO_DMA26_PTR1,
327 .ptr2_reg = MO_DMA26_PTR2,
328 .cnt1_reg = MO_DMA26_CNT1,
329 .cnt2_reg = MO_DMA26_CNT2,
330 },
331 [SRAM_CH28] = {
332 .name = "mpeg",
333 .cmds_start = 0x180200,
334 .ctrl_start = 0x1807C0,
335 .cdt = 0x1807C0 + 64,
Mauro Carvalho Chehabb7f355d2006-01-09 15:32:44 -0200336 .fifo_start = 0x186400,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 .fifo_size = 0x001000,
338 .ptr1_reg = MO_DMA28_PTR1,
339 .ptr2_reg = MO_DMA28_PTR2,
340 .cnt1_reg = MO_DMA28_CNT1,
341 .cnt2_reg = MO_DMA28_CNT2,
342 },
343};
344
345int cx88_sram_channel_setup(struct cx88_core *core,
346 struct sram_channel *ch,
347 unsigned int bpl, u32 risc)
348{
349 unsigned int i,lines;
350 u32 cdt;
351
352 bpl = (bpl + 7) & ~7; /* alignment */
353 cdt = ch->cdt;
354 lines = ch->fifo_size / bpl;
355 if (lines > 6)
356 lines = 6;
357 BUG_ON(lines < 2);
358
359 /* write CDT */
360 for (i = 0; i < lines; i++)
361 cx_write(cdt + 16*i, ch->fifo_start + bpl*i);
362
363 /* write CMDS */
364 cx_write(ch->cmds_start + 0, risc);
365 cx_write(ch->cmds_start + 4, cdt);
366 cx_write(ch->cmds_start + 8, (lines*16) >> 3);
367 cx_write(ch->cmds_start + 12, ch->ctrl_start);
368 cx_write(ch->cmds_start + 16, 64 >> 2);
369 for (i = 20; i < 64; i += 4)
370 cx_write(ch->cmds_start + i, 0);
371
372 /* fill registers */
373 cx_write(ch->ptr1_reg, ch->fifo_start);
374 cx_write(ch->ptr2_reg, cdt);
375 cx_write(ch->cnt1_reg, (bpl >> 3) -1);
376 cx_write(ch->cnt2_reg, (lines*16) >> 3);
377
378 dprintk(2,"sram setup %s: bpl=%d lines=%d\n", ch->name, bpl, lines);
379 return 0;
380}
381
382/* ------------------------------------------------------------------ */
383/* debug helper code */
384
Peter Hagervallf9e7a022005-11-08 21:36:29 -0800385static int cx88_risc_decode(u32 risc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386{
387 static char *instr[16] = {
388 [ RISC_SYNC >> 28 ] = "sync",
389 [ RISC_WRITE >> 28 ] = "write",
390 [ RISC_WRITEC >> 28 ] = "writec",
391 [ RISC_READ >> 28 ] = "read",
392 [ RISC_READC >> 28 ] = "readc",
393 [ RISC_JUMP >> 28 ] = "jump",
394 [ RISC_SKIP >> 28 ] = "skip",
395 [ RISC_WRITERM >> 28 ] = "writerm",
396 [ RISC_WRITECM >> 28 ] = "writecm",
397 [ RISC_WRITECR >> 28 ] = "writecr",
398 };
399 static int incr[16] = {
400 [ RISC_WRITE >> 28 ] = 2,
401 [ RISC_JUMP >> 28 ] = 2,
402 [ RISC_WRITERM >> 28 ] = 3,
403 [ RISC_WRITECM >> 28 ] = 3,
404 [ RISC_WRITECR >> 28 ] = 4,
405 };
406 static char *bits[] = {
407 "12", "13", "14", "resync",
408 "cnt0", "cnt1", "18", "19",
409 "20", "21", "22", "23",
410 "irq1", "irq2", "eol", "sol",
411 };
412 int i;
413
414 printk("0x%08x [ %s", risc,
415 instr[risc >> 28] ? instr[risc >> 28] : "INVALID");
416 for (i = ARRAY_SIZE(bits)-1; i >= 0; i--)
417 if (risc & (1 << (i + 12)))
418 printk(" %s",bits[i]);
419 printk(" count=%d ]\n", risc & 0xfff);
420 return incr[risc >> 28] ? incr[risc >> 28] : 1;
421}
422
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423
424void cx88_sram_channel_dump(struct cx88_core *core,
425 struct sram_channel *ch)
426{
427 static char *name[] = {
428 "initial risc",
429 "cdt base",
430 "cdt size",
431 "iq base",
432 "iq size",
433 "risc pc",
434 "iq wr ptr",
435 "iq rd ptr",
436 "cdt current",
437 "pci target",
438 "line / byte",
439 };
440 u32 risc;
441 unsigned int i,j,n;
442
443 printk("%s: %s - dma channel status dump\n",
444 core->name,ch->name);
445 for (i = 0; i < ARRAY_SIZE(name); i++)
446 printk("%s: cmds: %-12s: 0x%08x\n",
447 core->name,name[i],
448 cx_read(ch->cmds_start + 4*i));
449 for (i = 0; i < 4; i++) {
450 risc = cx_read(ch->cmds_start + 4 * (i+11));
451 printk("%s: risc%d: ", core->name, i);
452 cx88_risc_decode(risc);
453 }
454 for (i = 0; i < 16; i += n) {
455 risc = cx_read(ch->ctrl_start + 4 * i);
456 printk("%s: iq %x: ", core->name, i);
457 n = cx88_risc_decode(risc);
458 for (j = 1; j < n; j++) {
459 risc = cx_read(ch->ctrl_start + 4 * (i+j));
460 printk("%s: iq %x: 0x%08x [ arg #%d ]\n",
461 core->name, i+j, risc, j);
462 }
463 }
464
465 printk("%s: fifo: 0x%08x -> 0x%x\n",
466 core->name, ch->fifo_start, ch->fifo_start+ch->fifo_size);
467 printk("%s: ctrl: 0x%08x -> 0x%x\n",
468 core->name, ch->ctrl_start, ch->ctrl_start+6*16);
469 printk("%s: ptr1_reg: 0x%08x\n",
470 core->name,cx_read(ch->ptr1_reg));
471 printk("%s: ptr2_reg: 0x%08x\n",
472 core->name,cx_read(ch->ptr2_reg));
473 printk("%s: cnt1_reg: 0x%08x\n",
474 core->name,cx_read(ch->cnt1_reg));
475 printk("%s: cnt2_reg: 0x%08x\n",
476 core->name,cx_read(ch->cnt2_reg));
477}
478
Adrian Bunk408b6642005-05-01 08:59:29 -0700479static char *cx88_pci_irqs[32] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 "vid", "aud", "ts", "vip", "hst", "5", "6", "tm1",
481 "src_dma", "dst_dma", "risc_rd_err", "risc_wr_err",
482 "brdg_err", "src_dma_err", "dst_dma_err", "ipb_dma_err",
483 "i2c", "i2c_rack", "ir_smp", "gpio0", "gpio1"
484};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485
486void cx88_print_irqbits(char *name, char *tag, char **strings,
487 u32 bits, u32 mask)
488{
489 unsigned int i;
490
491 printk(KERN_DEBUG "%s: %s [0x%x]", name, tag, bits);
492 for (i = 0; i < 32; i++) {
493 if (!(bits & (1 << i)))
494 continue;
495 if (strings[i])
496 printk(" %s", strings[i]);
497 else
498 printk(" %d", i);
499 if (!(mask & (1 << i)))
500 continue;
501 printk("*");
502 }
503 printk("\n");
504}
505
506/* ------------------------------------------------------------------ */
507
508int cx88_core_irq(struct cx88_core *core, u32 status)
509{
510 int handled = 0;
511
512 if (status & (1<<18)) {
513 cx88_ir_irq(core);
514 handled++;
515 }
516 if (!handled)
517 cx88_print_irqbits(core->name, "irq pci",
518 cx88_pci_irqs, status,
519 core->pci_irqmask);
520 return handled;
521}
522
523void cx88_wakeup(struct cx88_core *core,
524 struct cx88_dmaqueue *q, u32 count)
525{
526 struct cx88_buffer *buf;
527 int bc;
528
529 for (bc = 0;; bc++) {
530 if (list_empty(&q->active))
531 break;
532 buf = list_entry(q->active.next,
533 struct cx88_buffer, vb.queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 /* count comes from the hw and is is 16bit wide --
535 * this trick handles wrap-arounds correctly for
536 * up to 32767 buffers in flight... */
537 if ((s16) (count - buf->count) < 0)
538 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 do_gettimeofday(&buf->vb.ts);
540 dprintk(2,"[%p/%d] wakeup reg=%d buf=%d\n",buf,buf->vb.i,
541 count, buf->count);
542 buf->vb.state = STATE_DONE;
543 list_del(&buf->vb.queue);
544 wake_up(&buf->vb.done);
545 }
546 if (list_empty(&q->active)) {
547 del_timer(&q->timeout);
548 } else {
549 mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
550 }
551 if (bc != 1)
552 printk("%s: %d buffers handled (should be 1)\n",__FUNCTION__,bc);
553}
554
555void cx88_shutdown(struct cx88_core *core)
556{
557 /* disable RISC controller + IRQs */
558 cx_write(MO_DEV_CNTRL2, 0);
559
560 /* stop dma transfers */
561 cx_write(MO_VID_DMACNTRL, 0x0);
562 cx_write(MO_AUD_DMACNTRL, 0x0);
563 cx_write(MO_TS_DMACNTRL, 0x0);
564 cx_write(MO_VIP_DMACNTRL, 0x0);
565 cx_write(MO_GPHST_DMACNTRL, 0x0);
566
567 /* stop interrupts */
568 cx_write(MO_PCI_INTMSK, 0x0);
569 cx_write(MO_VID_INTMSK, 0x0);
570 cx_write(MO_AUD_INTMSK, 0x0);
571 cx_write(MO_TS_INTMSK, 0x0);
572 cx_write(MO_VIP_INTMSK, 0x0);
573 cx_write(MO_GPHST_INTMSK, 0x0);
574
575 /* stop capturing */
576 cx_write(VID_CAPTURE_CONTROL, 0);
577}
578
579int cx88_reset(struct cx88_core *core)
580{
581 dprintk(1,"%s\n",__FUNCTION__);
582 cx88_shutdown(core);
583
584 /* clear irq status */
585 cx_write(MO_VID_INTSTAT, 0xFFFFFFFF); // Clear PIV int
586 cx_write(MO_PCI_INTSTAT, 0xFFFFFFFF); // Clear PCI int
587 cx_write(MO_INT1_STAT, 0xFFFFFFFF); // Clear RISC int
588
589 /* wait a bit */
590 msleep(100);
591
592 /* init sram */
593 cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH21], 720*4, 0);
594 cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH22], 128, 0);
595 cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH23], 128, 0);
596 cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH24], 128, 0);
597 cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH25], 128, 0);
598 cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH26], 128, 0);
599 cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH28], 188*4, 0);
600
601 /* misc init ... */
602 cx_write(MO_INPUT_FORMAT, ((1 << 13) | // agc enable
603 (1 << 12) | // agc gain
604 (1 << 11) | // adaptibe agc
605 (0 << 10) | // chroma agc
606 (0 << 9) | // ckillen
607 (7)));
608
609 /* setup image format */
610 cx_andor(MO_COLOR_CTRL, 0x4000, 0x4000);
611
612 /* setup FIFO Threshholds */
613 cx_write(MO_PDMA_STHRSH, 0x0807);
614 cx_write(MO_PDMA_DTHRSH, 0x0807);
615
616 /* fixes flashing of image */
617 cx_write(MO_AGC_SYNC_TIP1, 0x0380000F);
618 cx_write(MO_AGC_BACK_VBI, 0x00E00555);
619
620 cx_write(MO_VID_INTSTAT, 0xFFFFFFFF); // Clear PIV int
621 cx_write(MO_PCI_INTSTAT, 0xFFFFFFFF); // Clear PCI int
622 cx_write(MO_INT1_STAT, 0xFFFFFFFF); // Clear RISC int
623
624 /* Reset on-board parts */
625 cx_write(MO_SRST_IO, 0);
626 msleep(10);
627 cx_write(MO_SRST_IO, 1);
628
629 return 0;
630}
631
632/* ------------------------------------------------------------------ */
633
634static unsigned int inline norm_swidth(struct cx88_tvnorm *norm)
635{
Mauro Carvalho Chehab315eb9622006-12-17 23:30:47 -0300636 return (norm->id & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 754 : 922;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637}
638
639static unsigned int inline norm_hdelay(struct cx88_tvnorm *norm)
640{
Mauro Carvalho Chehab315eb9622006-12-17 23:30:47 -0300641 return (norm->id & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 135 : 186;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642}
643
644static unsigned int inline norm_vdelay(struct cx88_tvnorm *norm)
645{
646 return (norm->id & V4L2_STD_625_50) ? 0x24 : 0x18;
647}
648
649static unsigned int inline norm_fsc8(struct cx88_tvnorm *norm)
650{
Mauro Carvalho Chehab59dcd942005-06-23 22:04:50 -0700651 if (norm->id & V4L2_STD_PAL_M)
Mauro Carvalho Chehab315eb9622006-12-17 23:30:47 -0300652 return 28604892; // 3.575611 MHz
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653
Mauro Carvalho Chehab315eb9622006-12-17 23:30:47 -0300654 if (norm->id & (V4L2_STD_PAL_Nc))
655 return 28656448; // 3.582056 MHz
656
657 if (norm->id & V4L2_STD_NTSC) // All NTSC/M and variants
658 return 28636360; // 3.57954545 MHz +/- 10 Hz
659
660 /* SECAM have also different sub carrier for chroma,
661 but step_db and step_dr, at cx88_set_tvnorm already handles that.
662
663 The same FSC applies to PAL/BGDKIH, PAL/60, NTSC/4.43 and PAL/N
664 */
665
666 return 35468950; // 4.43361875 MHz +/- 5 Hz
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667}
668
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669static unsigned int inline norm_htotal(struct cx88_tvnorm *norm)
670{
Mauro Carvalho Chehab59dcd942005-06-23 22:04:50 -0700671
Mauro Carvalho Chehab315eb9622006-12-17 23:30:47 -0300672 unsigned int fsc4=norm_fsc8(norm)/2;
Mauro Carvalho Chehab59dcd942005-06-23 22:04:50 -0700673
Mauro Carvalho Chehab315eb9622006-12-17 23:30:47 -0300674 /* returns 4*FSC / vtotal / frames per seconds */
675 return (norm->id & V4L2_STD_625_50) ?
676 ((fsc4+312)/625+12)/25 :
677 ((fsc4+262)/525*1001+15000)/30000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678}
679
680static unsigned int inline norm_vbipack(struct cx88_tvnorm *norm)
681{
Michael Schimek419ac5d2006-05-22 10:32:11 -0300682 return (norm->id & V4L2_STD_625_50) ? 511 : 400;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683}
684
685int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int height,
686 enum v4l2_field field)
687{
688 unsigned int swidth = norm_swidth(core->tvnorm);
689 unsigned int sheight = norm_maxh(core->tvnorm);
690 u32 value;
691
692 dprintk(1,"set_scale: %dx%d [%s%s,%s]\n", width, height,
693 V4L2_FIELD_HAS_TOP(field) ? "T" : "",
694 V4L2_FIELD_HAS_BOTTOM(field) ? "B" : "",
695 core->tvnorm->name);
696 if (!V4L2_FIELD_HAS_BOTH(field))
697 height *= 2;
698
699 // recalc H delay and scale registers
700 value = (width * norm_hdelay(core->tvnorm)) / swidth;
701 value &= 0x3fe;
702 cx_write(MO_HDELAY_EVEN, value);
703 cx_write(MO_HDELAY_ODD, value);
Mauro Carvalho Chehab315eb9622006-12-17 23:30:47 -0300704 dprintk(1,"set_scale: hdelay 0x%04x (width %d)\n", value,swidth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705
706 value = (swidth * 4096 / width) - 4096;
707 cx_write(MO_HSCALE_EVEN, value);
708 cx_write(MO_HSCALE_ODD, value);
709 dprintk(1,"set_scale: hscale 0x%04x\n", value);
710
711 cx_write(MO_HACTIVE_EVEN, width);
712 cx_write(MO_HACTIVE_ODD, width);
713 dprintk(1,"set_scale: hactive 0x%04x\n", width);
714
715 // recalc V scale Register (delay is constant)
716 cx_write(MO_VDELAY_EVEN, norm_vdelay(core->tvnorm));
717 cx_write(MO_VDELAY_ODD, norm_vdelay(core->tvnorm));
718 dprintk(1,"set_scale: vdelay 0x%04x\n", norm_vdelay(core->tvnorm));
719
720 value = (0x10000 - (sheight * 512 / height - 512)) & 0x1fff;
721 cx_write(MO_VSCALE_EVEN, value);
722 cx_write(MO_VSCALE_ODD, value);
723 dprintk(1,"set_scale: vscale 0x%04x\n", value);
724
725 cx_write(MO_VACTIVE_EVEN, sheight);
726 cx_write(MO_VACTIVE_ODD, sheight);
727 dprintk(1,"set_scale: vactive 0x%04x\n", sheight);
728
729 // setup filters
730 value = 0;
731 value |= (1 << 19); // CFILT (default)
732 if (core->tvnorm->id & V4L2_STD_SECAM) {
733 value |= (1 << 15);
734 value |= (1 << 16);
735 }
736 if (INPUT(core->input)->type == CX88_VMUX_SVIDEO)
737 value |= (1 << 13) | (1 << 5);
738 if (V4L2_FIELD_INTERLACED == field)
739 value |= (1 << 3); // VINT (interlaced vertical scaling)
740 if (width < 385)
741 value |= (1 << 0); // 3-tap interpolation
742 if (width < 193)
743 value |= (1 << 1); // 5-tap interpolation
744 if (nocomb)
745 value |= (3 << 5); // disable comb filter
746
747 cx_write(MO_FILTER_EVEN, value);
748 cx_write(MO_FILTER_ODD, value);
749 dprintk(1,"set_scale: filter 0x%04x\n", value);
750
751 return 0;
752}
753
754static const u32 xtal = 28636363;
755
756static int set_pll(struct cx88_core *core, int prescale, u32 ofreq)
757{
758 static u32 pre[] = { 0, 0, 0, 3, 2, 1 };
759 u64 pll;
760 u32 reg;
761 int i;
762
763 if (prescale < 2)
764 prescale = 2;
765 if (prescale > 5)
766 prescale = 5;
767
768 pll = ofreq * 8 * prescale * (u64)(1 << 20);
769 do_div(pll,xtal);
770 reg = (pll & 0x3ffffff) | (pre[prescale] << 26);
771 if (((reg >> 20) & 0x3f) < 14) {
772 printk("%s/0: pll out of range\n",core->name);
773 return -1;
774 }
775
776 dprintk(1,"set_pll: MO_PLL_REG 0x%08x [old=0x%08x,freq=%d]\n",
777 reg, cx_read(MO_PLL_REG), ofreq);
778 cx_write(MO_PLL_REG, reg);
779 for (i = 0; i < 100; i++) {
780 reg = cx_read(MO_DEVICE_STATUS);
781 if (reg & (1<<2)) {
782 dprintk(1,"pll locked [pre=%d,ofreq=%d]\n",
783 prescale,ofreq);
784 return 0;
785 }
786 dprintk(1,"pll not locked yet, waiting ...\n");
787 msleep(10);
788 }
789 dprintk(1,"pll NOT locked [pre=%d,ofreq=%d]\n",prescale,ofreq);
790 return -1;
791}
792
Mauro Carvalho Chehab6f502b82005-12-01 00:51:34 -0800793int cx88_start_audio_dma(struct cx88_core *core)
794{
Marcin Rudowski17801f52006-02-06 09:15:14 -0200795 /* constant 128 made buzz in analog Nicam-stereo for bigger fifo_size */
796 int bpl = cx88_sram_channels[SRAM_CH25].fifo_size/4;
Ricardo Cerqueirae738e352006-08-17 18:40:28 -0300797
798 /* If downstream RISC is enabled, bail out; ALSA is managing DMA */
799 if (cx_read(MO_AUD_DMACNTRL) & 0x10)
800 return 0;
801
Mauro Carvalho Chehab6f502b82005-12-01 00:51:34 -0800802 /* setup fifo + format */
Marcin Rudowski17801f52006-02-06 09:15:14 -0200803 cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH25], bpl, 0);
804 cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH26], bpl, 0);
Mauro Carvalho Chehab6f502b82005-12-01 00:51:34 -0800805
Marcin Rudowski17801f52006-02-06 09:15:14 -0200806 cx_write(MO_AUDD_LNGTH, bpl); /* fifo bpl size */
807 cx_write(MO_AUDR_LNGTH, bpl); /* fifo bpl size */
Mauro Carvalho Chehab6f502b82005-12-01 00:51:34 -0800808
809 /* start dma */
810 cx_write(MO_AUD_DMACNTRL, 0x0003); /* Up and Down fifo enable */
Ricardo Cerqueirae738e352006-08-17 18:40:28 -0300811
Mauro Carvalho Chehab6f502b82005-12-01 00:51:34 -0800812 return 0;
813}
814
815int cx88_stop_audio_dma(struct cx88_core *core)
816{
Ricardo Cerqueirae738e352006-08-17 18:40:28 -0300817 /* If downstream RISC is enabled, bail out; ALSA is managing DMA */
818 if (cx_read(MO_AUD_DMACNTRL) & 0x10)
819 return 0;
820
Mauro Carvalho Chehab6f502b82005-12-01 00:51:34 -0800821 /* stop dma */
822 cx_write(MO_AUD_DMACNTRL, 0x0000);
823
824 return 0;
825}
826
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827static int set_tvaudio(struct cx88_core *core)
828{
829 struct cx88_tvnorm *norm = core->tvnorm;
830
831 if (CX88_VMUX_TELEVISION != INPUT(core->input)->type)
832 return 0;
833
834 if (V4L2_STD_PAL_BG & norm->id) {
Torsten Seebothb1706b92005-11-08 21:36:27 -0800835 core->tvaudio = WW_BG;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836
837 } else if (V4L2_STD_PAL_DK & norm->id) {
Torsten Seebothb1706b92005-11-08 21:36:27 -0800838 core->tvaudio = WW_DK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839
840 } else if (V4L2_STD_PAL_I & norm->id) {
Torsten Seebothb1706b92005-11-08 21:36:27 -0800841 core->tvaudio = WW_I;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842
843 } else if (V4L2_STD_SECAM_L & norm->id) {
Torsten Seebothb1706b92005-11-08 21:36:27 -0800844 core->tvaudio = WW_L;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845
846 } else if (V4L2_STD_SECAM_DK & norm->id) {
Torsten Seebothb1706b92005-11-08 21:36:27 -0800847 core->tvaudio = WW_DK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848
849 } else if ((V4L2_STD_NTSC_M & norm->id) ||
850 (V4L2_STD_PAL_M & norm->id)) {
851 core->tvaudio = WW_BTSC;
852
853 } else if (V4L2_STD_NTSC_M_JP & norm->id) {
854 core->tvaudio = WW_EIAJ;
855
856 } else {
857 printk("%s/0: tvaudio support needs work for this tv norm [%s], sorry\n",
858 core->name, norm->name);
859 core->tvaudio = 0;
860 return 0;
861 }
862
863 cx_andor(MO_AFECFG_IO, 0x1f, 0x0);
864 cx88_set_tvaudio(core);
Mauro Carvalho Chehabe52e98a2005-09-09 13:03:41 -0700865 /* cx88_set_stereo(dev,V4L2_TUNER_MODE_STEREO); */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866
Mauro Carvalho Chehab6f502b82005-12-01 00:51:34 -0800867/*
868 This should be needed only on cx88-alsa. It seems that some cx88 chips have
869 bugs and does require DMA enabled for it to work.
870 */
871 cx88_start_audio_dma(core);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 return 0;
873}
874
Mauro Carvalho Chehab6f502b82005-12-01 00:51:34 -0800875
876
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm)
878{
879 u32 fsc8;
880 u32 adc_clock;
881 u32 vdec_clock;
882 u32 step_db,step_dr;
883 u64 tmp64;
884 u32 bdelay,agcdelay,htotal;
885
886 core->tvnorm = norm;
887 fsc8 = norm_fsc8(norm);
888 adc_clock = xtal;
889 vdec_clock = fsc8;
890 step_db = fsc8;
891 step_dr = fsc8;
892
893 if (norm->id & V4L2_STD_SECAM) {
894 step_db = 4250000 * 8;
895 step_dr = 4406250 * 8;
896 }
897
898 dprintk(1,"set_tvnorm: \"%s\" fsc8=%d adc=%d vdec=%d db/dr=%d/%d\n",
899 norm->name, fsc8, adc_clock, vdec_clock, step_db, step_dr);
900 set_pll(core,2,vdec_clock);
901
902 dprintk(1,"set_tvnorm: MO_INPUT_FORMAT 0x%08x [old=0x%08x]\n",
903 norm->cxiformat, cx_read(MO_INPUT_FORMAT) & 0x0f);
904 cx_andor(MO_INPUT_FORMAT, 0xf, norm->cxiformat);
905
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 // FIXME: as-is from DScaler
907 dprintk(1,"set_tvnorm: MO_OUTPUT_FORMAT 0x%08x [old=0x%08x]\n",
908 norm->cxoformat, cx_read(MO_OUTPUT_FORMAT));
909 cx_write(MO_OUTPUT_FORMAT, norm->cxoformat);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910
911 // MO_SCONV_REG = adc clock / video dec clock * 2^17
912 tmp64 = adc_clock * (u64)(1 << 17);
913 do_div(tmp64, vdec_clock);
914 dprintk(1,"set_tvnorm: MO_SCONV_REG 0x%08x [old=0x%08x]\n",
915 (u32)tmp64, cx_read(MO_SCONV_REG));
916 cx_write(MO_SCONV_REG, (u32)tmp64);
917
918 // MO_SUB_STEP = 8 * fsc / video dec clock * 2^22
919 tmp64 = step_db * (u64)(1 << 22);
920 do_div(tmp64, vdec_clock);
921 dprintk(1,"set_tvnorm: MO_SUB_STEP 0x%08x [old=0x%08x]\n",
922 (u32)tmp64, cx_read(MO_SUB_STEP));
923 cx_write(MO_SUB_STEP, (u32)tmp64);
924
925 // MO_SUB_STEP_DR = 8 * 4406250 / video dec clock * 2^22
926 tmp64 = step_dr * (u64)(1 << 22);
927 do_div(tmp64, vdec_clock);
928 dprintk(1,"set_tvnorm: MO_SUB_STEP_DR 0x%08x [old=0x%08x]\n",
929 (u32)tmp64, cx_read(MO_SUB_STEP_DR));
930 cx_write(MO_SUB_STEP_DR, (u32)tmp64);
931
932 // bdelay + agcdelay
933 bdelay = vdec_clock * 65 / 20000000 + 21;
934 agcdelay = vdec_clock * 68 / 20000000 + 15;
935 dprintk(1,"set_tvnorm: MO_AGC_BURST 0x%08x [old=0x%08x,bdelay=%d,agcdelay=%d]\n",
936 (bdelay << 8) | agcdelay, cx_read(MO_AGC_BURST), bdelay, agcdelay);
937 cx_write(MO_AGC_BURST, (bdelay << 8) | agcdelay);
938
939 // htotal
940 tmp64 = norm_htotal(norm) * (u64)vdec_clock;
941 do_div(tmp64, fsc8);
Mauro Carvalho Chehabccbf64b2006-09-29 12:39:36 -0300942 htotal = (u32)tmp64 | (HLNotchFilter4xFsc << 11);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 dprintk(1,"set_tvnorm: MO_HTOTAL 0x%08x [old=0x%08x,htotal=%d]\n",
944 htotal, cx_read(MO_HTOTAL), (u32)tmp64);
945 cx_write(MO_HTOTAL, htotal);
946
Trent Piepho3eb73172006-05-23 23:54:44 -0300947 // vbi stuff, set vbi offset to 10 (for 20 Clk*2 pixels), this makes
948 // the effective vbi offset ~244 samples, the same as the Bt8x8
949 cx_write(MO_VBI_PACKET, (10<<11) | norm_vbipack(norm));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950
951 // this is needed as well to set all tvnorm parameter
952 cx88_set_scale(core, 320, 240, V4L2_FIELD_INTERLACED);
953
954 // audio
955 set_tvaudio(core);
956
957 // tell i2c chips
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 cx88_call_i2c_clients(core,VIDIOC_S_STD,&norm->id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959
960 // done
961 return 0;
962}
963
964/* ------------------------------------------------------------------ */
965
966static int cx88_pci_quirks(char *name, struct pci_dev *pci)
967{
968 unsigned int lat = UNSET;
969 u8 ctrl = 0;
970 u8 value;
971
972 /* check pci quirks */
973 if (pci_pci_problems & PCIPCI_TRITON) {
974 printk(KERN_INFO "%s: quirk: PCIPCI_TRITON -- set TBFX\n",
975 name);
976 ctrl |= CX88X_EN_TBFX;
977 }
978 if (pci_pci_problems & PCIPCI_NATOMA) {
979 printk(KERN_INFO "%s: quirk: PCIPCI_NATOMA -- set TBFX\n",
980 name);
981 ctrl |= CX88X_EN_TBFX;
982 }
983 if (pci_pci_problems & PCIPCI_VIAETBF) {
984 printk(KERN_INFO "%s: quirk: PCIPCI_VIAETBF -- set TBFX\n",
985 name);
986 ctrl |= CX88X_EN_TBFX;
987 }
988 if (pci_pci_problems & PCIPCI_VSFX) {
989 printk(KERN_INFO "%s: quirk: PCIPCI_VSFX -- set VSFX\n",
990 name);
991 ctrl |= CX88X_EN_VSFX;
992 }
993#ifdef PCIPCI_ALIMAGIK
994 if (pci_pci_problems & PCIPCI_ALIMAGIK) {
995 printk(KERN_INFO "%s: quirk: PCIPCI_ALIMAGIK -- latency fixup\n",
996 name);
997 lat = 0x0A;
998 }
999#endif
1000
1001 /* check insmod options */
1002 if (UNSET != latency)
1003 lat = latency;
1004
1005 /* apply stuff */
1006 if (ctrl) {
1007 pci_read_config_byte(pci, CX88X_DEVCTRL, &value);
1008 value |= ctrl;
1009 pci_write_config_byte(pci, CX88X_DEVCTRL, value);
1010 }
1011 if (UNSET != lat) {
1012 printk(KERN_INFO "%s: setting pci latency timer to %d\n",
1013 name, latency);
1014 pci_write_config_byte(pci, PCI_LATENCY_TIMER, latency);
1015 }
1016 return 0;
1017}
1018
1019/* ------------------------------------------------------------------ */
1020
1021struct video_device *cx88_vdev_init(struct cx88_core *core,
1022 struct pci_dev *pci,
1023 struct video_device *template,
1024 char *type)
1025{
1026 struct video_device *vfd;
1027
1028 vfd = video_device_alloc();
1029 if (NULL == vfd)
1030 return NULL;
1031 *vfd = *template;
1032 vfd->minor = -1;
1033 vfd->dev = &pci->dev;
1034 vfd->release = video_device_release;
1035 snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
1036 core->name, type, cx88_boards[core->board].name);
1037 return vfd;
1038}
1039
1040static int get_ressources(struct cx88_core *core, struct pci_dev *pci)
1041{
1042 if (request_mem_region(pci_resource_start(pci,0),
1043 pci_resource_len(pci,0),
1044 core->name))
1045 return 0;
Greg Kroah-Hartman228aef62006-06-12 15:16:52 -07001046 printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx\n",
1047 core->name,(unsigned long long)pci_resource_start(pci,0));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 return -EBUSY;
1049}
1050
1051struct cx88_core* cx88_core_get(struct pci_dev *pci)
1052{
1053 struct cx88_core *core;
1054 struct list_head *item;
1055 int i;
1056
Ingo Molnar1e4baed2006-01-15 07:52:23 -02001057 mutex_lock(&devlist);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 list_for_each(item,&cx88_devlist) {
1059 core = list_entry(item, struct cx88_core, devlist);
1060 if (pci->bus->number != core->pci_bus)
1061 continue;
1062 if (PCI_SLOT(pci->devfn) != core->pci_slot)
1063 continue;
1064
1065 if (0 != get_ressources(core,pci))
1066 goto fail_unlock;
1067 atomic_inc(&core->refcount);
Ingo Molnar1e4baed2006-01-15 07:52:23 -02001068 mutex_unlock(&devlist);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 return core;
1070 }
Panagiotis Issaris74081872006-01-11 19:40:56 -02001071 core = kzalloc(sizeof(*core),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 if (NULL == core)
1073 goto fail_unlock;
1074
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 atomic_inc(&core->refcount);
1076 core->pci_bus = pci->bus->number;
1077 core->pci_slot = PCI_SLOT(pci->devfn);
1078 core->pci_irqmask = 0x00fc00;
Ingo Molnar3593cab2006-02-07 06:49:14 -02001079 mutex_init(&core->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080
1081 core->nr = cx88_devcount++;
1082 sprintf(core->name,"cx88[%d]",core->nr);
1083 if (0 != get_ressources(core,pci)) {
Mauro Carvalho Chehabe52e98a2005-09-09 13:03:41 -07001084 printk(KERN_ERR "CORE %s No more PCI ressources for "
1085 "subsystem: %04x:%04x, board: %s\n",
1086 core->name,pci->subsystem_vendor,
1087 pci->subsystem_device,
1088 cx88_boards[core->board].name);
1089
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 cx88_devcount--;
1091 goto fail_free;
1092 }
1093 list_add_tail(&core->devlist,&cx88_devlist);
1094
1095 /* PCI stuff */
1096 cx88_pci_quirks(core->name, pci);
1097 core->lmmio = ioremap(pci_resource_start(pci,0),
1098 pci_resource_len(pci,0));
1099 core->bmmio = (u8 __iomem *)core->lmmio;
1100
1101 /* board config */
1102 core->board = UNSET;
1103 if (card[core->nr] < cx88_bcount)
1104 core->board = card[core->nr];
1105 for (i = 0; UNSET == core->board && i < cx88_idcount; i++)
1106 if (pci->subsystem_vendor == cx88_subids[i].subvendor &&
1107 pci->subsystem_device == cx88_subids[i].subdevice)
1108 core->board = cx88_subids[i].card;
1109 if (UNSET == core->board) {
1110 core->board = CX88_BOARD_UNKNOWN;
1111 cx88_card_list(core,pci);
1112 }
Mauro Carvalho Chehabe52e98a2005-09-09 13:03:41 -07001113 printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
1114 core->name,pci->subsystem_vendor,
1115 pci->subsystem_device,cx88_boards[core->board].name,
1116 core->board, card[core->nr] == core->board ?
1117 "insmod option" : "autodetected");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118
1119 core->tuner_type = tuner[core->nr];
Mauro Carvalho Chehabb45009b2005-06-23 22:05:03 -07001120 core->radio_type = radio[core->nr];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 if (UNSET == core->tuner_type)
1122 core->tuner_type = cx88_boards[core->board].tuner_type;
Mauro Carvalho Chehabb45009b2005-06-23 22:05:03 -07001123 if (UNSET == core->radio_type)
1124 core->radio_type = cx88_boards[core->board].radio_type;
1125 if (!core->tuner_addr)
1126 core->tuner_addr = cx88_boards[core->board].tuner_addr;
1127 if (!core->radio_addr)
1128 core->radio_addr = cx88_boards[core->board].radio_addr;
1129
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001130 printk(KERN_INFO "TV tuner %d at 0x%02x, Radio tuner %d at 0x%02x\n",
Mauro Carvalho Chehabb45009b2005-06-23 22:05:03 -07001131 core->tuner_type, core->tuner_addr<<1,
1132 core->radio_type, core->radio_addr<<1);
1133
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 core->tda9887_conf = cx88_boards[core->board].tda9887_conf;
1135
1136 /* init hardware */
1137 cx88_reset(core);
Steven Tothaa481a62006-09-14 15:41:13 -03001138 cx88_card_setup_pre_i2c(core);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 cx88_i2c_init(core,pci);
Michael Krufky87f07832005-11-08 21:36:19 -08001140 cx88_call_i2c_clients (core, TUNER_SET_STANDBY, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 cx88_card_setup(core);
1142 cx88_ir_init(core,pci);
1143
Ingo Molnar1e4baed2006-01-15 07:52:23 -02001144 mutex_unlock(&devlist);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 return core;
1146
1147fail_free:
1148 kfree(core);
1149fail_unlock:
Ingo Molnar1e4baed2006-01-15 07:52:23 -02001150 mutex_unlock(&devlist);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 return NULL;
1152}
1153
1154void cx88_core_put(struct cx88_core *core, struct pci_dev *pci)
1155{
1156 release_mem_region(pci_resource_start(pci,0),
1157 pci_resource_len(pci,0));
1158
1159 if (!atomic_dec_and_test(&core->refcount))
1160 return;
1161
Ingo Molnar1e4baed2006-01-15 07:52:23 -02001162 mutex_lock(&devlist);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 cx88_ir_fini(core);
1164 if (0 == core->i2c_rc)
Jean Delvare32697112006-12-10 21:21:33 +01001165 i2c_del_adapter(&core->i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 list_del(&core->devlist);
1167 iounmap(core->lmmio);
1168 cx88_devcount--;
Ingo Molnar1e4baed2006-01-15 07:52:23 -02001169 mutex_unlock(&devlist);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 kfree(core);
1171}
1172
1173/* ------------------------------------------------------------------ */
1174
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175EXPORT_SYMBOL(cx88_print_irqbits);
1176
1177EXPORT_SYMBOL(cx88_core_irq);
1178EXPORT_SYMBOL(cx88_wakeup);
1179EXPORT_SYMBOL(cx88_reset);
1180EXPORT_SYMBOL(cx88_shutdown);
1181
1182EXPORT_SYMBOL(cx88_risc_buffer);
1183EXPORT_SYMBOL(cx88_risc_databuffer);
1184EXPORT_SYMBOL(cx88_risc_stopper);
1185EXPORT_SYMBOL(cx88_free_buffer);
1186
1187EXPORT_SYMBOL(cx88_sram_channels);
1188EXPORT_SYMBOL(cx88_sram_channel_setup);
1189EXPORT_SYMBOL(cx88_sram_channel_dump);
1190
1191EXPORT_SYMBOL(cx88_set_tvnorm);
1192EXPORT_SYMBOL(cx88_set_scale);
1193
1194EXPORT_SYMBOL(cx88_vdev_init);
1195EXPORT_SYMBOL(cx88_core_get);
1196EXPORT_SYMBOL(cx88_core_put);
1197
1198/*
1199 * Local variables:
1200 * c-basic-offset: 8
1201 * End:
Mauro Carvalho Chehabe52e98a2005-09-09 13:03:41 -07001202 * 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 -07001203 */