xref: /linux/drivers/media/pci/cx23885/cx23885-core.c (revision a1c613ae4c322ddd58d5a8539dbfba2a0380a8c0)
1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2b285192aSMauro Carvalho Chehab /*
3b285192aSMauro Carvalho Chehab  *  Driver for the Conexant CX23885 PCIe bridge
4b285192aSMauro Carvalho Chehab  *
5b285192aSMauro Carvalho Chehab  *  Copyright (c) 2006 Steven Toth <stoth@linuxtv.org>
6b285192aSMauro Carvalho Chehab  */
7b285192aSMauro Carvalho Chehab 
8e39682b5SMauro Carvalho Chehab #include "cx23885.h"
9e39682b5SMauro Carvalho Chehab 
10b285192aSMauro Carvalho Chehab #include <linux/init.h>
11b285192aSMauro Carvalho Chehab #include <linux/list.h>
12b285192aSMauro Carvalho Chehab #include <linux/module.h>
13b285192aSMauro Carvalho Chehab #include <linux/moduleparam.h>
14b285192aSMauro Carvalho Chehab #include <linux/kmod.h>
15b285192aSMauro Carvalho Chehab #include <linux/kernel.h>
164bd46aa0SBrad Love #include <linux/pci.h>
17b285192aSMauro Carvalho Chehab #include <linux/slab.h>
18b285192aSMauro Carvalho Chehab #include <linux/interrupt.h>
19b285192aSMauro Carvalho Chehab #include <linux/delay.h>
20b285192aSMauro Carvalho Chehab #include <asm/div64.h>
21b285192aSMauro Carvalho Chehab #include <linux/firmware.h>
22b285192aSMauro Carvalho Chehab 
23b285192aSMauro Carvalho Chehab #include "cimax2.h"
24b285192aSMauro Carvalho Chehab #include "altera-ci.h"
25b285192aSMauro Carvalho Chehab #include "cx23888-ir.h"
26b285192aSMauro Carvalho Chehab #include "cx23885-ir.h"
27b285192aSMauro Carvalho Chehab #include "cx23885-av.h"
28b285192aSMauro Carvalho Chehab #include "cx23885-input.h"
29b285192aSMauro Carvalho Chehab 
30b285192aSMauro Carvalho Chehab MODULE_DESCRIPTION("Driver for cx23885 based TV cards");
31b285192aSMauro Carvalho Chehab MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
32b285192aSMauro Carvalho Chehab MODULE_LICENSE("GPL");
33b285192aSMauro Carvalho Chehab MODULE_VERSION(CX23885_VERSION);
34b285192aSMauro Carvalho Chehab 
354bd46aa0SBrad Love /*
364bd46aa0SBrad Love  * Some platforms have been found to require periodic resetting of the DMA
374bd46aa0SBrad Love  * engine. Ryzen and XEON platforms are known to be affected. The symptom
384bd46aa0SBrad Love  * encountered is "mpeg risc op code error". Only Ryzen platforms employ
394bd46aa0SBrad Love  * this workaround if the option equals 1. The workaround can be explicitly
404bd46aa0SBrad Love  * disabled for all platforms by setting to 0, the workaround can be forced
414bd46aa0SBrad Love  * on for any platform by setting to 2.
424bd46aa0SBrad Love  */
434bd46aa0SBrad Love static unsigned int dma_reset_workaround = 1;
444bd46aa0SBrad Love module_param(dma_reset_workaround, int, 0644);
454bd46aa0SBrad Love MODULE_PARM_DESC(dma_reset_workaround, "periodic RiSC dma engine reset; 0-force disable, 1-driver detect (default), 2-force enable");
464bd46aa0SBrad Love 
47b285192aSMauro Carvalho Chehab static unsigned int debug;
48b285192aSMauro Carvalho Chehab module_param(debug, int, 0644);
49b285192aSMauro Carvalho Chehab MODULE_PARM_DESC(debug, "enable debug messages");
50b285192aSMauro Carvalho Chehab 
51b285192aSMauro Carvalho Chehab static unsigned int card[]  = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };
52b285192aSMauro Carvalho Chehab module_param_array(card,  int, NULL, 0444);
53b285192aSMauro Carvalho Chehab MODULE_PARM_DESC(card, "card type");
54b285192aSMauro Carvalho Chehab 
55b285192aSMauro Carvalho Chehab #define dprintk(level, fmt, arg...)\
56b285192aSMauro Carvalho Chehab 	do { if (debug >= level)\
57e39682b5SMauro Carvalho Chehab 		printk(KERN_DEBUG pr_fmt("%s: " fmt), \
58e39682b5SMauro Carvalho Chehab 		       __func__, ##arg); \
59b285192aSMauro Carvalho Chehab 	} while (0)
60b285192aSMauro Carvalho Chehab 
61b285192aSMauro Carvalho Chehab static unsigned int cx23885_devcount;
62b285192aSMauro Carvalho Chehab 
63b285192aSMauro Carvalho Chehab #define NO_SYNC_LINE (-1U)
64b285192aSMauro Carvalho Chehab 
65b285192aSMauro Carvalho Chehab /* FIXME, these allocations will change when
66b285192aSMauro Carvalho Chehab  * analog arrives. The be reviewed.
67b285192aSMauro Carvalho Chehab  * CX23887 Assumptions
68b285192aSMauro Carvalho Chehab  * 1 line = 16 bytes of CDT
69b285192aSMauro Carvalho Chehab  * cmds size = 80
70b285192aSMauro Carvalho Chehab  * cdt size = 16 * linesize
71b285192aSMauro Carvalho Chehab  * iqsize = 64
72b285192aSMauro Carvalho Chehab  * maxlines = 6
73b285192aSMauro Carvalho Chehab  *
74b285192aSMauro Carvalho Chehab  * Address Space:
75b285192aSMauro Carvalho Chehab  * 0x00000000 0x00008fff FIFO clusters
76b285192aSMauro Carvalho Chehab  * 0x00010000 0x000104af Channel Management Data Structures
77b285192aSMauro Carvalho Chehab  * 0x000104b0 0x000104ff Free
78b285192aSMauro Carvalho Chehab  * 0x00010500 0x000108bf 15 channels * iqsize
79b285192aSMauro Carvalho Chehab  * 0x000108c0 0x000108ff Free
80b285192aSMauro Carvalho Chehab  * 0x00010900 0x00010e9f IQ's + Cluster Descriptor Tables
81b285192aSMauro Carvalho Chehab  *                       15 channels * (iqsize + (maxlines * linesize))
82b285192aSMauro Carvalho Chehab  * 0x00010ea0 0x00010xxx Free
83b285192aSMauro Carvalho Chehab  */
84b285192aSMauro Carvalho Chehab 
85b285192aSMauro Carvalho Chehab static struct sram_channel cx23885_sram_channels[] = {
86b285192aSMauro Carvalho Chehab 	[SRAM_CH01] = {
87b285192aSMauro Carvalho Chehab 		.name		= "VID A",
88b285192aSMauro Carvalho Chehab 		.cmds_start	= 0x10000,
89b285192aSMauro Carvalho Chehab 		.ctrl_start	= 0x10380,
90b285192aSMauro Carvalho Chehab 		.cdt		= 0x104c0,
91b285192aSMauro Carvalho Chehab 		.fifo_start	= 0x40,
92b285192aSMauro Carvalho Chehab 		.fifo_size	= 0x2800,
93b285192aSMauro Carvalho Chehab 		.ptr1_reg	= DMA1_PTR1,
94b285192aSMauro Carvalho Chehab 		.ptr2_reg	= DMA1_PTR2,
95b285192aSMauro Carvalho Chehab 		.cnt1_reg	= DMA1_CNT1,
96b285192aSMauro Carvalho Chehab 		.cnt2_reg	= DMA1_CNT2,
97b285192aSMauro Carvalho Chehab 	},
98b285192aSMauro Carvalho Chehab 	[SRAM_CH02] = {
99b285192aSMauro Carvalho Chehab 		.name		= "ch2",
100b285192aSMauro Carvalho Chehab 		.cmds_start	= 0x0,
101b285192aSMauro Carvalho Chehab 		.ctrl_start	= 0x0,
102b285192aSMauro Carvalho Chehab 		.cdt		= 0x0,
103b285192aSMauro Carvalho Chehab 		.fifo_start	= 0x0,
104b285192aSMauro Carvalho Chehab 		.fifo_size	= 0x0,
105b285192aSMauro Carvalho Chehab 		.ptr1_reg	= DMA2_PTR1,
106b285192aSMauro Carvalho Chehab 		.ptr2_reg	= DMA2_PTR2,
107b285192aSMauro Carvalho Chehab 		.cnt1_reg	= DMA2_CNT1,
108b285192aSMauro Carvalho Chehab 		.cnt2_reg	= DMA2_CNT2,
109b285192aSMauro Carvalho Chehab 	},
110b285192aSMauro Carvalho Chehab 	[SRAM_CH03] = {
111b285192aSMauro Carvalho Chehab 		.name		= "TS1 B",
112b285192aSMauro Carvalho Chehab 		.cmds_start	= 0x100A0,
113b285192aSMauro Carvalho Chehab 		.ctrl_start	= 0x10400,
114b285192aSMauro Carvalho Chehab 		.cdt		= 0x10580,
115b285192aSMauro Carvalho Chehab 		.fifo_start	= 0x5000,
116b285192aSMauro Carvalho Chehab 		.fifo_size	= 0x1000,
117b285192aSMauro Carvalho Chehab 		.ptr1_reg	= DMA3_PTR1,
118b285192aSMauro Carvalho Chehab 		.ptr2_reg	= DMA3_PTR2,
119b285192aSMauro Carvalho Chehab 		.cnt1_reg	= DMA3_CNT1,
120b285192aSMauro Carvalho Chehab 		.cnt2_reg	= DMA3_CNT2,
121b285192aSMauro Carvalho Chehab 	},
122b285192aSMauro Carvalho Chehab 	[SRAM_CH04] = {
123b285192aSMauro Carvalho Chehab 		.name		= "ch4",
124b285192aSMauro Carvalho Chehab 		.cmds_start	= 0x0,
125b285192aSMauro Carvalho Chehab 		.ctrl_start	= 0x0,
126b285192aSMauro Carvalho Chehab 		.cdt		= 0x0,
127b285192aSMauro Carvalho Chehab 		.fifo_start	= 0x0,
128b285192aSMauro Carvalho Chehab 		.fifo_size	= 0x0,
129b285192aSMauro Carvalho Chehab 		.ptr1_reg	= DMA4_PTR1,
130b285192aSMauro Carvalho Chehab 		.ptr2_reg	= DMA4_PTR2,
131b285192aSMauro Carvalho Chehab 		.cnt1_reg	= DMA4_CNT1,
132b285192aSMauro Carvalho Chehab 		.cnt2_reg	= DMA4_CNT2,
133b285192aSMauro Carvalho Chehab 	},
134b285192aSMauro Carvalho Chehab 	[SRAM_CH05] = {
135b285192aSMauro Carvalho Chehab 		.name		= "ch5",
136b285192aSMauro Carvalho Chehab 		.cmds_start	= 0x0,
137b285192aSMauro Carvalho Chehab 		.ctrl_start	= 0x0,
138b285192aSMauro Carvalho Chehab 		.cdt		= 0x0,
139b285192aSMauro Carvalho Chehab 		.fifo_start	= 0x0,
140b285192aSMauro Carvalho Chehab 		.fifo_size	= 0x0,
141b285192aSMauro Carvalho Chehab 		.ptr1_reg	= DMA5_PTR1,
142b285192aSMauro Carvalho Chehab 		.ptr2_reg	= DMA5_PTR2,
143b285192aSMauro Carvalho Chehab 		.cnt1_reg	= DMA5_CNT1,
144b285192aSMauro Carvalho Chehab 		.cnt2_reg	= DMA5_CNT2,
145b285192aSMauro Carvalho Chehab 	},
146b285192aSMauro Carvalho Chehab 	[SRAM_CH06] = {
147b285192aSMauro Carvalho Chehab 		.name		= "TS2 C",
148b285192aSMauro Carvalho Chehab 		.cmds_start	= 0x10140,
149b285192aSMauro Carvalho Chehab 		.ctrl_start	= 0x10440,
150b285192aSMauro Carvalho Chehab 		.cdt		= 0x105e0,
151b285192aSMauro Carvalho Chehab 		.fifo_start	= 0x6000,
152b285192aSMauro Carvalho Chehab 		.fifo_size	= 0x1000,
153b285192aSMauro Carvalho Chehab 		.ptr1_reg	= DMA5_PTR1,
154b285192aSMauro Carvalho Chehab 		.ptr2_reg	= DMA5_PTR2,
155b285192aSMauro Carvalho Chehab 		.cnt1_reg	= DMA5_CNT1,
156b285192aSMauro Carvalho Chehab 		.cnt2_reg	= DMA5_CNT2,
157b285192aSMauro Carvalho Chehab 	},
158b285192aSMauro Carvalho Chehab 	[SRAM_CH07] = {
159b285192aSMauro Carvalho Chehab 		.name		= "TV Audio",
160b285192aSMauro Carvalho Chehab 		.cmds_start	= 0x10190,
161b285192aSMauro Carvalho Chehab 		.ctrl_start	= 0x10480,
162b285192aSMauro Carvalho Chehab 		.cdt		= 0x10a00,
163b285192aSMauro Carvalho Chehab 		.fifo_start	= 0x7000,
164b285192aSMauro Carvalho Chehab 		.fifo_size	= 0x1000,
165b285192aSMauro Carvalho Chehab 		.ptr1_reg	= DMA6_PTR1,
166b285192aSMauro Carvalho Chehab 		.ptr2_reg	= DMA6_PTR2,
167b285192aSMauro Carvalho Chehab 		.cnt1_reg	= DMA6_CNT1,
168b285192aSMauro Carvalho Chehab 		.cnt2_reg	= DMA6_CNT2,
169b285192aSMauro Carvalho Chehab 	},
170b285192aSMauro Carvalho Chehab 	[SRAM_CH08] = {
171b285192aSMauro Carvalho Chehab 		.name		= "ch8",
172b285192aSMauro Carvalho Chehab 		.cmds_start	= 0x0,
173b285192aSMauro Carvalho Chehab 		.ctrl_start	= 0x0,
174b285192aSMauro Carvalho Chehab 		.cdt		= 0x0,
175b285192aSMauro Carvalho Chehab 		.fifo_start	= 0x0,
176b285192aSMauro Carvalho Chehab 		.fifo_size	= 0x0,
177b285192aSMauro Carvalho Chehab 		.ptr1_reg	= DMA7_PTR1,
178b285192aSMauro Carvalho Chehab 		.ptr2_reg	= DMA7_PTR2,
179b285192aSMauro Carvalho Chehab 		.cnt1_reg	= DMA7_CNT1,
180b285192aSMauro Carvalho Chehab 		.cnt2_reg	= DMA7_CNT2,
181b285192aSMauro Carvalho Chehab 	},
182b285192aSMauro Carvalho Chehab 	[SRAM_CH09] = {
183b285192aSMauro Carvalho Chehab 		.name		= "ch9",
184b285192aSMauro Carvalho Chehab 		.cmds_start	= 0x0,
185b285192aSMauro Carvalho Chehab 		.ctrl_start	= 0x0,
186b285192aSMauro Carvalho Chehab 		.cdt		= 0x0,
187b285192aSMauro Carvalho Chehab 		.fifo_start	= 0x0,
188b285192aSMauro Carvalho Chehab 		.fifo_size	= 0x0,
189b285192aSMauro Carvalho Chehab 		.ptr1_reg	= DMA8_PTR1,
190b285192aSMauro Carvalho Chehab 		.ptr2_reg	= DMA8_PTR2,
191b285192aSMauro Carvalho Chehab 		.cnt1_reg	= DMA8_CNT1,
192b285192aSMauro Carvalho Chehab 		.cnt2_reg	= DMA8_CNT2,
193b285192aSMauro Carvalho Chehab 	},
194b285192aSMauro Carvalho Chehab };
195b285192aSMauro Carvalho Chehab 
196b285192aSMauro Carvalho Chehab static struct sram_channel cx23887_sram_channels[] = {
197b285192aSMauro Carvalho Chehab 	[SRAM_CH01] = {
198b285192aSMauro Carvalho Chehab 		.name		= "VID A",
199b285192aSMauro Carvalho Chehab 		.cmds_start	= 0x10000,
200b285192aSMauro Carvalho Chehab 		.ctrl_start	= 0x105b0,
201b285192aSMauro Carvalho Chehab 		.cdt		= 0x107b0,
202b285192aSMauro Carvalho Chehab 		.fifo_start	= 0x40,
203b285192aSMauro Carvalho Chehab 		.fifo_size	= 0x2800,
204b285192aSMauro Carvalho Chehab 		.ptr1_reg	= DMA1_PTR1,
205b285192aSMauro Carvalho Chehab 		.ptr2_reg	= DMA1_PTR2,
206b285192aSMauro Carvalho Chehab 		.cnt1_reg	= DMA1_CNT1,
207b285192aSMauro Carvalho Chehab 		.cnt2_reg	= DMA1_CNT2,
208b285192aSMauro Carvalho Chehab 	},
209b285192aSMauro Carvalho Chehab 	[SRAM_CH02] = {
210b285192aSMauro Carvalho Chehab 		.name		= "VID A (VBI)",
211b285192aSMauro Carvalho Chehab 		.cmds_start	= 0x10050,
212b285192aSMauro Carvalho Chehab 		.ctrl_start	= 0x105F0,
213b285192aSMauro Carvalho Chehab 		.cdt		= 0x10810,
214b285192aSMauro Carvalho Chehab 		.fifo_start	= 0x3000,
215b285192aSMauro Carvalho Chehab 		.fifo_size	= 0x1000,
216b285192aSMauro Carvalho Chehab 		.ptr1_reg	= DMA2_PTR1,
217b285192aSMauro Carvalho Chehab 		.ptr2_reg	= DMA2_PTR2,
218b285192aSMauro Carvalho Chehab 		.cnt1_reg	= DMA2_CNT1,
219b285192aSMauro Carvalho Chehab 		.cnt2_reg	= DMA2_CNT2,
220b285192aSMauro Carvalho Chehab 	},
221b285192aSMauro Carvalho Chehab 	[SRAM_CH03] = {
222b285192aSMauro Carvalho Chehab 		.name		= "TS1 B",
223b285192aSMauro Carvalho Chehab 		.cmds_start	= 0x100A0,
224b285192aSMauro Carvalho Chehab 		.ctrl_start	= 0x10630,
225b285192aSMauro Carvalho Chehab 		.cdt		= 0x10870,
226b285192aSMauro Carvalho Chehab 		.fifo_start	= 0x5000,
227b285192aSMauro Carvalho Chehab 		.fifo_size	= 0x1000,
228b285192aSMauro Carvalho Chehab 		.ptr1_reg	= DMA3_PTR1,
229b285192aSMauro Carvalho Chehab 		.ptr2_reg	= DMA3_PTR2,
230b285192aSMauro Carvalho Chehab 		.cnt1_reg	= DMA3_CNT1,
231b285192aSMauro Carvalho Chehab 		.cnt2_reg	= DMA3_CNT2,
232b285192aSMauro Carvalho Chehab 	},
233b285192aSMauro Carvalho Chehab 	[SRAM_CH04] = {
234b285192aSMauro Carvalho Chehab 		.name		= "ch4",
235b285192aSMauro Carvalho Chehab 		.cmds_start	= 0x0,
236b285192aSMauro Carvalho Chehab 		.ctrl_start	= 0x0,
237b285192aSMauro Carvalho Chehab 		.cdt		= 0x0,
238b285192aSMauro Carvalho Chehab 		.fifo_start	= 0x0,
239b285192aSMauro Carvalho Chehab 		.fifo_size	= 0x0,
240b285192aSMauro Carvalho Chehab 		.ptr1_reg	= DMA4_PTR1,
241b285192aSMauro Carvalho Chehab 		.ptr2_reg	= DMA4_PTR2,
242b285192aSMauro Carvalho Chehab 		.cnt1_reg	= DMA4_CNT1,
243b285192aSMauro Carvalho Chehab 		.cnt2_reg	= DMA4_CNT2,
244b285192aSMauro Carvalho Chehab 	},
245b285192aSMauro Carvalho Chehab 	[SRAM_CH05] = {
246b285192aSMauro Carvalho Chehab 		.name		= "ch5",
247b285192aSMauro Carvalho Chehab 		.cmds_start	= 0x0,
248b285192aSMauro Carvalho Chehab 		.ctrl_start	= 0x0,
249b285192aSMauro Carvalho Chehab 		.cdt		= 0x0,
250b285192aSMauro Carvalho Chehab 		.fifo_start	= 0x0,
251b285192aSMauro Carvalho Chehab 		.fifo_size	= 0x0,
252b285192aSMauro Carvalho Chehab 		.ptr1_reg	= DMA5_PTR1,
253b285192aSMauro Carvalho Chehab 		.ptr2_reg	= DMA5_PTR2,
254b285192aSMauro Carvalho Chehab 		.cnt1_reg	= DMA5_CNT1,
255b285192aSMauro Carvalho Chehab 		.cnt2_reg	= DMA5_CNT2,
256b285192aSMauro Carvalho Chehab 	},
257b285192aSMauro Carvalho Chehab 	[SRAM_CH06] = {
258b285192aSMauro Carvalho Chehab 		.name		= "TS2 C",
259b285192aSMauro Carvalho Chehab 		.cmds_start	= 0x10140,
260b285192aSMauro Carvalho Chehab 		.ctrl_start	= 0x10670,
261b285192aSMauro Carvalho Chehab 		.cdt		= 0x108d0,
262b285192aSMauro Carvalho Chehab 		.fifo_start	= 0x6000,
263b285192aSMauro Carvalho Chehab 		.fifo_size	= 0x1000,
264b285192aSMauro Carvalho Chehab 		.ptr1_reg	= DMA5_PTR1,
265b285192aSMauro Carvalho Chehab 		.ptr2_reg	= DMA5_PTR2,
266b285192aSMauro Carvalho Chehab 		.cnt1_reg	= DMA5_CNT1,
267b285192aSMauro Carvalho Chehab 		.cnt2_reg	= DMA5_CNT2,
268b285192aSMauro Carvalho Chehab 	},
269b285192aSMauro Carvalho Chehab 	[SRAM_CH07] = {
270b285192aSMauro Carvalho Chehab 		.name		= "TV Audio",
271b285192aSMauro Carvalho Chehab 		.cmds_start	= 0x10190,
272b285192aSMauro Carvalho Chehab 		.ctrl_start	= 0x106B0,
273b285192aSMauro Carvalho Chehab 		.cdt		= 0x10930,
274b285192aSMauro Carvalho Chehab 		.fifo_start	= 0x7000,
275b285192aSMauro Carvalho Chehab 		.fifo_size	= 0x1000,
276b285192aSMauro Carvalho Chehab 		.ptr1_reg	= DMA6_PTR1,
277b285192aSMauro Carvalho Chehab 		.ptr2_reg	= DMA6_PTR2,
278b285192aSMauro Carvalho Chehab 		.cnt1_reg	= DMA6_CNT1,
279b285192aSMauro Carvalho Chehab 		.cnt2_reg	= DMA6_CNT2,
280b285192aSMauro Carvalho Chehab 	},
281b285192aSMauro Carvalho Chehab 	[SRAM_CH08] = {
282b285192aSMauro Carvalho Chehab 		.name		= "ch8",
283b285192aSMauro Carvalho Chehab 		.cmds_start	= 0x0,
284b285192aSMauro Carvalho Chehab 		.ctrl_start	= 0x0,
285b285192aSMauro Carvalho Chehab 		.cdt		= 0x0,
286b285192aSMauro Carvalho Chehab 		.fifo_start	= 0x0,
287b285192aSMauro Carvalho Chehab 		.fifo_size	= 0x0,
288b285192aSMauro Carvalho Chehab 		.ptr1_reg	= DMA7_PTR1,
289b285192aSMauro Carvalho Chehab 		.ptr2_reg	= DMA7_PTR2,
290b285192aSMauro Carvalho Chehab 		.cnt1_reg	= DMA7_CNT1,
291b285192aSMauro Carvalho Chehab 		.cnt2_reg	= DMA7_CNT2,
292b285192aSMauro Carvalho Chehab 	},
293b285192aSMauro Carvalho Chehab 	[SRAM_CH09] = {
294b285192aSMauro Carvalho Chehab 		.name		= "ch9",
295b285192aSMauro Carvalho Chehab 		.cmds_start	= 0x0,
296b285192aSMauro Carvalho Chehab 		.ctrl_start	= 0x0,
297b285192aSMauro Carvalho Chehab 		.cdt		= 0x0,
298b285192aSMauro Carvalho Chehab 		.fifo_start	= 0x0,
299b285192aSMauro Carvalho Chehab 		.fifo_size	= 0x0,
300b285192aSMauro Carvalho Chehab 		.ptr1_reg	= DMA8_PTR1,
301b285192aSMauro Carvalho Chehab 		.ptr2_reg	= DMA8_PTR2,
302b285192aSMauro Carvalho Chehab 		.cnt1_reg	= DMA8_CNT1,
303b285192aSMauro Carvalho Chehab 		.cnt2_reg	= DMA8_CNT2,
304b285192aSMauro Carvalho Chehab 	},
305b285192aSMauro Carvalho Chehab };
306b285192aSMauro Carvalho Chehab 
cx23885_irq_add(struct cx23885_dev * dev,u32 mask)307ada73eeeSMauro Carvalho Chehab static void cx23885_irq_add(struct cx23885_dev *dev, u32 mask)
308b285192aSMauro Carvalho Chehab {
309b285192aSMauro Carvalho Chehab 	unsigned long flags;
310b285192aSMauro Carvalho Chehab 	spin_lock_irqsave(&dev->pci_irqmask_lock, flags);
311b285192aSMauro Carvalho Chehab 
312b285192aSMauro Carvalho Chehab 	dev->pci_irqmask |= mask;
313b285192aSMauro Carvalho Chehab 
314b285192aSMauro Carvalho Chehab 	spin_unlock_irqrestore(&dev->pci_irqmask_lock, flags);
315b285192aSMauro Carvalho Chehab }
316b285192aSMauro Carvalho Chehab 
cx23885_irq_add_enable(struct cx23885_dev * dev,u32 mask)317b285192aSMauro Carvalho Chehab void cx23885_irq_add_enable(struct cx23885_dev *dev, u32 mask)
318b285192aSMauro Carvalho Chehab {
319b285192aSMauro Carvalho Chehab 	unsigned long flags;
320b285192aSMauro Carvalho Chehab 	spin_lock_irqsave(&dev->pci_irqmask_lock, flags);
321b285192aSMauro Carvalho Chehab 
322b285192aSMauro Carvalho Chehab 	dev->pci_irqmask |= mask;
323b285192aSMauro Carvalho Chehab 	cx_set(PCI_INT_MSK, mask);
324b285192aSMauro Carvalho Chehab 
325b285192aSMauro Carvalho Chehab 	spin_unlock_irqrestore(&dev->pci_irqmask_lock, flags);
326b285192aSMauro Carvalho Chehab }
327b285192aSMauro Carvalho Chehab 
cx23885_irq_enable(struct cx23885_dev * dev,u32 mask)328b285192aSMauro Carvalho Chehab void cx23885_irq_enable(struct cx23885_dev *dev, u32 mask)
329b285192aSMauro Carvalho Chehab {
330b285192aSMauro Carvalho Chehab 	u32 v;
331b285192aSMauro Carvalho Chehab 	unsigned long flags;
332b285192aSMauro Carvalho Chehab 	spin_lock_irqsave(&dev->pci_irqmask_lock, flags);
333b285192aSMauro Carvalho Chehab 
334b285192aSMauro Carvalho Chehab 	v = mask & dev->pci_irqmask;
335b285192aSMauro Carvalho Chehab 	if (v)
336b285192aSMauro Carvalho Chehab 		cx_set(PCI_INT_MSK, v);
337b285192aSMauro Carvalho Chehab 
338b285192aSMauro Carvalho Chehab 	spin_unlock_irqrestore(&dev->pci_irqmask_lock, flags);
339b285192aSMauro Carvalho Chehab }
340b285192aSMauro Carvalho Chehab 
cx23885_irq_enable_all(struct cx23885_dev * dev)341b285192aSMauro Carvalho Chehab static inline void cx23885_irq_enable_all(struct cx23885_dev *dev)
342b285192aSMauro Carvalho Chehab {
343b285192aSMauro Carvalho Chehab 	cx23885_irq_enable(dev, 0xffffffff);
344b285192aSMauro Carvalho Chehab }
345b285192aSMauro Carvalho Chehab 
cx23885_irq_disable(struct cx23885_dev * dev,u32 mask)346b285192aSMauro Carvalho Chehab void cx23885_irq_disable(struct cx23885_dev *dev, u32 mask)
347b285192aSMauro Carvalho Chehab {
348b285192aSMauro Carvalho Chehab 	unsigned long flags;
349b285192aSMauro Carvalho Chehab 	spin_lock_irqsave(&dev->pci_irqmask_lock, flags);
350b285192aSMauro Carvalho Chehab 
351b285192aSMauro Carvalho Chehab 	cx_clear(PCI_INT_MSK, mask);
352b285192aSMauro Carvalho Chehab 
353b285192aSMauro Carvalho Chehab 	spin_unlock_irqrestore(&dev->pci_irqmask_lock, flags);
354b285192aSMauro Carvalho Chehab }
355b285192aSMauro Carvalho Chehab 
cx23885_irq_disable_all(struct cx23885_dev * dev)356b285192aSMauro Carvalho Chehab static inline void cx23885_irq_disable_all(struct cx23885_dev *dev)
357b285192aSMauro Carvalho Chehab {
358b285192aSMauro Carvalho Chehab 	cx23885_irq_disable(dev, 0xffffffff);
359b285192aSMauro Carvalho Chehab }
360b285192aSMauro Carvalho Chehab 
cx23885_irq_remove(struct cx23885_dev * dev,u32 mask)361b285192aSMauro Carvalho Chehab void cx23885_irq_remove(struct cx23885_dev *dev, u32 mask)
362b285192aSMauro Carvalho Chehab {
363b285192aSMauro Carvalho Chehab 	unsigned long flags;
364b285192aSMauro Carvalho Chehab 	spin_lock_irqsave(&dev->pci_irqmask_lock, flags);
365b285192aSMauro Carvalho Chehab 
366b285192aSMauro Carvalho Chehab 	dev->pci_irqmask &= ~mask;
367b285192aSMauro Carvalho Chehab 	cx_clear(PCI_INT_MSK, mask);
368b285192aSMauro Carvalho Chehab 
369b285192aSMauro Carvalho Chehab 	spin_unlock_irqrestore(&dev->pci_irqmask_lock, flags);
370b285192aSMauro Carvalho Chehab }
371b285192aSMauro Carvalho Chehab 
cx23885_irq_get_mask(struct cx23885_dev * dev)372b285192aSMauro Carvalho Chehab static u32 cx23885_irq_get_mask(struct cx23885_dev *dev)
373b285192aSMauro Carvalho Chehab {
374b285192aSMauro Carvalho Chehab 	u32 v;
375b285192aSMauro Carvalho Chehab 	unsigned long flags;
376b285192aSMauro Carvalho Chehab 	spin_lock_irqsave(&dev->pci_irqmask_lock, flags);
377b285192aSMauro Carvalho Chehab 
378b285192aSMauro Carvalho Chehab 	v = cx_read(PCI_INT_MSK);
379b285192aSMauro Carvalho Chehab 
380b285192aSMauro Carvalho Chehab 	spin_unlock_irqrestore(&dev->pci_irqmask_lock, flags);
381b285192aSMauro Carvalho Chehab 	return v;
382b285192aSMauro Carvalho Chehab }
383b285192aSMauro Carvalho Chehab 
cx23885_risc_decode(u32 risc)384b285192aSMauro Carvalho Chehab static int cx23885_risc_decode(u32 risc)
385b285192aSMauro Carvalho Chehab {
386b285192aSMauro Carvalho Chehab 	static char *instr[16] = {
387b285192aSMauro Carvalho Chehab 		[RISC_SYNC    >> 28] = "sync",
388b285192aSMauro Carvalho Chehab 		[RISC_WRITE   >> 28] = "write",
389b285192aSMauro Carvalho Chehab 		[RISC_WRITEC  >> 28] = "writec",
390b285192aSMauro Carvalho Chehab 		[RISC_READ    >> 28] = "read",
391b285192aSMauro Carvalho Chehab 		[RISC_READC   >> 28] = "readc",
392b285192aSMauro Carvalho Chehab 		[RISC_JUMP    >> 28] = "jump",
393b285192aSMauro Carvalho Chehab 		[RISC_SKIP    >> 28] = "skip",
394b285192aSMauro Carvalho Chehab 		[RISC_WRITERM >> 28] = "writerm",
395b285192aSMauro Carvalho Chehab 		[RISC_WRITECM >> 28] = "writecm",
396b285192aSMauro Carvalho Chehab 		[RISC_WRITECR >> 28] = "writecr",
397b285192aSMauro Carvalho Chehab 	};
398b285192aSMauro Carvalho Chehab 	static int incr[16] = {
399b285192aSMauro Carvalho Chehab 		[RISC_WRITE   >> 28] = 3,
400b285192aSMauro Carvalho Chehab 		[RISC_JUMP    >> 28] = 3,
401b285192aSMauro Carvalho Chehab 		[RISC_SKIP    >> 28] = 1,
402b285192aSMauro Carvalho Chehab 		[RISC_SYNC    >> 28] = 1,
403b285192aSMauro Carvalho Chehab 		[RISC_WRITERM >> 28] = 3,
404b285192aSMauro Carvalho Chehab 		[RISC_WRITECM >> 28] = 3,
405b285192aSMauro Carvalho Chehab 		[RISC_WRITECR >> 28] = 4,
406b285192aSMauro Carvalho Chehab 	};
407b285192aSMauro Carvalho Chehab 	static char *bits[] = {
408b285192aSMauro Carvalho Chehab 		"12",   "13",   "14",   "resync",
409b285192aSMauro Carvalho Chehab 		"cnt0", "cnt1", "18",   "19",
410b285192aSMauro Carvalho Chehab 		"20",   "21",   "22",   "23",
411b285192aSMauro Carvalho Chehab 		"irq1", "irq2", "eol",  "sol",
412b285192aSMauro Carvalho Chehab 	};
413b285192aSMauro Carvalho Chehab 	int i;
414b285192aSMauro Carvalho Chehab 
41509f8be26SMauro Carvalho Chehab 	printk(KERN_DEBUG "0x%08x [ %s", risc,
416b285192aSMauro Carvalho Chehab 	       instr[risc >> 28] ? instr[risc >> 28] : "INVALID");
417b285192aSMauro Carvalho Chehab 	for (i = ARRAY_SIZE(bits) - 1; i >= 0; i--)
418b285192aSMauro Carvalho Chehab 		if (risc & (1 << (i + 12)))
419e39682b5SMauro Carvalho Chehab 			pr_cont(" %s", bits[i]);
420e39682b5SMauro Carvalho Chehab 	pr_cont(" count=%d ]\n", risc & 0xfff);
421b285192aSMauro Carvalho Chehab 	return incr[risc >> 28] ? incr[risc >> 28] : 1;
422b285192aSMauro Carvalho Chehab }
423b285192aSMauro Carvalho Chehab 
cx23885_wakeup(struct cx23885_tsport * port,struct cx23885_dmaqueue * q,u32 count)424453afdd9SHans Verkuil static void cx23885_wakeup(struct cx23885_tsport *port,
425b285192aSMauro Carvalho Chehab 			   struct cx23885_dmaqueue *q, u32 count)
426b285192aSMauro Carvalho Chehab {
427b285192aSMauro Carvalho Chehab 	struct cx23885_buffer *buf;
4289a7dc2b0SBrad Love 	int count_delta;
4299a7dc2b0SBrad Love 	int max_buf_done = 5; /* service maximum five buffers */
430b285192aSMauro Carvalho Chehab 
4319a7dc2b0SBrad Love 	do {
432b285192aSMauro Carvalho Chehab 		if (list_empty(&q->active))
433453afdd9SHans Verkuil 			return;
434b285192aSMauro Carvalho Chehab 		buf = list_entry(q->active.next,
435453afdd9SHans Verkuil 				 struct cx23885_buffer, queue);
436b285192aSMauro Carvalho Chehab 
437d6dd645eSJunghak Sung 		buf->vb.vb2_buf.timestamp = ktime_get_ns();
4382d700715SJunghak Sung 		buf->vb.sequence = q->count++;
4399a7dc2b0SBrad Love 		if (count != (q->count % 65536)) {
4402d700715SJunghak Sung 			dprintk(1, "[%p/%d] wakeup reg=%d buf=%d\n", buf,
4419a7dc2b0SBrad Love 				buf->vb.vb2_buf.index, count, q->count);
4429a7dc2b0SBrad Love 		} else {
4439a7dc2b0SBrad Love 			dprintk(7, "[%p/%d] wakeup reg=%d buf=%d\n", buf,
4449a7dc2b0SBrad Love 				buf->vb.vb2_buf.index, count, q->count);
4459a7dc2b0SBrad Love 		}
446453afdd9SHans Verkuil 		list_del(&buf->queue);
4472d700715SJunghak Sung 		vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
4489a7dc2b0SBrad Love 		max_buf_done--;
4499a7dc2b0SBrad Love 		/* count register is 16 bits so apply modulo appropriately */
4509a7dc2b0SBrad Love 		count_delta = ((int)count - (int)(q->count % 65536));
4519a7dc2b0SBrad Love 	} while ((count_delta > 0) && (max_buf_done > 0));
452b285192aSMauro Carvalho Chehab }
453b285192aSMauro Carvalho Chehab 
cx23885_sram_channel_setup(struct cx23885_dev * dev,struct sram_channel * ch,unsigned int bpl,u32 risc)454b285192aSMauro Carvalho Chehab int cx23885_sram_channel_setup(struct cx23885_dev *dev,
455b285192aSMauro Carvalho Chehab 				      struct sram_channel *ch,
456b285192aSMauro Carvalho Chehab 				      unsigned int bpl, u32 risc)
457b285192aSMauro Carvalho Chehab {
458b285192aSMauro Carvalho Chehab 	unsigned int i, lines;
459b285192aSMauro Carvalho Chehab 	u32 cdt;
460b285192aSMauro Carvalho Chehab 
461b285192aSMauro Carvalho Chehab 	if (ch->cmds_start == 0) {
462b285192aSMauro Carvalho Chehab 		dprintk(1, "%s() Erasing channel [%s]\n", __func__,
463b285192aSMauro Carvalho Chehab 			ch->name);
464b285192aSMauro Carvalho Chehab 		cx_write(ch->ptr1_reg, 0);
465b285192aSMauro Carvalho Chehab 		cx_write(ch->ptr2_reg, 0);
466b285192aSMauro Carvalho Chehab 		cx_write(ch->cnt2_reg, 0);
467b285192aSMauro Carvalho Chehab 		cx_write(ch->cnt1_reg, 0);
468b285192aSMauro Carvalho Chehab 		return 0;
469b285192aSMauro Carvalho Chehab 	} else {
470b285192aSMauro Carvalho Chehab 		dprintk(1, "%s() Configuring channel [%s]\n", __func__,
471b285192aSMauro Carvalho Chehab 			ch->name);
472b285192aSMauro Carvalho Chehab 	}
473b285192aSMauro Carvalho Chehab 
474b285192aSMauro Carvalho Chehab 	bpl   = (bpl + 7) & ~7; /* alignment */
475b285192aSMauro Carvalho Chehab 	cdt   = ch->cdt;
476b285192aSMauro Carvalho Chehab 	lines = ch->fifo_size / bpl;
477b285192aSMauro Carvalho Chehab 	if (lines > 6)
478b285192aSMauro Carvalho Chehab 		lines = 6;
479b285192aSMauro Carvalho Chehab 	BUG_ON(lines < 2);
480b285192aSMauro Carvalho Chehab 
481453afdd9SHans Verkuil 	cx_write(8 + 0, RISC_JUMP | RISC_CNT_RESET);
482453afdd9SHans Verkuil 	cx_write(8 + 4, 12);
483b285192aSMauro Carvalho Chehab 	cx_write(8 + 8, 0);
484b285192aSMauro Carvalho Chehab 
485b285192aSMauro Carvalho Chehab 	/* write CDT */
486b285192aSMauro Carvalho Chehab 	for (i = 0; i < lines; i++) {
487b285192aSMauro Carvalho Chehab 		dprintk(2, "%s() 0x%08x <- 0x%08x\n", __func__, cdt + 16*i,
488b285192aSMauro Carvalho Chehab 			ch->fifo_start + bpl*i);
489b285192aSMauro Carvalho Chehab 		cx_write(cdt + 16*i, ch->fifo_start + bpl*i);
490b285192aSMauro Carvalho Chehab 		cx_write(cdt + 16*i +  4, 0);
491b285192aSMauro Carvalho Chehab 		cx_write(cdt + 16*i +  8, 0);
492b285192aSMauro Carvalho Chehab 		cx_write(cdt + 16*i + 12, 0);
493b285192aSMauro Carvalho Chehab 	}
494b285192aSMauro Carvalho Chehab 
495b285192aSMauro Carvalho Chehab 	/* write CMDS */
496b285192aSMauro Carvalho Chehab 	if (ch->jumponly)
497b285192aSMauro Carvalho Chehab 		cx_write(ch->cmds_start + 0, 8);
498b285192aSMauro Carvalho Chehab 	else
499b285192aSMauro Carvalho Chehab 		cx_write(ch->cmds_start + 0, risc);
500b285192aSMauro Carvalho Chehab 	cx_write(ch->cmds_start +  4, 0); /* 64 bits 63-32 */
501b285192aSMauro Carvalho Chehab 	cx_write(ch->cmds_start +  8, cdt);
502b285192aSMauro Carvalho Chehab 	cx_write(ch->cmds_start + 12, (lines*16) >> 3);
503b285192aSMauro Carvalho Chehab 	cx_write(ch->cmds_start + 16, ch->ctrl_start);
504b285192aSMauro Carvalho Chehab 	if (ch->jumponly)
505b285192aSMauro Carvalho Chehab 		cx_write(ch->cmds_start + 20, 0x80000000 | (64 >> 2));
506b285192aSMauro Carvalho Chehab 	else
507b285192aSMauro Carvalho Chehab 		cx_write(ch->cmds_start + 20, 64 >> 2);
508b285192aSMauro Carvalho Chehab 	for (i = 24; i < 80; i += 4)
509b285192aSMauro Carvalho Chehab 		cx_write(ch->cmds_start + i, 0);
510b285192aSMauro Carvalho Chehab 
511b285192aSMauro Carvalho Chehab 	/* fill registers */
512b285192aSMauro Carvalho Chehab 	cx_write(ch->ptr1_reg, ch->fifo_start);
513b285192aSMauro Carvalho Chehab 	cx_write(ch->ptr2_reg, cdt);
514b285192aSMauro Carvalho Chehab 	cx_write(ch->cnt2_reg, (lines*16) >> 3);
515b285192aSMauro Carvalho Chehab 	cx_write(ch->cnt1_reg, (bpl >> 3) - 1);
516b285192aSMauro Carvalho Chehab 
517b285192aSMauro Carvalho Chehab 	dprintk(2, "[bridge %d] sram setup %s: bpl=%d lines=%d\n",
518b285192aSMauro Carvalho Chehab 		dev->bridge,
519b285192aSMauro Carvalho Chehab 		ch->name,
520b285192aSMauro Carvalho Chehab 		bpl,
521b285192aSMauro Carvalho Chehab 		lines);
522b285192aSMauro Carvalho Chehab 
523b285192aSMauro Carvalho Chehab 	return 0;
524b285192aSMauro Carvalho Chehab }
525b285192aSMauro Carvalho Chehab 
cx23885_sram_channel_dump(struct cx23885_dev * dev,struct sram_channel * ch)526b285192aSMauro Carvalho Chehab void cx23885_sram_channel_dump(struct cx23885_dev *dev,
527b285192aSMauro Carvalho Chehab 				      struct sram_channel *ch)
528b285192aSMauro Carvalho Chehab {
529b285192aSMauro Carvalho Chehab 	static char *name[] = {
530b285192aSMauro Carvalho Chehab 		"init risc lo",
531b285192aSMauro Carvalho Chehab 		"init risc hi",
532b285192aSMauro Carvalho Chehab 		"cdt base",
533b285192aSMauro Carvalho Chehab 		"cdt size",
534b285192aSMauro Carvalho Chehab 		"iq base",
535b285192aSMauro Carvalho Chehab 		"iq size",
536b285192aSMauro Carvalho Chehab 		"risc pc lo",
537b285192aSMauro Carvalho Chehab 		"risc pc hi",
538b285192aSMauro Carvalho Chehab 		"iq wr ptr",
539b285192aSMauro Carvalho Chehab 		"iq rd ptr",
540b285192aSMauro Carvalho Chehab 		"cdt current",
541b285192aSMauro Carvalho Chehab 		"pci target lo",
542b285192aSMauro Carvalho Chehab 		"pci target hi",
543b285192aSMauro Carvalho Chehab 		"line / byte",
544b285192aSMauro Carvalho Chehab 	};
545b285192aSMauro Carvalho Chehab 	u32 risc;
546b285192aSMauro Carvalho Chehab 	unsigned int i, j, n;
547b285192aSMauro Carvalho Chehab 
548e39682b5SMauro Carvalho Chehab 	pr_warn("%s: %s - dma channel status dump\n",
549b285192aSMauro Carvalho Chehab 		dev->name, ch->name);
550b285192aSMauro Carvalho Chehab 	for (i = 0; i < ARRAY_SIZE(name); i++)
551e39682b5SMauro Carvalho Chehab 		pr_warn("%s:   cmds: %-15s: 0x%08x\n",
552b285192aSMauro Carvalho Chehab 			dev->name, name[i],
553b285192aSMauro Carvalho Chehab 			cx_read(ch->cmds_start + 4*i));
554b285192aSMauro Carvalho Chehab 
555b285192aSMauro Carvalho Chehab 	for (i = 0; i < 4; i++) {
556b285192aSMauro Carvalho Chehab 		risc = cx_read(ch->cmds_start + 4 * (i + 14));
557e39682b5SMauro Carvalho Chehab 		pr_warn("%s:   risc%d:", dev->name, i);
558b285192aSMauro Carvalho Chehab 		cx23885_risc_decode(risc);
559b285192aSMauro Carvalho Chehab 	}
560b285192aSMauro Carvalho Chehab 	for (i = 0; i < (64 >> 2); i += n) {
561b285192aSMauro Carvalho Chehab 		risc = cx_read(ch->ctrl_start + 4 * i);
562b285192aSMauro Carvalho Chehab 		/* No consideration for bits 63-32 */
563b285192aSMauro Carvalho Chehab 
564e39682b5SMauro Carvalho Chehab 		pr_warn("%s:   (0x%08x) iq %x:", dev->name,
565b285192aSMauro Carvalho Chehab 			ch->ctrl_start + 4 * i, i);
566b285192aSMauro Carvalho Chehab 		n = cx23885_risc_decode(risc);
567b285192aSMauro Carvalho Chehab 		for (j = 1; j < n; j++) {
568b285192aSMauro Carvalho Chehab 			risc = cx_read(ch->ctrl_start + 4 * (i + j));
569e39682b5SMauro Carvalho Chehab 			pr_warn("%s:   iq %x: 0x%08x [ arg #%d ]\n",
570b285192aSMauro Carvalho Chehab 				dev->name, i+j, risc, j);
571b285192aSMauro Carvalho Chehab 		}
572b285192aSMauro Carvalho Chehab 	}
573b285192aSMauro Carvalho Chehab 
574e39682b5SMauro Carvalho Chehab 	pr_warn("%s: fifo: 0x%08x -> 0x%x\n",
575b285192aSMauro Carvalho Chehab 		dev->name, ch->fifo_start, ch->fifo_start+ch->fifo_size);
576e39682b5SMauro Carvalho Chehab 	pr_warn("%s: ctrl: 0x%08x -> 0x%x\n",
577b285192aSMauro Carvalho Chehab 		dev->name, ch->ctrl_start, ch->ctrl_start + 6*16);
578e39682b5SMauro Carvalho Chehab 	pr_warn("%s:   ptr1_reg: 0x%08x\n",
579b285192aSMauro Carvalho Chehab 		dev->name, cx_read(ch->ptr1_reg));
580e39682b5SMauro Carvalho Chehab 	pr_warn("%s:   ptr2_reg: 0x%08x\n",
581b285192aSMauro Carvalho Chehab 		dev->name, cx_read(ch->ptr2_reg));
582e39682b5SMauro Carvalho Chehab 	pr_warn("%s:   cnt1_reg: 0x%08x\n",
583b285192aSMauro Carvalho Chehab 		dev->name, cx_read(ch->cnt1_reg));
584e39682b5SMauro Carvalho Chehab 	pr_warn("%s:   cnt2_reg: 0x%08x\n",
585b285192aSMauro Carvalho Chehab 		dev->name, cx_read(ch->cnt2_reg));
586b285192aSMauro Carvalho Chehab }
587b285192aSMauro Carvalho Chehab 
cx23885_risc_disasm(struct cx23885_tsport * port,struct cx23885_riscmem * risc)588b285192aSMauro Carvalho Chehab static void cx23885_risc_disasm(struct cx23885_tsport *port,
5894d63a25cSHans Verkuil 				struct cx23885_riscmem *risc)
590b285192aSMauro Carvalho Chehab {
591b285192aSMauro Carvalho Chehab 	struct cx23885_dev *dev = port->dev;
592b285192aSMauro Carvalho Chehab 	unsigned int i, j, n;
593b285192aSMauro Carvalho Chehab 
594e39682b5SMauro Carvalho Chehab 	pr_info("%s: risc disasm: %p [dma=0x%08lx]\n",
595b285192aSMauro Carvalho Chehab 	       dev->name, risc->cpu, (unsigned long)risc->dma);
596b285192aSMauro Carvalho Chehab 	for (i = 0; i < (risc->size >> 2); i += n) {
597e39682b5SMauro Carvalho Chehab 		pr_info("%s:   %04d:", dev->name, i);
598b285192aSMauro Carvalho Chehab 		n = cx23885_risc_decode(le32_to_cpu(risc->cpu[i]));
599b285192aSMauro Carvalho Chehab 		for (j = 1; j < n; j++)
600e39682b5SMauro Carvalho Chehab 			pr_info("%s:   %04d: 0x%08x [ arg #%d ]\n",
601b285192aSMauro Carvalho Chehab 				dev->name, i + j, risc->cpu[i + j], j);
602b285192aSMauro Carvalho Chehab 		if (risc->cpu[i] == cpu_to_le32(RISC_JUMP))
603b285192aSMauro Carvalho Chehab 			break;
604b285192aSMauro Carvalho Chehab 	}
605b285192aSMauro Carvalho Chehab }
606b285192aSMauro Carvalho Chehab 
cx23885_clear_bridge_error(struct cx23885_dev * dev)60795f408bbSBrad Love static void cx23885_clear_bridge_error(struct cx23885_dev *dev)
60895f408bbSBrad Love {
6094bd46aa0SBrad Love 	uint32_t reg1_val, reg2_val;
6104bd46aa0SBrad Love 
6114bd46aa0SBrad Love 	if (!dev->need_dma_reset)
6124bd46aa0SBrad Love 		return;
6134bd46aa0SBrad Love 
6144bd46aa0SBrad Love 	reg1_val = cx_read(TC_REQ); /* read-only */
6154bd46aa0SBrad Love 	reg2_val = cx_read(TC_REQ_SET);
61695f408bbSBrad Love 
61795f408bbSBrad Love 	if (reg1_val && reg2_val) {
61895f408bbSBrad Love 		cx_write(TC_REQ, reg1_val);
61995f408bbSBrad Love 		cx_write(TC_REQ_SET, reg2_val);
62095f408bbSBrad Love 		cx_read(VID_B_DMA);
62195f408bbSBrad Love 		cx_read(VBI_B_DMA);
62295f408bbSBrad Love 		cx_read(VID_C_DMA);
62395f408bbSBrad Love 		cx_read(VBI_C_DMA);
62495f408bbSBrad Love 
62595f408bbSBrad Love 		dev_info(&dev->pci->dev,
62695f408bbSBrad Love 			"dma in progress detected 0x%08x 0x%08x, clearing\n",
62795f408bbSBrad Love 			reg1_val, reg2_val);
62895f408bbSBrad Love 	}
62995f408bbSBrad Love }
63095f408bbSBrad Love 
cx23885_shutdown(struct cx23885_dev * dev)631b285192aSMauro Carvalho Chehab static void cx23885_shutdown(struct cx23885_dev *dev)
632b285192aSMauro Carvalho Chehab {
633b285192aSMauro Carvalho Chehab 	/* disable RISC controller */
634b285192aSMauro Carvalho Chehab 	cx_write(DEV_CNTRL2, 0);
635b285192aSMauro Carvalho Chehab 
636b285192aSMauro Carvalho Chehab 	/* Disable all IR activity */
637b285192aSMauro Carvalho Chehab 	cx_write(IR_CNTRL_REG, 0);
638b285192aSMauro Carvalho Chehab 
639b285192aSMauro Carvalho Chehab 	/* Disable Video A/B activity */
640b285192aSMauro Carvalho Chehab 	cx_write(VID_A_DMA_CTL, 0);
641b285192aSMauro Carvalho Chehab 	cx_write(VID_B_DMA_CTL, 0);
642b285192aSMauro Carvalho Chehab 	cx_write(VID_C_DMA_CTL, 0);
643b285192aSMauro Carvalho Chehab 
644b285192aSMauro Carvalho Chehab 	/* Disable Audio activity */
645b285192aSMauro Carvalho Chehab 	cx_write(AUD_INT_DMA_CTL, 0);
646b285192aSMauro Carvalho Chehab 	cx_write(AUD_EXT_DMA_CTL, 0);
647b285192aSMauro Carvalho Chehab 
648b285192aSMauro Carvalho Chehab 	/* Disable Serial port */
649b285192aSMauro Carvalho Chehab 	cx_write(UART_CTL, 0);
650b285192aSMauro Carvalho Chehab 
651b285192aSMauro Carvalho Chehab 	/* Disable Interrupts */
652b285192aSMauro Carvalho Chehab 	cx23885_irq_disable_all(dev);
653b285192aSMauro Carvalho Chehab 	cx_write(VID_A_INT_MSK, 0);
654b285192aSMauro Carvalho Chehab 	cx_write(VID_B_INT_MSK, 0);
655b285192aSMauro Carvalho Chehab 	cx_write(VID_C_INT_MSK, 0);
656b285192aSMauro Carvalho Chehab 	cx_write(AUDIO_INT_INT_MSK, 0);
657b285192aSMauro Carvalho Chehab 	cx_write(AUDIO_EXT_INT_MSK, 0);
658b285192aSMauro Carvalho Chehab 
659b285192aSMauro Carvalho Chehab }
660b285192aSMauro Carvalho Chehab 
cx23885_reset(struct cx23885_dev * dev)661b285192aSMauro Carvalho Chehab static void cx23885_reset(struct cx23885_dev *dev)
662b285192aSMauro Carvalho Chehab {
663b285192aSMauro Carvalho Chehab 	dprintk(1, "%s()\n", __func__);
664b285192aSMauro Carvalho Chehab 
665b285192aSMauro Carvalho Chehab 	cx23885_shutdown(dev);
666b285192aSMauro Carvalho Chehab 
667b285192aSMauro Carvalho Chehab 	cx_write(PCI_INT_STAT, 0xffffffff);
668b285192aSMauro Carvalho Chehab 	cx_write(VID_A_INT_STAT, 0xffffffff);
669b285192aSMauro Carvalho Chehab 	cx_write(VID_B_INT_STAT, 0xffffffff);
670b285192aSMauro Carvalho Chehab 	cx_write(VID_C_INT_STAT, 0xffffffff);
671b285192aSMauro Carvalho Chehab 	cx_write(AUDIO_INT_INT_STAT, 0xffffffff);
672b285192aSMauro Carvalho Chehab 	cx_write(AUDIO_EXT_INT_STAT, 0xffffffff);
673b285192aSMauro Carvalho Chehab 	cx_write(CLK_DELAY, cx_read(CLK_DELAY) & 0x80000000);
674b285192aSMauro Carvalho Chehab 	cx_write(PAD_CTRL, 0x00500300);
675b285192aSMauro Carvalho Chehab 
67695f408bbSBrad Love 	/* clear dma in progress */
67795f408bbSBrad Love 	cx23885_clear_bridge_error(dev);
67871be8deeSJia-Ju Bai 	msleep(100);
679b285192aSMauro Carvalho Chehab 
680b285192aSMauro Carvalho Chehab 	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH01],
681b285192aSMauro Carvalho Chehab 		720*4, 0);
682b285192aSMauro Carvalho Chehab 	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH02], 128, 0);
683b285192aSMauro Carvalho Chehab 	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH03],
684b285192aSMauro Carvalho Chehab 		188*4, 0);
685b285192aSMauro Carvalho Chehab 	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH04], 128, 0);
686b285192aSMauro Carvalho Chehab 	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH05], 128, 0);
687b285192aSMauro Carvalho Chehab 	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH06],
688b285192aSMauro Carvalho Chehab 		188*4, 0);
689b285192aSMauro Carvalho Chehab 	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH07], 128, 0);
690b285192aSMauro Carvalho Chehab 	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH08], 128, 0);
691b285192aSMauro Carvalho Chehab 	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH09], 128, 0);
692b285192aSMauro Carvalho Chehab 
693b285192aSMauro Carvalho Chehab 	cx23885_gpio_setup(dev);
69495f408bbSBrad Love 
69595f408bbSBrad Love 	cx23885_irq_get_mask(dev);
69695f408bbSBrad Love 
69795f408bbSBrad Love 	/* clear dma in progress */
69895f408bbSBrad Love 	cx23885_clear_bridge_error(dev);
699b285192aSMauro Carvalho Chehab }
700b285192aSMauro Carvalho Chehab 
701b285192aSMauro Carvalho Chehab 
cx23885_pci_quirks(struct cx23885_dev * dev)702b285192aSMauro Carvalho Chehab static int cx23885_pci_quirks(struct cx23885_dev *dev)
703b285192aSMauro Carvalho Chehab {
704b285192aSMauro Carvalho Chehab 	dprintk(1, "%s()\n", __func__);
705b285192aSMauro Carvalho Chehab 
706b285192aSMauro Carvalho Chehab 	/* The cx23885 bridge has a weird bug which causes NMI to be asserted
707b285192aSMauro Carvalho Chehab 	 * when DMA begins if RDR_TLCTL0 bit4 is not cleared. It does not
708b285192aSMauro Carvalho Chehab 	 * occur on the cx23887 bridge.
709b285192aSMauro Carvalho Chehab 	 */
710b285192aSMauro Carvalho Chehab 	if (dev->bridge == CX23885_BRIDGE_885)
711b285192aSMauro Carvalho Chehab 		cx_clear(RDR_TLCTL0, 1 << 4);
712b285192aSMauro Carvalho Chehab 
71395f408bbSBrad Love 	/* clear dma in progress */
71495f408bbSBrad Love 	cx23885_clear_bridge_error(dev);
715b285192aSMauro Carvalho Chehab 	return 0;
716b285192aSMauro Carvalho Chehab }
717b285192aSMauro Carvalho Chehab 
get_resources(struct cx23885_dev * dev)718b285192aSMauro Carvalho Chehab static int get_resources(struct cx23885_dev *dev)
719b285192aSMauro Carvalho Chehab {
720b285192aSMauro Carvalho Chehab 	if (request_mem_region(pci_resource_start(dev->pci, 0),
721b285192aSMauro Carvalho Chehab 			       pci_resource_len(dev->pci, 0),
722b285192aSMauro Carvalho Chehab 			       dev->name))
723b285192aSMauro Carvalho Chehab 		return 0;
724b285192aSMauro Carvalho Chehab 
725e39682b5SMauro Carvalho Chehab 	pr_err("%s: can't get MMIO memory @ 0x%llx\n",
726b285192aSMauro Carvalho Chehab 	       dev->name, (unsigned long long)pci_resource_start(dev->pci, 0));
727b285192aSMauro Carvalho Chehab 
728b285192aSMauro Carvalho Chehab 	return -EBUSY;
729b285192aSMauro Carvalho Chehab }
730b285192aSMauro Carvalho Chehab 
cx23885_init_tsport(struct cx23885_dev * dev,struct cx23885_tsport * port,int portno)731b285192aSMauro Carvalho Chehab static int cx23885_init_tsport(struct cx23885_dev *dev,
732b285192aSMauro Carvalho Chehab 	struct cx23885_tsport *port, int portno)
733b285192aSMauro Carvalho Chehab {
734b285192aSMauro Carvalho Chehab 	dprintk(1, "%s(portno=%d)\n", __func__, portno);
735b285192aSMauro Carvalho Chehab 
736b285192aSMauro Carvalho Chehab 	/* Transport bus init dma queue  - Common settings */
737b285192aSMauro Carvalho Chehab 	port->dma_ctl_val        = 0x11; /* Enable RISC controller and Fifo */
738b285192aSMauro Carvalho Chehab 	port->ts_int_msk_val     = 0x1111; /* TS port bits for RISC */
739b285192aSMauro Carvalho Chehab 	port->vld_misc_val       = 0x0;
740b285192aSMauro Carvalho Chehab 	port->hw_sop_ctrl_val    = (0x47 << 16 | 188 << 4);
741b285192aSMauro Carvalho Chehab 
742b285192aSMauro Carvalho Chehab 	spin_lock_init(&port->slock);
743b285192aSMauro Carvalho Chehab 	port->dev = dev;
744b285192aSMauro Carvalho Chehab 	port->nr = portno;
745b285192aSMauro Carvalho Chehab 
746b285192aSMauro Carvalho Chehab 	INIT_LIST_HEAD(&port->mpegq.active);
747b285192aSMauro Carvalho Chehab 	mutex_init(&port->frontends.lock);
748b285192aSMauro Carvalho Chehab 	INIT_LIST_HEAD(&port->frontends.felist);
749b285192aSMauro Carvalho Chehab 	port->frontends.active_fe_id = 0;
750b285192aSMauro Carvalho Chehab 
751b285192aSMauro Carvalho Chehab 	/* This should be hardcoded allow a single frontend
752b285192aSMauro Carvalho Chehab 	 * attachment to this tsport, keeping the -dvb.c
753b285192aSMauro Carvalho Chehab 	 * code clean and safe.
754b285192aSMauro Carvalho Chehab 	 */
755b285192aSMauro Carvalho Chehab 	if (!port->num_frontends)
756b285192aSMauro Carvalho Chehab 		port->num_frontends = 1;
757b285192aSMauro Carvalho Chehab 
758b285192aSMauro Carvalho Chehab 	switch (portno) {
759b285192aSMauro Carvalho Chehab 	case 1:
760b285192aSMauro Carvalho Chehab 		port->reg_gpcnt          = VID_B_GPCNT;
761b285192aSMauro Carvalho Chehab 		port->reg_gpcnt_ctl      = VID_B_GPCNT_CTL;
762b285192aSMauro Carvalho Chehab 		port->reg_dma_ctl        = VID_B_DMA_CTL;
763b285192aSMauro Carvalho Chehab 		port->reg_lngth          = VID_B_LNGTH;
764b285192aSMauro Carvalho Chehab 		port->reg_hw_sop_ctrl    = VID_B_HW_SOP_CTL;
765b285192aSMauro Carvalho Chehab 		port->reg_gen_ctrl       = VID_B_GEN_CTL;
766b285192aSMauro Carvalho Chehab 		port->reg_bd_pkt_status  = VID_B_BD_PKT_STATUS;
767b285192aSMauro Carvalho Chehab 		port->reg_sop_status     = VID_B_SOP_STATUS;
768b285192aSMauro Carvalho Chehab 		port->reg_fifo_ovfl_stat = VID_B_FIFO_OVFL_STAT;
769b285192aSMauro Carvalho Chehab 		port->reg_vld_misc       = VID_B_VLD_MISC;
770b285192aSMauro Carvalho Chehab 		port->reg_ts_clk_en      = VID_B_TS_CLK_EN;
771b285192aSMauro Carvalho Chehab 		port->reg_src_sel        = VID_B_SRC_SEL;
772b285192aSMauro Carvalho Chehab 		port->reg_ts_int_msk     = VID_B_INT_MSK;
773b285192aSMauro Carvalho Chehab 		port->reg_ts_int_stat    = VID_B_INT_STAT;
774b285192aSMauro Carvalho Chehab 		port->sram_chno          = SRAM_CH03; /* VID_B */
775b285192aSMauro Carvalho Chehab 		port->pci_irqmask        = 0x02; /* VID_B bit1 */
776b285192aSMauro Carvalho Chehab 		break;
777b285192aSMauro Carvalho Chehab 	case 2:
778b285192aSMauro Carvalho Chehab 		port->reg_gpcnt          = VID_C_GPCNT;
779b285192aSMauro Carvalho Chehab 		port->reg_gpcnt_ctl      = VID_C_GPCNT_CTL;
780b285192aSMauro Carvalho Chehab 		port->reg_dma_ctl        = VID_C_DMA_CTL;
781b285192aSMauro Carvalho Chehab 		port->reg_lngth          = VID_C_LNGTH;
782b285192aSMauro Carvalho Chehab 		port->reg_hw_sop_ctrl    = VID_C_HW_SOP_CTL;
783b285192aSMauro Carvalho Chehab 		port->reg_gen_ctrl       = VID_C_GEN_CTL;
784b285192aSMauro Carvalho Chehab 		port->reg_bd_pkt_status  = VID_C_BD_PKT_STATUS;
785b285192aSMauro Carvalho Chehab 		port->reg_sop_status     = VID_C_SOP_STATUS;
786b285192aSMauro Carvalho Chehab 		port->reg_fifo_ovfl_stat = VID_C_FIFO_OVFL_STAT;
787b285192aSMauro Carvalho Chehab 		port->reg_vld_misc       = VID_C_VLD_MISC;
788b285192aSMauro Carvalho Chehab 		port->reg_ts_clk_en      = VID_C_TS_CLK_EN;
789b285192aSMauro Carvalho Chehab 		port->reg_src_sel        = 0;
790b285192aSMauro Carvalho Chehab 		port->reg_ts_int_msk     = VID_C_INT_MSK;
791b285192aSMauro Carvalho Chehab 		port->reg_ts_int_stat    = VID_C_INT_STAT;
792b285192aSMauro Carvalho Chehab 		port->sram_chno          = SRAM_CH06; /* VID_C */
793b285192aSMauro Carvalho Chehab 		port->pci_irqmask        = 0x04; /* VID_C bit2 */
794b285192aSMauro Carvalho Chehab 		break;
795b285192aSMauro Carvalho Chehab 	default:
796b285192aSMauro Carvalho Chehab 		BUG();
797b285192aSMauro Carvalho Chehab 	}
798b285192aSMauro Carvalho Chehab 
799b285192aSMauro Carvalho Chehab 	return 0;
800b285192aSMauro Carvalho Chehab }
801b285192aSMauro Carvalho Chehab 
cx23885_dev_checkrevision(struct cx23885_dev * dev)802b285192aSMauro Carvalho Chehab static void cx23885_dev_checkrevision(struct cx23885_dev *dev)
803b285192aSMauro Carvalho Chehab {
804b285192aSMauro Carvalho Chehab 	switch (cx_read(RDR_CFG2) & 0xff) {
805b285192aSMauro Carvalho Chehab 	case 0x00:
806b285192aSMauro Carvalho Chehab 		/* cx23885 */
807b285192aSMauro Carvalho Chehab 		dev->hwrevision = 0xa0;
808b285192aSMauro Carvalho Chehab 		break;
809b285192aSMauro Carvalho Chehab 	case 0x01:
810b285192aSMauro Carvalho Chehab 		/* CX23885-12Z */
811b285192aSMauro Carvalho Chehab 		dev->hwrevision = 0xa1;
812b285192aSMauro Carvalho Chehab 		break;
813b285192aSMauro Carvalho Chehab 	case 0x02:
814b285192aSMauro Carvalho Chehab 		/* CX23885-13Z/14Z */
815b285192aSMauro Carvalho Chehab 		dev->hwrevision = 0xb0;
816b285192aSMauro Carvalho Chehab 		break;
817b285192aSMauro Carvalho Chehab 	case 0x03:
818b285192aSMauro Carvalho Chehab 		if (dev->pci->device == 0x8880) {
819b285192aSMauro Carvalho Chehab 			/* CX23888-21Z/22Z */
820b285192aSMauro Carvalho Chehab 			dev->hwrevision = 0xc0;
821b285192aSMauro Carvalho Chehab 		} else {
822b285192aSMauro Carvalho Chehab 			/* CX23885-14Z */
823b285192aSMauro Carvalho Chehab 			dev->hwrevision = 0xa4;
824b285192aSMauro Carvalho Chehab 		}
825b285192aSMauro Carvalho Chehab 		break;
826b285192aSMauro Carvalho Chehab 	case 0x04:
827b285192aSMauro Carvalho Chehab 		if (dev->pci->device == 0x8880) {
828b285192aSMauro Carvalho Chehab 			/* CX23888-31Z */
829b285192aSMauro Carvalho Chehab 			dev->hwrevision = 0xd0;
830b285192aSMauro Carvalho Chehab 		} else {
831b285192aSMauro Carvalho Chehab 			/* CX23885-15Z, CX23888-31Z */
832b285192aSMauro Carvalho Chehab 			dev->hwrevision = 0xa5;
833b285192aSMauro Carvalho Chehab 		}
834b285192aSMauro Carvalho Chehab 		break;
835b285192aSMauro Carvalho Chehab 	case 0x0e:
836b285192aSMauro Carvalho Chehab 		/* CX23887-15Z */
837b285192aSMauro Carvalho Chehab 		dev->hwrevision = 0xc0;
838b285192aSMauro Carvalho Chehab 		break;
839b285192aSMauro Carvalho Chehab 	case 0x0f:
840b285192aSMauro Carvalho Chehab 		/* CX23887-14Z */
841b285192aSMauro Carvalho Chehab 		dev->hwrevision = 0xb1;
842b285192aSMauro Carvalho Chehab 		break;
843b285192aSMauro Carvalho Chehab 	default:
844e39682b5SMauro Carvalho Chehab 		pr_err("%s() New hardware revision found 0x%x\n",
845b285192aSMauro Carvalho Chehab 		       __func__, dev->hwrevision);
846b285192aSMauro Carvalho Chehab 	}
847b285192aSMauro Carvalho Chehab 	if (dev->hwrevision)
848e39682b5SMauro Carvalho Chehab 		pr_info("%s() Hardware revision = 0x%02x\n",
849b285192aSMauro Carvalho Chehab 			__func__, dev->hwrevision);
850b285192aSMauro Carvalho Chehab 	else
851e39682b5SMauro Carvalho Chehab 		pr_err("%s() Hardware revision unknown 0x%x\n",
852b285192aSMauro Carvalho Chehab 		       __func__, dev->hwrevision);
853b285192aSMauro Carvalho Chehab }
854b285192aSMauro Carvalho Chehab 
855b285192aSMauro Carvalho Chehab /* Find the first v4l2_subdev member of the group id in hw */
cx23885_find_hw(struct cx23885_dev * dev,u32 hw)856b285192aSMauro Carvalho Chehab struct v4l2_subdev *cx23885_find_hw(struct cx23885_dev *dev, u32 hw)
857b285192aSMauro Carvalho Chehab {
858b285192aSMauro Carvalho Chehab 	struct v4l2_subdev *result = NULL;
859b285192aSMauro Carvalho Chehab 	struct v4l2_subdev *sd;
860b285192aSMauro Carvalho Chehab 
861b285192aSMauro Carvalho Chehab 	spin_lock(&dev->v4l2_dev.lock);
862b285192aSMauro Carvalho Chehab 	v4l2_device_for_each_subdev(sd, &dev->v4l2_dev) {
863b285192aSMauro Carvalho Chehab 		if (sd->grp_id == hw) {
864b285192aSMauro Carvalho Chehab 			result = sd;
865b285192aSMauro Carvalho Chehab 			break;
866b285192aSMauro Carvalho Chehab 		}
867b285192aSMauro Carvalho Chehab 	}
868b285192aSMauro Carvalho Chehab 	spin_unlock(&dev->v4l2_dev.lock);
869b285192aSMauro Carvalho Chehab 	return result;
870b285192aSMauro Carvalho Chehab }
871b285192aSMauro Carvalho Chehab 
cx23885_dev_setup(struct cx23885_dev * dev)872b285192aSMauro Carvalho Chehab static int cx23885_dev_setup(struct cx23885_dev *dev)
873b285192aSMauro Carvalho Chehab {
874b285192aSMauro Carvalho Chehab 	int i;
875b285192aSMauro Carvalho Chehab 
876b285192aSMauro Carvalho Chehab 	spin_lock_init(&dev->pci_irqmask_lock);
877af7f388eSDavid Howells 	spin_lock_init(&dev->slock);
878b285192aSMauro Carvalho Chehab 
879b285192aSMauro Carvalho Chehab 	mutex_init(&dev->lock);
880b285192aSMauro Carvalho Chehab 	mutex_init(&dev->gpio_lock);
881b285192aSMauro Carvalho Chehab 
882b285192aSMauro Carvalho Chehab 	atomic_inc(&dev->refcount);
883b285192aSMauro Carvalho Chehab 
884b285192aSMauro Carvalho Chehab 	dev->nr = cx23885_devcount++;
885b285192aSMauro Carvalho Chehab 	sprintf(dev->name, "cx23885[%d]", dev->nr);
886b285192aSMauro Carvalho Chehab 
887b285192aSMauro Carvalho Chehab 	/* Configure the internal memory */
888b285192aSMauro Carvalho Chehab 	if (dev->pci->device == 0x8880) {
8895da1a682SBrad Love 		/* Could be 887 or 888, assume an 888 default */
8905da1a682SBrad Love 		dev->bridge = CX23885_BRIDGE_888;
891b285192aSMauro Carvalho Chehab 		/* Apply a sensible clock frequency for the PCIe bridge */
8925da1a682SBrad Love 		dev->clk_freq = 50000000;
893b285192aSMauro Carvalho Chehab 		dev->sram_channels = cx23887_sram_channels;
894b285192aSMauro Carvalho Chehab 	} else
895b285192aSMauro Carvalho Chehab 	if (dev->pci->device == 0x8852) {
896b285192aSMauro Carvalho Chehab 		dev->bridge = CX23885_BRIDGE_885;
897b285192aSMauro Carvalho Chehab 		/* Apply a sensible clock frequency for the PCIe bridge */
898b285192aSMauro Carvalho Chehab 		dev->clk_freq = 28000000;
899b285192aSMauro Carvalho Chehab 		dev->sram_channels = cx23885_sram_channels;
900b285192aSMauro Carvalho Chehab 	} else
901b285192aSMauro Carvalho Chehab 		BUG();
902b285192aSMauro Carvalho Chehab 
903b285192aSMauro Carvalho Chehab 	dprintk(1, "%s() Memory configured for PCIe bridge type %d\n",
904b285192aSMauro Carvalho Chehab 		__func__, dev->bridge);
905b285192aSMauro Carvalho Chehab 
906b285192aSMauro Carvalho Chehab 	/* board config */
907b285192aSMauro Carvalho Chehab 	dev->board = UNSET;
908b285192aSMauro Carvalho Chehab 	if (card[dev->nr] < cx23885_bcount)
909b285192aSMauro Carvalho Chehab 		dev->board = card[dev->nr];
910b285192aSMauro Carvalho Chehab 	for (i = 0; UNSET == dev->board  &&  i < cx23885_idcount; i++)
911b285192aSMauro Carvalho Chehab 		if (dev->pci->subsystem_vendor == cx23885_subids[i].subvendor &&
912b285192aSMauro Carvalho Chehab 		    dev->pci->subsystem_device == cx23885_subids[i].subdevice)
913b285192aSMauro Carvalho Chehab 			dev->board = cx23885_subids[i].card;
914b285192aSMauro Carvalho Chehab 	if (UNSET == dev->board) {
915b285192aSMauro Carvalho Chehab 		dev->board = CX23885_BOARD_UNKNOWN;
916b285192aSMauro Carvalho Chehab 		cx23885_card_list(dev);
917b285192aSMauro Carvalho Chehab 	}
918b285192aSMauro Carvalho Chehab 
919c00ba2c1SBrad Love 	if (dev->pci->device == 0x8852) {
920c00ba2c1SBrad Love 		/* no DIF on cx23885, so no analog tuner support possible */
921c00ba2c1SBrad Love 		if (dev->board == CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC)
922c00ba2c1SBrad Love 			dev->board = CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC_885;
923c00ba2c1SBrad Love 		else if (dev->board == CX23885_BOARD_HAUPPAUGE_QUADHD_DVB)
924c00ba2c1SBrad Love 			dev->board = CX23885_BOARD_HAUPPAUGE_QUADHD_DVB_885;
925c00ba2c1SBrad Love 	}
926c00ba2c1SBrad Love 
927b285192aSMauro Carvalho Chehab 	/* If the user specific a clk freq override, apply it */
928b285192aSMauro Carvalho Chehab 	if (cx23885_boards[dev->board].clk_freq > 0)
929b285192aSMauro Carvalho Chehab 		dev->clk_freq = cx23885_boards[dev->board].clk_freq;
930b285192aSMauro Carvalho Chehab 
931779c79d4SBrad Love 	if (dev->board == CX23885_BOARD_HAUPPAUGE_IMPACTVCBE &&
932779c79d4SBrad Love 		dev->pci->subsystem_device == 0x7137) {
933779c79d4SBrad Love 		/* Hauppauge ImpactVCBe device ID 0x7137 is populated
934779c79d4SBrad Love 		 * with an 888, and a 25Mhz crystal, instead of the
935779c79d4SBrad Love 		 * usual third overtone 50Mhz. The default clock rate must
936779c79d4SBrad Love 		 * be overridden so the cx25840 is properly configured
937779c79d4SBrad Love 		 */
938779c79d4SBrad Love 		dev->clk_freq = 25000000;
939779c79d4SBrad Love 	}
940779c79d4SBrad Love 
941b285192aSMauro Carvalho Chehab 	dev->pci_bus  = dev->pci->bus->number;
942b285192aSMauro Carvalho Chehab 	dev->pci_slot = PCI_SLOT(dev->pci->devfn);
943b285192aSMauro Carvalho Chehab 	cx23885_irq_add(dev, 0x001f00);
944b285192aSMauro Carvalho Chehab 
945b285192aSMauro Carvalho Chehab 	/* External Master 1 Bus */
946b285192aSMauro Carvalho Chehab 	dev->i2c_bus[0].nr = 0;
947b285192aSMauro Carvalho Chehab 	dev->i2c_bus[0].dev = dev;
948b285192aSMauro Carvalho Chehab 	dev->i2c_bus[0].reg_stat  = I2C1_STAT;
949b285192aSMauro Carvalho Chehab 	dev->i2c_bus[0].reg_ctrl  = I2C1_CTRL;
950b285192aSMauro Carvalho Chehab 	dev->i2c_bus[0].reg_addr  = I2C1_ADDR;
951b285192aSMauro Carvalho Chehab 	dev->i2c_bus[0].reg_rdata = I2C1_RDATA;
952b285192aSMauro Carvalho Chehab 	dev->i2c_bus[0].reg_wdata = I2C1_WDATA;
953b285192aSMauro Carvalho Chehab 	dev->i2c_bus[0].i2c_period = (0x9d << 24); /* 100kHz */
954b285192aSMauro Carvalho Chehab 
955b285192aSMauro Carvalho Chehab 	/* External Master 2 Bus */
956b285192aSMauro Carvalho Chehab 	dev->i2c_bus[1].nr = 1;
957b285192aSMauro Carvalho Chehab 	dev->i2c_bus[1].dev = dev;
958b285192aSMauro Carvalho Chehab 	dev->i2c_bus[1].reg_stat  = I2C2_STAT;
959b285192aSMauro Carvalho Chehab 	dev->i2c_bus[1].reg_ctrl  = I2C2_CTRL;
960b285192aSMauro Carvalho Chehab 	dev->i2c_bus[1].reg_addr  = I2C2_ADDR;
961b285192aSMauro Carvalho Chehab 	dev->i2c_bus[1].reg_rdata = I2C2_RDATA;
962b285192aSMauro Carvalho Chehab 	dev->i2c_bus[1].reg_wdata = I2C2_WDATA;
963b285192aSMauro Carvalho Chehab 	dev->i2c_bus[1].i2c_period = (0x9d << 24); /* 100kHz */
964b285192aSMauro Carvalho Chehab 
965b285192aSMauro Carvalho Chehab 	/* Internal Master 3 Bus */
966b285192aSMauro Carvalho Chehab 	dev->i2c_bus[2].nr = 2;
967b285192aSMauro Carvalho Chehab 	dev->i2c_bus[2].dev = dev;
968b285192aSMauro Carvalho Chehab 	dev->i2c_bus[2].reg_stat  = I2C3_STAT;
969b285192aSMauro Carvalho Chehab 	dev->i2c_bus[2].reg_ctrl  = I2C3_CTRL;
970b285192aSMauro Carvalho Chehab 	dev->i2c_bus[2].reg_addr  = I2C3_ADDR;
971b285192aSMauro Carvalho Chehab 	dev->i2c_bus[2].reg_rdata = I2C3_RDATA;
972b285192aSMauro Carvalho Chehab 	dev->i2c_bus[2].reg_wdata = I2C3_WDATA;
973b285192aSMauro Carvalho Chehab 	dev->i2c_bus[2].i2c_period = (0x07 << 24); /* 1.95MHz */
974b285192aSMauro Carvalho Chehab 
975b285192aSMauro Carvalho Chehab 	if ((cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) ||
976b285192aSMauro Carvalho Chehab 		(cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER))
977b285192aSMauro Carvalho Chehab 		cx23885_init_tsport(dev, &dev->ts1, 1);
978b285192aSMauro Carvalho Chehab 
979b285192aSMauro Carvalho Chehab 	if ((cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) ||
980b285192aSMauro Carvalho Chehab 		(cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER))
981b285192aSMauro Carvalho Chehab 		cx23885_init_tsport(dev, &dev->ts2, 2);
982b285192aSMauro Carvalho Chehab 
983b285192aSMauro Carvalho Chehab 	if (get_resources(dev) < 0) {
984e39682b5SMauro Carvalho Chehab 		pr_err("CORE %s No more PCIe resources for subsystem: %04x:%04x\n",
985b285192aSMauro Carvalho Chehab 		       dev->name, dev->pci->subsystem_vendor,
986b285192aSMauro Carvalho Chehab 		       dev->pci->subsystem_device);
987b285192aSMauro Carvalho Chehab 
988b285192aSMauro Carvalho Chehab 		cx23885_devcount--;
989b285192aSMauro Carvalho Chehab 		return -ENODEV;
990b285192aSMauro Carvalho Chehab 	}
991b285192aSMauro Carvalho Chehab 
992b285192aSMauro Carvalho Chehab 	/* PCIe stuff */
993b285192aSMauro Carvalho Chehab 	dev->lmmio = ioremap(pci_resource_start(dev->pci, 0),
994b285192aSMauro Carvalho Chehab 			     pci_resource_len(dev->pci, 0));
995b285192aSMauro Carvalho Chehab 
996b285192aSMauro Carvalho Chehab 	dev->bmmio = (u8 __iomem *)dev->lmmio;
997b285192aSMauro Carvalho Chehab 
998e39682b5SMauro Carvalho Chehab 	pr_info("CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
999b285192aSMauro Carvalho Chehab 		dev->name, dev->pci->subsystem_vendor,
1000b285192aSMauro Carvalho Chehab 		dev->pci->subsystem_device, cx23885_boards[dev->board].name,
1001b285192aSMauro Carvalho Chehab 		dev->board, card[dev->nr] == dev->board ?
1002b285192aSMauro Carvalho Chehab 		"insmod option" : "autodetected");
1003b285192aSMauro Carvalho Chehab 
1004b285192aSMauro Carvalho Chehab 	cx23885_pci_quirks(dev);
1005b285192aSMauro Carvalho Chehab 
1006b285192aSMauro Carvalho Chehab 	/* Assume some sensible defaults */
1007b285192aSMauro Carvalho Chehab 	dev->tuner_type = cx23885_boards[dev->board].tuner_type;
1008b285192aSMauro Carvalho Chehab 	dev->tuner_addr = cx23885_boards[dev->board].tuner_addr;
1009b285192aSMauro Carvalho Chehab 	dev->tuner_bus = cx23885_boards[dev->board].tuner_bus;
1010b285192aSMauro Carvalho Chehab 	dev->radio_type = cx23885_boards[dev->board].radio_type;
1011b285192aSMauro Carvalho Chehab 	dev->radio_addr = cx23885_boards[dev->board].radio_addr;
1012b285192aSMauro Carvalho Chehab 
1013b285192aSMauro Carvalho Chehab 	dprintk(1, "%s() tuner_type = 0x%x tuner_addr = 0x%x tuner_bus = %d\n",
1014b285192aSMauro Carvalho Chehab 		__func__, dev->tuner_type, dev->tuner_addr, dev->tuner_bus);
1015b285192aSMauro Carvalho Chehab 	dprintk(1, "%s() radio_type = 0x%x radio_addr = 0x%x\n",
1016b285192aSMauro Carvalho Chehab 		__func__, dev->radio_type, dev->radio_addr);
1017b285192aSMauro Carvalho Chehab 
1018b285192aSMauro Carvalho Chehab 	/* The cx23417 encoder has GPIO's that need to be initialised
1019b285192aSMauro Carvalho Chehab 	 * before DVB, so that demodulators and tuners are out of
1020b285192aSMauro Carvalho Chehab 	 * reset before DVB uses them.
1021b285192aSMauro Carvalho Chehab 	 */
1022b285192aSMauro Carvalho Chehab 	if ((cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) ||
1023b285192aSMauro Carvalho Chehab 		(cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER))
1024b285192aSMauro Carvalho Chehab 			cx23885_mc417_init(dev);
1025b285192aSMauro Carvalho Chehab 
1026b285192aSMauro Carvalho Chehab 	/* init hardware */
1027b285192aSMauro Carvalho Chehab 	cx23885_reset(dev);
1028b285192aSMauro Carvalho Chehab 
1029b285192aSMauro Carvalho Chehab 	cx23885_i2c_register(&dev->i2c_bus[0]);
1030b285192aSMauro Carvalho Chehab 	cx23885_i2c_register(&dev->i2c_bus[1]);
1031b285192aSMauro Carvalho Chehab 	cx23885_i2c_register(&dev->i2c_bus[2]);
1032b285192aSMauro Carvalho Chehab 	cx23885_card_setup(dev);
10333aab15afSHans Verkuil 	call_all(dev, tuner, standby);
1034b285192aSMauro Carvalho Chehab 	cx23885_ir_init(dev);
1035b285192aSMauro Carvalho Chehab 
10366c43a217SHans Verkuil 	if (dev->board == CX23885_BOARD_VIEWCAST_460E) {
10376c43a217SHans Verkuil 		/*
10386c43a217SHans Verkuil 		 * GPIOs 9/8 are input detection bits for the breakout video
10396c43a217SHans Verkuil 		 * (gpio 8) and audio (gpio 9) cables. When they're attached,
10406c43a217SHans Verkuil 		 * this gpios are pulled high. Make sure these GPIOs are marked
10416c43a217SHans Verkuil 		 * as inputs.
10426c43a217SHans Verkuil 		 */
10436c43a217SHans Verkuil 		cx23885_gpio_enable(dev, 0x300, 0);
10446c43a217SHans Verkuil 	}
10456c43a217SHans Verkuil 
1046b285192aSMauro Carvalho Chehab 	if (cx23885_boards[dev->board].porta == CX23885_ANALOG_VIDEO) {
1047b285192aSMauro Carvalho Chehab 		if (cx23885_video_register(dev) < 0) {
1048e39682b5SMauro Carvalho Chehab 			pr_err("%s() Failed to register analog video adapters on VID_A\n",
104907ab29e1SMauro Carvalho Chehab 			       __func__);
1050b285192aSMauro Carvalho Chehab 		}
1051b285192aSMauro Carvalho Chehab 	}
1052b285192aSMauro Carvalho Chehab 
1053b285192aSMauro Carvalho Chehab 	if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) {
1054b285192aSMauro Carvalho Chehab 		if (cx23885_boards[dev->board].num_fds_portb)
1055b285192aSMauro Carvalho Chehab 			dev->ts1.num_frontends =
1056b285192aSMauro Carvalho Chehab 				cx23885_boards[dev->board].num_fds_portb;
1057b285192aSMauro Carvalho Chehab 		if (cx23885_dvb_register(&dev->ts1) < 0) {
1058e39682b5SMauro Carvalho Chehab 			pr_err("%s() Failed to register dvb adapters on VID_B\n",
1059b285192aSMauro Carvalho Chehab 			       __func__);
1060b285192aSMauro Carvalho Chehab 		}
1061b285192aSMauro Carvalho Chehab 	} else
1062b285192aSMauro Carvalho Chehab 	if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) {
1063b285192aSMauro Carvalho Chehab 		if (cx23885_417_register(dev) < 0) {
1064e39682b5SMauro Carvalho Chehab 			pr_err("%s() Failed to register 417 on VID_B\n",
1065b285192aSMauro Carvalho Chehab 			       __func__);
1066b285192aSMauro Carvalho Chehab 		}
1067b285192aSMauro Carvalho Chehab 	}
1068b285192aSMauro Carvalho Chehab 
1069b285192aSMauro Carvalho Chehab 	if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) {
1070b285192aSMauro Carvalho Chehab 		if (cx23885_boards[dev->board].num_fds_portc)
1071b285192aSMauro Carvalho Chehab 			dev->ts2.num_frontends =
1072b285192aSMauro Carvalho Chehab 				cx23885_boards[dev->board].num_fds_portc;
1073b285192aSMauro Carvalho Chehab 		if (cx23885_dvb_register(&dev->ts2) < 0) {
1074e39682b5SMauro Carvalho Chehab 			pr_err("%s() Failed to register dvb on VID_C\n",
1075b285192aSMauro Carvalho Chehab 			       __func__);
1076b285192aSMauro Carvalho Chehab 		}
1077b285192aSMauro Carvalho Chehab 	} else
1078b285192aSMauro Carvalho Chehab 	if (cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER) {
1079b285192aSMauro Carvalho Chehab 		if (cx23885_417_register(dev) < 0) {
1080e39682b5SMauro Carvalho Chehab 			pr_err("%s() Failed to register 417 on VID_C\n",
1081b285192aSMauro Carvalho Chehab 			       __func__);
1082b285192aSMauro Carvalho Chehab 		}
1083b285192aSMauro Carvalho Chehab 	}
1084b285192aSMauro Carvalho Chehab 
1085b285192aSMauro Carvalho Chehab 	cx23885_dev_checkrevision(dev);
1086b285192aSMauro Carvalho Chehab 
1087b285192aSMauro Carvalho Chehab 	/* disable MSI for NetUP cards, otherwise CI is not working */
1088b285192aSMauro Carvalho Chehab 	if (cx23885_boards[dev->board].ci_type > 0)
1089b285192aSMauro Carvalho Chehab 		cx_clear(RDR_RDRCTL1, 1 << 8);
1090b285192aSMauro Carvalho Chehab 
1091b285192aSMauro Carvalho Chehab 	switch (dev->board) {
1092b285192aSMauro Carvalho Chehab 	case CX23885_BOARD_TEVII_S470:
1093b285192aSMauro Carvalho Chehab 	case CX23885_BOARD_TEVII_S471:
1094b285192aSMauro Carvalho Chehab 		cx_clear(RDR_RDRCTL1, 1 << 8);
1095b285192aSMauro Carvalho Chehab 		break;
1096b285192aSMauro Carvalho Chehab 	}
1097b285192aSMauro Carvalho Chehab 
1098b285192aSMauro Carvalho Chehab 	return 0;
1099b285192aSMauro Carvalho Chehab }
1100b285192aSMauro Carvalho Chehab 
cx23885_dev_unregister(struct cx23885_dev * dev)1101b285192aSMauro Carvalho Chehab static void cx23885_dev_unregister(struct cx23885_dev *dev)
1102b285192aSMauro Carvalho Chehab {
1103b285192aSMauro Carvalho Chehab 	release_mem_region(pci_resource_start(dev->pci, 0),
1104b285192aSMauro Carvalho Chehab 			   pci_resource_len(dev->pci, 0));
1105b285192aSMauro Carvalho Chehab 
1106b285192aSMauro Carvalho Chehab 	if (!atomic_dec_and_test(&dev->refcount))
1107b285192aSMauro Carvalho Chehab 		return;
1108b285192aSMauro Carvalho Chehab 
1109b285192aSMauro Carvalho Chehab 	if (cx23885_boards[dev->board].porta == CX23885_ANALOG_VIDEO)
1110b285192aSMauro Carvalho Chehab 		cx23885_video_unregister(dev);
1111b285192aSMauro Carvalho Chehab 
1112b285192aSMauro Carvalho Chehab 	if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB)
1113b285192aSMauro Carvalho Chehab 		cx23885_dvb_unregister(&dev->ts1);
1114b285192aSMauro Carvalho Chehab 
1115b285192aSMauro Carvalho Chehab 	if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER)
1116b285192aSMauro Carvalho Chehab 		cx23885_417_unregister(dev);
1117b285192aSMauro Carvalho Chehab 
1118b285192aSMauro Carvalho Chehab 	if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB)
1119b285192aSMauro Carvalho Chehab 		cx23885_dvb_unregister(&dev->ts2);
1120b285192aSMauro Carvalho Chehab 
1121b285192aSMauro Carvalho Chehab 	if (cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER)
1122b285192aSMauro Carvalho Chehab 		cx23885_417_unregister(dev);
1123b285192aSMauro Carvalho Chehab 
1124b285192aSMauro Carvalho Chehab 	cx23885_i2c_unregister(&dev->i2c_bus[2]);
1125b285192aSMauro Carvalho Chehab 	cx23885_i2c_unregister(&dev->i2c_bus[1]);
1126b285192aSMauro Carvalho Chehab 	cx23885_i2c_unregister(&dev->i2c_bus[0]);
1127b285192aSMauro Carvalho Chehab 
1128b285192aSMauro Carvalho Chehab 	iounmap(dev->lmmio);
1129b285192aSMauro Carvalho Chehab }
1130b285192aSMauro Carvalho Chehab 
cx23885_risc_field(__le32 * rp,struct scatterlist * sglist,unsigned int offset,u32 sync_line,unsigned int bpl,unsigned int padding,unsigned int lines,unsigned int lpi,bool jump)1131b285192aSMauro Carvalho Chehab static __le32 *cx23885_risc_field(__le32 *rp, struct scatterlist *sglist,
1132b285192aSMauro Carvalho Chehab 			       unsigned int offset, u32 sync_line,
1133b285192aSMauro Carvalho Chehab 			       unsigned int bpl, unsigned int padding,
1134453afdd9SHans Verkuil 			       unsigned int lines,  unsigned int lpi, bool jump)
1135b285192aSMauro Carvalho Chehab {
1136b285192aSMauro Carvalho Chehab 	struct scatterlist *sg;
1137b285192aSMauro Carvalho Chehab 	unsigned int line, todo, sol;
1138b285192aSMauro Carvalho Chehab 
1139453afdd9SHans Verkuil 
1140453afdd9SHans Verkuil 	if (jump) {
1141453afdd9SHans Verkuil 		*(rp++) = cpu_to_le32(RISC_JUMP);
1142453afdd9SHans Verkuil 		*(rp++) = cpu_to_le32(0);
1143453afdd9SHans Verkuil 		*(rp++) = cpu_to_le32(0); /* bits 63-32 */
1144453afdd9SHans Verkuil 	}
1145453afdd9SHans Verkuil 
1146b285192aSMauro Carvalho Chehab 	/* sync instruction */
1147b285192aSMauro Carvalho Chehab 	if (sync_line != NO_SYNC_LINE)
1148b285192aSMauro Carvalho Chehab 		*(rp++) = cpu_to_le32(RISC_RESYNC | sync_line);
1149b285192aSMauro Carvalho Chehab 
1150b285192aSMauro Carvalho Chehab 	/* scan lines */
1151b285192aSMauro Carvalho Chehab 	sg = sglist;
1152b285192aSMauro Carvalho Chehab 	for (line = 0; line < lines; line++) {
1153b285192aSMauro Carvalho Chehab 		while (offset && offset >= sg_dma_len(sg)) {
1154b285192aSMauro Carvalho Chehab 			offset -= sg_dma_len(sg);
11557675fe99SHans Verkuil 			sg = sg_next(sg);
1156b285192aSMauro Carvalho Chehab 		}
1157b285192aSMauro Carvalho Chehab 
1158b285192aSMauro Carvalho Chehab 		if (lpi && line > 0 && !(line % lpi))
1159b285192aSMauro Carvalho Chehab 			sol = RISC_SOL | RISC_IRQ1 | RISC_CNT_INC;
1160b285192aSMauro Carvalho Chehab 		else
1161b285192aSMauro Carvalho Chehab 			sol = RISC_SOL;
1162b285192aSMauro Carvalho Chehab 
1163b285192aSMauro Carvalho Chehab 		if (bpl <= sg_dma_len(sg)-offset) {
1164b285192aSMauro Carvalho Chehab 			/* fits into current chunk */
1165b285192aSMauro Carvalho Chehab 			*(rp++) = cpu_to_le32(RISC_WRITE|sol|RISC_EOL|bpl);
1166b285192aSMauro Carvalho Chehab 			*(rp++) = cpu_to_le32(sg_dma_address(sg)+offset);
1167b285192aSMauro Carvalho Chehab 			*(rp++) = cpu_to_le32(0); /* bits 63-32 */
1168b285192aSMauro Carvalho Chehab 			offset += bpl;
1169b285192aSMauro Carvalho Chehab 		} else {
1170b285192aSMauro Carvalho Chehab 			/* scanline needs to be split */
1171b285192aSMauro Carvalho Chehab 			todo = bpl;
1172b285192aSMauro Carvalho Chehab 			*(rp++) = cpu_to_le32(RISC_WRITE|sol|
1173b285192aSMauro Carvalho Chehab 					    (sg_dma_len(sg)-offset));
1174b285192aSMauro Carvalho Chehab 			*(rp++) = cpu_to_le32(sg_dma_address(sg)+offset);
1175b285192aSMauro Carvalho Chehab 			*(rp++) = cpu_to_le32(0); /* bits 63-32 */
1176b285192aSMauro Carvalho Chehab 			todo -= (sg_dma_len(sg)-offset);
1177b285192aSMauro Carvalho Chehab 			offset = 0;
11787675fe99SHans Verkuil 			sg = sg_next(sg);
1179b285192aSMauro Carvalho Chehab 			while (todo > sg_dma_len(sg)) {
1180b285192aSMauro Carvalho Chehab 				*(rp++) = cpu_to_le32(RISC_WRITE|
1181b285192aSMauro Carvalho Chehab 						    sg_dma_len(sg));
1182b285192aSMauro Carvalho Chehab 				*(rp++) = cpu_to_le32(sg_dma_address(sg));
1183b285192aSMauro Carvalho Chehab 				*(rp++) = cpu_to_le32(0); /* bits 63-32 */
1184b285192aSMauro Carvalho Chehab 				todo -= sg_dma_len(sg);
11857675fe99SHans Verkuil 				sg = sg_next(sg);
1186b285192aSMauro Carvalho Chehab 			}
1187b285192aSMauro Carvalho Chehab 			*(rp++) = cpu_to_le32(RISC_WRITE|RISC_EOL|todo);
1188b285192aSMauro Carvalho Chehab 			*(rp++) = cpu_to_le32(sg_dma_address(sg));
1189b285192aSMauro Carvalho Chehab 			*(rp++) = cpu_to_le32(0); /* bits 63-32 */
1190b285192aSMauro Carvalho Chehab 			offset += todo;
1191b285192aSMauro Carvalho Chehab 		}
1192b285192aSMauro Carvalho Chehab 		offset += padding;
1193b285192aSMauro Carvalho Chehab 	}
1194b285192aSMauro Carvalho Chehab 
1195b285192aSMauro Carvalho Chehab 	return rp;
1196b285192aSMauro Carvalho Chehab }
1197b285192aSMauro Carvalho Chehab 
cx23885_risc_buffer(struct pci_dev * pci,struct cx23885_riscmem * risc,struct scatterlist * sglist,unsigned int top_offset,unsigned int bottom_offset,unsigned int bpl,unsigned int padding,unsigned int lines)11984d63a25cSHans Verkuil int cx23885_risc_buffer(struct pci_dev *pci, struct cx23885_riscmem *risc,
1199b285192aSMauro Carvalho Chehab 			struct scatterlist *sglist, unsigned int top_offset,
1200b285192aSMauro Carvalho Chehab 			unsigned int bottom_offset, unsigned int bpl,
1201b285192aSMauro Carvalho Chehab 			unsigned int padding, unsigned int lines)
1202b285192aSMauro Carvalho Chehab {
1203b285192aSMauro Carvalho Chehab 	u32 instructions, fields;
1204b285192aSMauro Carvalho Chehab 	__le32 *rp;
1205b285192aSMauro Carvalho Chehab 
1206b285192aSMauro Carvalho Chehab 	fields = 0;
1207b285192aSMauro Carvalho Chehab 	if (UNSET != top_offset)
1208b285192aSMauro Carvalho Chehab 		fields++;
1209b285192aSMauro Carvalho Chehab 	if (UNSET != bottom_offset)
1210b285192aSMauro Carvalho Chehab 		fields++;
1211b285192aSMauro Carvalho Chehab 
1212b285192aSMauro Carvalho Chehab 	/* estimate risc mem: worst case is one write per page border +
1213b285192aSMauro Carvalho Chehab 	   one write per scan line + syncs + jump (all 2 dwords).  Padding
1214b285192aSMauro Carvalho Chehab 	   can cause next bpl to start close to a page border.  First DMA
1215b285192aSMauro Carvalho Chehab 	   region may be smaller than PAGE_SIZE */
1216b285192aSMauro Carvalho Chehab 	/* write and jump need and extra dword */
1217b285192aSMauro Carvalho Chehab 	instructions  = fields * (1 + ((bpl + padding) * lines)
1218b285192aSMauro Carvalho Chehab 		/ PAGE_SIZE + lines);
1219453afdd9SHans Verkuil 	instructions += 5;
12204d63a25cSHans Verkuil 	risc->size = instructions * 12;
12217a77379fSChristophe JAILLET 	risc->cpu = dma_alloc_coherent(&pci->dev, risc->size, &risc->dma,
12227a77379fSChristophe JAILLET 				       GFP_KERNEL);
12234d63a25cSHans Verkuil 	if (risc->cpu == NULL)
12244d63a25cSHans Verkuil 		return -ENOMEM;
1225b285192aSMauro Carvalho Chehab 
1226b285192aSMauro Carvalho Chehab 	/* write risc instructions */
1227b285192aSMauro Carvalho Chehab 	rp = risc->cpu;
1228b285192aSMauro Carvalho Chehab 	if (UNSET != top_offset)
1229b285192aSMauro Carvalho Chehab 		rp = cx23885_risc_field(rp, sglist, top_offset, 0,
1230453afdd9SHans Verkuil 					bpl, padding, lines, 0, true);
1231b285192aSMauro Carvalho Chehab 	if (UNSET != bottom_offset)
1232b285192aSMauro Carvalho Chehab 		rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x200,
1233453afdd9SHans Verkuil 					bpl, padding, lines, 0, UNSET == top_offset);
1234b285192aSMauro Carvalho Chehab 
1235b285192aSMauro Carvalho Chehab 	/* save pointer to jmp instruction address */
1236b285192aSMauro Carvalho Chehab 	risc->jmp = rp;
1237b285192aSMauro Carvalho Chehab 	BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
1238b285192aSMauro Carvalho Chehab 	return 0;
1239b285192aSMauro Carvalho Chehab }
1240b285192aSMauro Carvalho Chehab 
cx23885_risc_databuffer(struct pci_dev * pci,struct cx23885_riscmem * risc,struct scatterlist * sglist,unsigned int bpl,unsigned int lines,unsigned int lpi)1241b285192aSMauro Carvalho Chehab int cx23885_risc_databuffer(struct pci_dev *pci,
12424d63a25cSHans Verkuil 				   struct cx23885_riscmem *risc,
1243b285192aSMauro Carvalho Chehab 				   struct scatterlist *sglist,
1244b285192aSMauro Carvalho Chehab 				   unsigned int bpl,
1245b285192aSMauro Carvalho Chehab 				   unsigned int lines, unsigned int lpi)
1246b285192aSMauro Carvalho Chehab {
1247b285192aSMauro Carvalho Chehab 	u32 instructions;
1248b285192aSMauro Carvalho Chehab 	__le32 *rp;
1249b285192aSMauro Carvalho Chehab 
1250b285192aSMauro Carvalho Chehab 	/* estimate risc mem: worst case is one write per page border +
1251b285192aSMauro Carvalho Chehab 	   one write per scan line + syncs + jump (all 2 dwords).  Here
1252b285192aSMauro Carvalho Chehab 	   there is no padding and no sync.  First DMA region may be smaller
1253b285192aSMauro Carvalho Chehab 	   than PAGE_SIZE */
1254b285192aSMauro Carvalho Chehab 	/* Jump and write need an extra dword */
1255b285192aSMauro Carvalho Chehab 	instructions  = 1 + (bpl * lines) / PAGE_SIZE + lines;
1256453afdd9SHans Verkuil 	instructions += 4;
1257b285192aSMauro Carvalho Chehab 
12584d63a25cSHans Verkuil 	risc->size = instructions * 12;
12597a77379fSChristophe JAILLET 	risc->cpu = dma_alloc_coherent(&pci->dev, risc->size, &risc->dma,
12607a77379fSChristophe JAILLET 				       GFP_KERNEL);
12614d63a25cSHans Verkuil 	if (risc->cpu == NULL)
12624d63a25cSHans Verkuil 		return -ENOMEM;
1263b285192aSMauro Carvalho Chehab 
1264b285192aSMauro Carvalho Chehab 	/* write risc instructions */
1265b285192aSMauro Carvalho Chehab 	rp = risc->cpu;
1266b285192aSMauro Carvalho Chehab 	rp = cx23885_risc_field(rp, sglist, 0, NO_SYNC_LINE,
1267453afdd9SHans Verkuil 				bpl, 0, lines, lpi, lpi == 0);
1268b285192aSMauro Carvalho Chehab 
1269b285192aSMauro Carvalho Chehab 	/* save pointer to jmp instruction address */
1270b285192aSMauro Carvalho Chehab 	risc->jmp = rp;
1271b285192aSMauro Carvalho Chehab 	BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
1272b285192aSMauro Carvalho Chehab 	return 0;
1273b285192aSMauro Carvalho Chehab }
1274b285192aSMauro Carvalho Chehab 
cx23885_risc_vbibuffer(struct pci_dev * pci,struct cx23885_riscmem * risc,struct scatterlist * sglist,unsigned int top_offset,unsigned int bottom_offset,unsigned int bpl,unsigned int padding,unsigned int lines)12754d63a25cSHans Verkuil int cx23885_risc_vbibuffer(struct pci_dev *pci, struct cx23885_riscmem *risc,
1276b285192aSMauro Carvalho Chehab 			struct scatterlist *sglist, unsigned int top_offset,
1277b285192aSMauro Carvalho Chehab 			unsigned int bottom_offset, unsigned int bpl,
1278b285192aSMauro Carvalho Chehab 			unsigned int padding, unsigned int lines)
1279b285192aSMauro Carvalho Chehab {
1280b285192aSMauro Carvalho Chehab 	u32 instructions, fields;
1281b285192aSMauro Carvalho Chehab 	__le32 *rp;
1282b285192aSMauro Carvalho Chehab 
1283b285192aSMauro Carvalho Chehab 	fields = 0;
1284b285192aSMauro Carvalho Chehab 	if (UNSET != top_offset)
1285b285192aSMauro Carvalho Chehab 		fields++;
1286b285192aSMauro Carvalho Chehab 	if (UNSET != bottom_offset)
1287b285192aSMauro Carvalho Chehab 		fields++;
1288b285192aSMauro Carvalho Chehab 
1289b285192aSMauro Carvalho Chehab 	/* estimate risc mem: worst case is one write per page border +
1290b285192aSMauro Carvalho Chehab 	   one write per scan line + syncs + jump (all 2 dwords).  Padding
1291b285192aSMauro Carvalho Chehab 	   can cause next bpl to start close to a page border.  First DMA
1292b285192aSMauro Carvalho Chehab 	   region may be smaller than PAGE_SIZE */
1293b285192aSMauro Carvalho Chehab 	/* write and jump need and extra dword */
1294b285192aSMauro Carvalho Chehab 	instructions  = fields * (1 + ((bpl + padding) * lines)
1295b285192aSMauro Carvalho Chehab 		/ PAGE_SIZE + lines);
1296453afdd9SHans Verkuil 	instructions += 5;
12974d63a25cSHans Verkuil 	risc->size = instructions * 12;
12987a77379fSChristophe JAILLET 	risc->cpu = dma_alloc_coherent(&pci->dev, risc->size, &risc->dma,
12997a77379fSChristophe JAILLET 				       GFP_KERNEL);
13004d63a25cSHans Verkuil 	if (risc->cpu == NULL)
13014d63a25cSHans Verkuil 		return -ENOMEM;
1302b285192aSMauro Carvalho Chehab 	/* write risc instructions */
1303b285192aSMauro Carvalho Chehab 	rp = risc->cpu;
1304b285192aSMauro Carvalho Chehab 
1305b285192aSMauro Carvalho Chehab 	/* Sync to line 6, so US CC line 21 will appear in line '12'
1306b285192aSMauro Carvalho Chehab 	 * in the userland vbi payload */
1307b285192aSMauro Carvalho Chehab 	if (UNSET != top_offset)
1308420b2176SHans Verkuil 		rp = cx23885_risc_field(rp, sglist, top_offset, 0,
1309453afdd9SHans Verkuil 					bpl, padding, lines, 0, true);
1310b285192aSMauro Carvalho Chehab 
1311b285192aSMauro Carvalho Chehab 	if (UNSET != bottom_offset)
1312420b2176SHans Verkuil 		rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x200,
1313453afdd9SHans Verkuil 					bpl, padding, lines, 0, UNSET == top_offset);
1314b285192aSMauro Carvalho Chehab 
1315b285192aSMauro Carvalho Chehab 
1316b285192aSMauro Carvalho Chehab 
1317b285192aSMauro Carvalho Chehab 	/* save pointer to jmp instruction address */
1318b285192aSMauro Carvalho Chehab 	risc->jmp = rp;
1319b285192aSMauro Carvalho Chehab 	BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
1320b285192aSMauro Carvalho Chehab 	return 0;
1321b285192aSMauro Carvalho Chehab }
1322b285192aSMauro Carvalho Chehab 
1323b285192aSMauro Carvalho Chehab 
cx23885_free_buffer(struct cx23885_dev * dev,struct cx23885_buffer * buf)1324453afdd9SHans Verkuil void cx23885_free_buffer(struct cx23885_dev *dev, struct cx23885_buffer *buf)
1325b285192aSMauro Carvalho Chehab {
13264d63a25cSHans Verkuil 	struct cx23885_riscmem *risc = &buf->risc;
13274d63a25cSHans Verkuil 
1328*47e8b73bSharperchen 	if (risc->cpu)
13297a77379fSChristophe JAILLET 		dma_free_coherent(&dev->pci->dev, risc->size, risc->cpu, risc->dma);
1330*47e8b73bSharperchen 	memset(risc, 0, sizeof(*risc));
1331b285192aSMauro Carvalho Chehab }
1332b285192aSMauro Carvalho Chehab 
cx23885_tsport_reg_dump(struct cx23885_tsport * port)1333b285192aSMauro Carvalho Chehab static void cx23885_tsport_reg_dump(struct cx23885_tsport *port)
1334b285192aSMauro Carvalho Chehab {
1335b285192aSMauro Carvalho Chehab 	struct cx23885_dev *dev = port->dev;
1336b285192aSMauro Carvalho Chehab 
1337b285192aSMauro Carvalho Chehab 	dprintk(1, "%s() Register Dump\n", __func__);
1338b285192aSMauro Carvalho Chehab 	dprintk(1, "%s() DEV_CNTRL2               0x%08X\n", __func__,
1339b285192aSMauro Carvalho Chehab 		cx_read(DEV_CNTRL2));
1340b285192aSMauro Carvalho Chehab 	dprintk(1, "%s() PCI_INT_MSK              0x%08X\n", __func__,
1341b285192aSMauro Carvalho Chehab 		cx23885_irq_get_mask(dev));
1342b285192aSMauro Carvalho Chehab 	dprintk(1, "%s() AUD_INT_INT_MSK          0x%08X\n", __func__,
1343b285192aSMauro Carvalho Chehab 		cx_read(AUDIO_INT_INT_MSK));
1344b285192aSMauro Carvalho Chehab 	dprintk(1, "%s() AUD_INT_DMA_CTL          0x%08X\n", __func__,
1345b285192aSMauro Carvalho Chehab 		cx_read(AUD_INT_DMA_CTL));
1346b285192aSMauro Carvalho Chehab 	dprintk(1, "%s() AUD_EXT_INT_MSK          0x%08X\n", __func__,
1347b285192aSMauro Carvalho Chehab 		cx_read(AUDIO_EXT_INT_MSK));
1348b285192aSMauro Carvalho Chehab 	dprintk(1, "%s() AUD_EXT_DMA_CTL          0x%08X\n", __func__,
1349b285192aSMauro Carvalho Chehab 		cx_read(AUD_EXT_DMA_CTL));
1350b285192aSMauro Carvalho Chehab 	dprintk(1, "%s() PAD_CTRL                 0x%08X\n", __func__,
1351b285192aSMauro Carvalho Chehab 		cx_read(PAD_CTRL));
1352b285192aSMauro Carvalho Chehab 	dprintk(1, "%s() ALT_PIN_OUT_SEL          0x%08X\n", __func__,
1353b285192aSMauro Carvalho Chehab 		cx_read(ALT_PIN_OUT_SEL));
1354b285192aSMauro Carvalho Chehab 	dprintk(1, "%s() GPIO2                    0x%08X\n", __func__,
1355b285192aSMauro Carvalho Chehab 		cx_read(GPIO2));
1356b285192aSMauro Carvalho Chehab 	dprintk(1, "%s() gpcnt(0x%08X)          0x%08X\n", __func__,
1357b285192aSMauro Carvalho Chehab 		port->reg_gpcnt, cx_read(port->reg_gpcnt));
1358b285192aSMauro Carvalho Chehab 	dprintk(1, "%s() gpcnt_ctl(0x%08X)      0x%08x\n", __func__,
1359b285192aSMauro Carvalho Chehab 		port->reg_gpcnt_ctl, cx_read(port->reg_gpcnt_ctl));
1360b285192aSMauro Carvalho Chehab 	dprintk(1, "%s() dma_ctl(0x%08X)        0x%08x\n", __func__,
1361b285192aSMauro Carvalho Chehab 		port->reg_dma_ctl, cx_read(port->reg_dma_ctl));
1362b285192aSMauro Carvalho Chehab 	if (port->reg_src_sel)
1363b285192aSMauro Carvalho Chehab 		dprintk(1, "%s() src_sel(0x%08X)        0x%08x\n", __func__,
1364b285192aSMauro Carvalho Chehab 			port->reg_src_sel, cx_read(port->reg_src_sel));
1365b285192aSMauro Carvalho Chehab 	dprintk(1, "%s() lngth(0x%08X)          0x%08x\n", __func__,
1366b285192aSMauro Carvalho Chehab 		port->reg_lngth, cx_read(port->reg_lngth));
1367b285192aSMauro Carvalho Chehab 	dprintk(1, "%s() hw_sop_ctrl(0x%08X)    0x%08x\n", __func__,
1368b285192aSMauro Carvalho Chehab 		port->reg_hw_sop_ctrl, cx_read(port->reg_hw_sop_ctrl));
1369b285192aSMauro Carvalho Chehab 	dprintk(1, "%s() gen_ctrl(0x%08X)       0x%08x\n", __func__,
1370b285192aSMauro Carvalho Chehab 		port->reg_gen_ctrl, cx_read(port->reg_gen_ctrl));
1371b285192aSMauro Carvalho Chehab 	dprintk(1, "%s() bd_pkt_status(0x%08X)  0x%08x\n", __func__,
1372b285192aSMauro Carvalho Chehab 		port->reg_bd_pkt_status, cx_read(port->reg_bd_pkt_status));
1373b285192aSMauro Carvalho Chehab 	dprintk(1, "%s() sop_status(0x%08X)     0x%08x\n", __func__,
1374b285192aSMauro Carvalho Chehab 		port->reg_sop_status, cx_read(port->reg_sop_status));
1375b285192aSMauro Carvalho Chehab 	dprintk(1, "%s() fifo_ovfl_stat(0x%08X) 0x%08x\n", __func__,
1376b285192aSMauro Carvalho Chehab 		port->reg_fifo_ovfl_stat, cx_read(port->reg_fifo_ovfl_stat));
1377b285192aSMauro Carvalho Chehab 	dprintk(1, "%s() vld_misc(0x%08X)       0x%08x\n", __func__,
1378b285192aSMauro Carvalho Chehab 		port->reg_vld_misc, cx_read(port->reg_vld_misc));
1379b285192aSMauro Carvalho Chehab 	dprintk(1, "%s() ts_clk_en(0x%08X)      0x%08x\n", __func__,
1380b285192aSMauro Carvalho Chehab 		port->reg_ts_clk_en, cx_read(port->reg_ts_clk_en));
1381b285192aSMauro Carvalho Chehab 	dprintk(1, "%s() ts_int_msk(0x%08X)     0x%08x\n", __func__,
1382b285192aSMauro Carvalho Chehab 		port->reg_ts_int_msk, cx_read(port->reg_ts_int_msk));
1383f72ff638SBrad Love 	dprintk(1, "%s() ts_int_status(0x%08X)  0x%08x\n", __func__,
1384f72ff638SBrad Love 		port->reg_ts_int_stat, cx_read(port->reg_ts_int_stat));
1385f72ff638SBrad Love 	dprintk(1, "%s() PCI_INT_STAT           0x%08X\n", __func__,
1386f72ff638SBrad Love 		cx_read(PCI_INT_STAT));
1387f72ff638SBrad Love 	dprintk(1, "%s() VID_B_INT_MSTAT        0x%08X\n", __func__,
1388f72ff638SBrad Love 		cx_read(VID_B_INT_MSTAT));
1389f72ff638SBrad Love 	dprintk(1, "%s() VID_B_INT_SSTAT        0x%08X\n", __func__,
1390f72ff638SBrad Love 		cx_read(VID_B_INT_SSTAT));
1391f72ff638SBrad Love 	dprintk(1, "%s() VID_C_INT_MSTAT        0x%08X\n", __func__,
1392f72ff638SBrad Love 		cx_read(VID_C_INT_MSTAT));
1393f72ff638SBrad Love 	dprintk(1, "%s() VID_C_INT_SSTAT        0x%08X\n", __func__,
1394f72ff638SBrad Love 		cx_read(VID_C_INT_SSTAT));
1395b285192aSMauro Carvalho Chehab }
1396b285192aSMauro Carvalho Chehab 
cx23885_start_dma(struct cx23885_tsport * port,struct cx23885_dmaqueue * q,struct cx23885_buffer * buf)1397453afdd9SHans Verkuil int cx23885_start_dma(struct cx23885_tsport *port,
1398b285192aSMauro Carvalho Chehab 			     struct cx23885_dmaqueue *q,
1399b285192aSMauro Carvalho Chehab 			     struct cx23885_buffer   *buf)
1400b285192aSMauro Carvalho Chehab {
1401b285192aSMauro Carvalho Chehab 	struct cx23885_dev *dev = port->dev;
1402b285192aSMauro Carvalho Chehab 	u32 reg;
1403b285192aSMauro Carvalho Chehab 
1404b285192aSMauro Carvalho Chehab 	dprintk(1, "%s() w: %d, h: %d, f: %d\n", __func__,
1405453afdd9SHans Verkuil 		dev->width, dev->height, dev->field);
1406b285192aSMauro Carvalho Chehab 
140795f408bbSBrad Love 	/* clear dma in progress */
140895f408bbSBrad Love 	cx23885_clear_bridge_error(dev);
140995f408bbSBrad Love 
1410b285192aSMauro Carvalho Chehab 	/* Stop the fifo and risc engine for this port */
1411b285192aSMauro Carvalho Chehab 	cx_clear(port->reg_dma_ctl, port->dma_ctl_val);
1412b285192aSMauro Carvalho Chehab 
1413b285192aSMauro Carvalho Chehab 	/* setup fifo + format */
1414b285192aSMauro Carvalho Chehab 	cx23885_sram_channel_setup(dev,
1415b285192aSMauro Carvalho Chehab 				   &dev->sram_channels[port->sram_chno],
1416b285192aSMauro Carvalho Chehab 				   port->ts_packet_size, buf->risc.dma);
1417b285192aSMauro Carvalho Chehab 	if (debug > 5) {
1418b285192aSMauro Carvalho Chehab 		cx23885_sram_channel_dump(dev,
1419b285192aSMauro Carvalho Chehab 			&dev->sram_channels[port->sram_chno]);
1420b285192aSMauro Carvalho Chehab 		cx23885_risc_disasm(port, &buf->risc);
1421b285192aSMauro Carvalho Chehab 	}
1422b285192aSMauro Carvalho Chehab 
1423b285192aSMauro Carvalho Chehab 	/* write TS length to chip */
1424453afdd9SHans Verkuil 	cx_write(port->reg_lngth, port->ts_packet_size);
1425b285192aSMauro Carvalho Chehab 
1426b285192aSMauro Carvalho Chehab 	if ((!(cx23885_boards[dev->board].portb & CX23885_MPEG_DVB)) &&
1427b285192aSMauro Carvalho Chehab 		(!(cx23885_boards[dev->board].portc & CX23885_MPEG_DVB))) {
1428e39682b5SMauro Carvalho Chehab 		pr_err("%s() Unsupported .portb/c (0x%08x)/(0x%08x)\n",
1429b285192aSMauro Carvalho Chehab 			__func__,
1430b285192aSMauro Carvalho Chehab 			cx23885_boards[dev->board].portb,
1431b285192aSMauro Carvalho Chehab 			cx23885_boards[dev->board].portc);
1432b285192aSMauro Carvalho Chehab 		return -EINVAL;
1433b285192aSMauro Carvalho Chehab 	}
1434b285192aSMauro Carvalho Chehab 
1435b285192aSMauro Carvalho Chehab 	if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER)
1436b285192aSMauro Carvalho Chehab 		cx23885_av_clk(dev, 0);
1437b285192aSMauro Carvalho Chehab 
1438b285192aSMauro Carvalho Chehab 	udelay(100);
1439b285192aSMauro Carvalho Chehab 
1440b285192aSMauro Carvalho Chehab 	/* If the port supports SRC SELECT, configure it */
1441b285192aSMauro Carvalho Chehab 	if (port->reg_src_sel)
1442b285192aSMauro Carvalho Chehab 		cx_write(port->reg_src_sel, port->src_sel_val);
1443b285192aSMauro Carvalho Chehab 
1444b285192aSMauro Carvalho Chehab 	cx_write(port->reg_hw_sop_ctrl, port->hw_sop_ctrl_val);
1445b285192aSMauro Carvalho Chehab 	cx_write(port->reg_ts_clk_en, port->ts_clk_en_val);
1446b285192aSMauro Carvalho Chehab 	cx_write(port->reg_vld_misc, port->vld_misc_val);
1447b285192aSMauro Carvalho Chehab 	cx_write(port->reg_gen_ctrl, port->gen_ctrl_val);
1448b285192aSMauro Carvalho Chehab 	udelay(100);
1449b285192aSMauro Carvalho Chehab 
1450b285192aSMauro Carvalho Chehab 	/* NOTE: this is 2 (reserved) for portb, does it matter? */
1451b285192aSMauro Carvalho Chehab 	/* reset counter to zero */
1452b285192aSMauro Carvalho Chehab 	cx_write(port->reg_gpcnt_ctl, 3);
1453453afdd9SHans Verkuil 	q->count = 0;
1454b285192aSMauro Carvalho Chehab 
1455b285192aSMauro Carvalho Chehab 	/* Set VIDB pins to input */
1456b285192aSMauro Carvalho Chehab 	if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) {
1457b285192aSMauro Carvalho Chehab 		reg = cx_read(PAD_CTRL);
1458b285192aSMauro Carvalho Chehab 		reg &= ~0x3; /* Clear TS1_OE & TS1_SOP_OE */
1459b285192aSMauro Carvalho Chehab 		cx_write(PAD_CTRL, reg);
1460b285192aSMauro Carvalho Chehab 	}
1461b285192aSMauro Carvalho Chehab 
1462b285192aSMauro Carvalho Chehab 	/* Set VIDC pins to input */
1463b285192aSMauro Carvalho Chehab 	if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) {
1464b285192aSMauro Carvalho Chehab 		reg = cx_read(PAD_CTRL);
1465b285192aSMauro Carvalho Chehab 		reg &= ~0x4; /* Clear TS2_SOP_OE */
1466b285192aSMauro Carvalho Chehab 		cx_write(PAD_CTRL, reg);
1467b285192aSMauro Carvalho Chehab 	}
1468b285192aSMauro Carvalho Chehab 
1469b285192aSMauro Carvalho Chehab 	if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) {
1470b285192aSMauro Carvalho Chehab 
1471b285192aSMauro Carvalho Chehab 		reg = cx_read(PAD_CTRL);
1472b285192aSMauro Carvalho Chehab 		reg = reg & ~0x1;    /* Clear TS1_OE */
1473b285192aSMauro Carvalho Chehab 
1474b285192aSMauro Carvalho Chehab 		/* FIXME, bit 2 writing here is questionable */
1475b285192aSMauro Carvalho Chehab 		/* set TS1_SOP_OE and TS1_OE_HI */
1476b285192aSMauro Carvalho Chehab 		reg = reg | 0xa;
1477b285192aSMauro Carvalho Chehab 		cx_write(PAD_CTRL, reg);
1478b285192aSMauro Carvalho Chehab 
1479ff9d1c01SBrad Love 		/* Sets MOE_CLK_DIS to disable MoE clock */
1480ff9d1c01SBrad Love 		/* sets MCLK_DLY_SEL/BCLK_DLY_SEL to 1 buffer delay each */
1481b285192aSMauro Carvalho Chehab 		cx_write(CLK_DELAY, cx_read(CLK_DELAY) | 0x80000011);
1482ff9d1c01SBrad Love 
1483ff9d1c01SBrad Love 		/* ALT_GPIO_ALT_SET: GPIO[0]
1484ff9d1c01SBrad Love 		 * IR_ALT_TX_SEL: GPIO[1]
1485ff9d1c01SBrad Love 		 * GPIO1_ALT_SEL: VIP_656_DATA[0]
1486ff9d1c01SBrad Love 		 * GPIO0_ALT_SEL: VIP_656_CLK
1487ff9d1c01SBrad Love 		 */
1488b285192aSMauro Carvalho Chehab 		cx_write(ALT_PIN_OUT_SEL, 0x10100045);
1489b285192aSMauro Carvalho Chehab 	}
1490b285192aSMauro Carvalho Chehab 
1491b285192aSMauro Carvalho Chehab 	switch (dev->bridge) {
1492b285192aSMauro Carvalho Chehab 	case CX23885_BRIDGE_885:
1493b285192aSMauro Carvalho Chehab 	case CX23885_BRIDGE_887:
1494b285192aSMauro Carvalho Chehab 	case CX23885_BRIDGE_888:
1495b285192aSMauro Carvalho Chehab 		/* enable irqs */
1496b285192aSMauro Carvalho Chehab 		dprintk(1, "%s() enabling TS int's and DMA\n", __func__);
149795f408bbSBrad Love 		/* clear dma in progress */
149895f408bbSBrad Love 		cx23885_clear_bridge_error(dev);
1499b285192aSMauro Carvalho Chehab 		cx_set(port->reg_ts_int_msk,  port->ts_int_msk_val);
1500b285192aSMauro Carvalho Chehab 		cx_set(port->reg_dma_ctl, port->dma_ctl_val);
150195f408bbSBrad Love 
150295f408bbSBrad Love 		/* clear dma in progress */
150395f408bbSBrad Love 		cx23885_clear_bridge_error(dev);
1504b285192aSMauro Carvalho Chehab 		cx23885_irq_add(dev, port->pci_irqmask);
1505b285192aSMauro Carvalho Chehab 		cx23885_irq_enable_all(dev);
150695f408bbSBrad Love 
150795f408bbSBrad Love 		/* clear dma in progress */
150895f408bbSBrad Love 		cx23885_clear_bridge_error(dev);
1509b285192aSMauro Carvalho Chehab 		break;
1510b285192aSMauro Carvalho Chehab 	default:
1511b285192aSMauro Carvalho Chehab 		BUG();
1512b285192aSMauro Carvalho Chehab 	}
1513b285192aSMauro Carvalho Chehab 
1514b285192aSMauro Carvalho Chehab 	cx_set(DEV_CNTRL2, (1<<5)); /* Enable RISC controller */
151595f408bbSBrad Love 	/* clear dma in progress */
151695f408bbSBrad Love 	cx23885_clear_bridge_error(dev);
1517b285192aSMauro Carvalho Chehab 
1518b285192aSMauro Carvalho Chehab 	if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER)
1519b285192aSMauro Carvalho Chehab 		cx23885_av_clk(dev, 1);
1520b285192aSMauro Carvalho Chehab 
1521b285192aSMauro Carvalho Chehab 	if (debug > 4)
1522b285192aSMauro Carvalho Chehab 		cx23885_tsport_reg_dump(port);
1523b285192aSMauro Carvalho Chehab 
152495f408bbSBrad Love 	cx23885_irq_get_mask(dev);
152595f408bbSBrad Love 
152695f408bbSBrad Love 	/* clear dma in progress */
152795f408bbSBrad Love 	cx23885_clear_bridge_error(dev);
152895f408bbSBrad Love 
1529b285192aSMauro Carvalho Chehab 	return 0;
1530b285192aSMauro Carvalho Chehab }
1531b285192aSMauro Carvalho Chehab 
cx23885_stop_dma(struct cx23885_tsport * port)1532b285192aSMauro Carvalho Chehab static int cx23885_stop_dma(struct cx23885_tsport *port)
1533b285192aSMauro Carvalho Chehab {
1534b285192aSMauro Carvalho Chehab 	struct cx23885_dev *dev = port->dev;
1535b285192aSMauro Carvalho Chehab 	u32 reg;
153695f408bbSBrad Love 	int delay = 0;
153795f408bbSBrad Love 	uint32_t reg1_val;
153895f408bbSBrad Love 	uint32_t reg2_val;
1539b285192aSMauro Carvalho Chehab 
1540b285192aSMauro Carvalho Chehab 	dprintk(1, "%s()\n", __func__);
1541b285192aSMauro Carvalho Chehab 
1542b285192aSMauro Carvalho Chehab 	/* Stop interrupts and DMA */
1543b285192aSMauro Carvalho Chehab 	cx_clear(port->reg_ts_int_msk, port->ts_int_msk_val);
1544b285192aSMauro Carvalho Chehab 	cx_clear(port->reg_dma_ctl, port->dma_ctl_val);
154595f408bbSBrad Love 	/* just in case wait for any dma to complete before allowing dealloc */
154695f408bbSBrad Love 	mdelay(20);
154795f408bbSBrad Love 	for (delay = 0; delay < 100; delay++) {
154895f408bbSBrad Love 		reg1_val = cx_read(TC_REQ);
154995f408bbSBrad Love 		reg2_val = cx_read(TC_REQ_SET);
155095f408bbSBrad Love 		if (reg1_val == 0 || reg2_val == 0)
155195f408bbSBrad Love 			break;
155295f408bbSBrad Love 		mdelay(1);
155395f408bbSBrad Love 	}
155495f408bbSBrad Love 	dev_dbg(&dev->pci->dev, "delay=%d reg1=0x%08x reg2=0x%08x\n",
155595f408bbSBrad Love 		delay, reg1_val, reg2_val);
1556b285192aSMauro Carvalho Chehab 
1557b285192aSMauro Carvalho Chehab 	if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) {
1558b285192aSMauro Carvalho Chehab 		reg = cx_read(PAD_CTRL);
1559b285192aSMauro Carvalho Chehab 
1560b285192aSMauro Carvalho Chehab 		/* Set TS1_OE */
1561b285192aSMauro Carvalho Chehab 		reg = reg | 0x1;
1562b285192aSMauro Carvalho Chehab 
1563b285192aSMauro Carvalho Chehab 		/* clear TS1_SOP_OE and TS1_OE_HI */
1564b285192aSMauro Carvalho Chehab 		reg = reg & ~0xa;
1565b285192aSMauro Carvalho Chehab 		cx_write(PAD_CTRL, reg);
1566b285192aSMauro Carvalho Chehab 		cx_write(port->reg_src_sel, 0);
1567b285192aSMauro Carvalho Chehab 		cx_write(port->reg_gen_ctrl, 8);
1568b285192aSMauro Carvalho Chehab 	}
1569b285192aSMauro Carvalho Chehab 
1570b285192aSMauro Carvalho Chehab 	if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER)
1571b285192aSMauro Carvalho Chehab 		cx23885_av_clk(dev, 0);
1572b285192aSMauro Carvalho Chehab 
1573b285192aSMauro Carvalho Chehab 	return 0;
1574b285192aSMauro Carvalho Chehab }
1575b285192aSMauro Carvalho Chehab 
1576b285192aSMauro Carvalho Chehab /* ------------------------------------------------------------------ */
1577b285192aSMauro Carvalho Chehab 
cx23885_buf_prepare(struct cx23885_buffer * buf,struct cx23885_tsport * port)1578453afdd9SHans Verkuil int cx23885_buf_prepare(struct cx23885_buffer *buf, struct cx23885_tsport *port)
1579b285192aSMauro Carvalho Chehab {
1580b285192aSMauro Carvalho Chehab 	struct cx23885_dev *dev = port->dev;
1581b285192aSMauro Carvalho Chehab 	int size = port->ts_packet_size * port->ts_packet_count;
15822d700715SJunghak Sung 	struct sg_table *sgt = vb2_dma_sg_plane_desc(&buf->vb.vb2_buf, 0);
1583b285192aSMauro Carvalho Chehab 
1584b285192aSMauro Carvalho Chehab 	dprintk(1, "%s: %p\n", __func__, buf);
15852d700715SJunghak Sung 	if (vb2_plane_size(&buf->vb.vb2_buf, 0) < size)
1586b285192aSMauro Carvalho Chehab 		return -EINVAL;
15872d700715SJunghak Sung 	vb2_set_plane_payload(&buf->vb.vb2_buf, 0, size);
1588b285192aSMauro Carvalho Chehab 
1589b285192aSMauro Carvalho Chehab 	cx23885_risc_databuffer(dev->pci, &buf->risc,
1590453afdd9SHans Verkuil 				sgt->sgl,
1591453afdd9SHans Verkuil 				port->ts_packet_size, port->ts_packet_count, 0);
1592b285192aSMauro Carvalho Chehab 	return 0;
1593b285192aSMauro Carvalho Chehab }
1594b285192aSMauro Carvalho Chehab 
1595453afdd9SHans Verkuil /*
1596453afdd9SHans Verkuil  * The risc program for each buffer works as follows: it starts with a simple
1597453afdd9SHans Verkuil  * 'JUMP to addr + 12', which is effectively a NOP. Then the code to DMA the
1598453afdd9SHans Verkuil  * buffer follows and at the end we have a JUMP back to the start + 12 (skipping
1599453afdd9SHans Verkuil  * the initial JUMP).
1600453afdd9SHans Verkuil  *
1601453afdd9SHans Verkuil  * This is the risc program of the first buffer to be queued if the active list
1602453afdd9SHans Verkuil  * is empty and it just keeps DMAing this buffer without generating any
1603453afdd9SHans Verkuil  * interrupts.
1604453afdd9SHans Verkuil  *
1605453afdd9SHans Verkuil  * If a new buffer is added then the initial JUMP in the code for that buffer
1606453afdd9SHans Verkuil  * will generate an interrupt which signals that the previous buffer has been
1607453afdd9SHans Verkuil  * DMAed successfully and that it can be returned to userspace.
1608453afdd9SHans Verkuil  *
1609453afdd9SHans Verkuil  * It also sets the final jump of the previous buffer to the start of the new
1610453afdd9SHans Verkuil  * buffer, thus chaining the new buffer into the DMA chain. This is a single
1611453afdd9SHans Verkuil  * atomic u32 write, so there is no race condition.
1612453afdd9SHans Verkuil  *
1613453afdd9SHans Verkuil  * The end-result of all this that you only get an interrupt when a buffer
1614453afdd9SHans Verkuil  * is ready, so the control flow is very easy.
1615453afdd9SHans Verkuil  */
cx23885_buf_queue(struct cx23885_tsport * port,struct cx23885_buffer * buf)1616b285192aSMauro Carvalho Chehab void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf)
1617b285192aSMauro Carvalho Chehab {
1618b285192aSMauro Carvalho Chehab 	struct cx23885_buffer    *prev;
1619b285192aSMauro Carvalho Chehab 	struct cx23885_dev *dev = port->dev;
1620b285192aSMauro Carvalho Chehab 	struct cx23885_dmaqueue  *cx88q = &port->mpegq;
1621453afdd9SHans Verkuil 	unsigned long flags;
1622b285192aSMauro Carvalho Chehab 
1623453afdd9SHans Verkuil 	buf->risc.cpu[1] = cpu_to_le32(buf->risc.dma + 12);
1624453afdd9SHans Verkuil 	buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_CNT_INC);
1625453afdd9SHans Verkuil 	buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma + 12);
1626b285192aSMauro Carvalho Chehab 	buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
1627b285192aSMauro Carvalho Chehab 
1628453afdd9SHans Verkuil 	spin_lock_irqsave(&dev->slock, flags);
1629b285192aSMauro Carvalho Chehab 	if (list_empty(&cx88q->active)) {
1630453afdd9SHans Verkuil 		list_add_tail(&buf->queue, &cx88q->active);
1631b285192aSMauro Carvalho Chehab 		dprintk(1, "[%p/%d] %s - first active\n",
16322d700715SJunghak Sung 			buf, buf->vb.vb2_buf.index, __func__);
1633b285192aSMauro Carvalho Chehab 	} else {
1634453afdd9SHans Verkuil 		buf->risc.cpu[0] |= cpu_to_le32(RISC_IRQ1);
1635b285192aSMauro Carvalho Chehab 		prev = list_entry(cx88q->active.prev, struct cx23885_buffer,
1636453afdd9SHans Verkuil 				  queue);
1637453afdd9SHans Verkuil 		list_add_tail(&buf->queue, &cx88q->active);
1638b285192aSMauro Carvalho Chehab 		prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
1639b285192aSMauro Carvalho Chehab 		dprintk(1, "[%p/%d] %s - append to active\n",
16402d700715SJunghak Sung 			 buf, buf->vb.vb2_buf.index, __func__);
1641b285192aSMauro Carvalho Chehab 	}
1642453afdd9SHans Verkuil 	spin_unlock_irqrestore(&dev->slock, flags);
1643b285192aSMauro Carvalho Chehab }
1644b285192aSMauro Carvalho Chehab 
1645b285192aSMauro Carvalho Chehab /* ----------------------------------------------------------- */
1646b285192aSMauro Carvalho Chehab 
do_cancel_buffers(struct cx23885_tsport * port,char * reason)1647453afdd9SHans Verkuil static void do_cancel_buffers(struct cx23885_tsport *port, char *reason)
1648b285192aSMauro Carvalho Chehab {
1649b285192aSMauro Carvalho Chehab 	struct cx23885_dmaqueue *q = &port->mpegq;
1650b285192aSMauro Carvalho Chehab 	struct cx23885_buffer *buf;
1651b285192aSMauro Carvalho Chehab 	unsigned long flags;
1652b285192aSMauro Carvalho Chehab 
1653b285192aSMauro Carvalho Chehab 	spin_lock_irqsave(&port->slock, flags);
1654b285192aSMauro Carvalho Chehab 	while (!list_empty(&q->active)) {
1655b285192aSMauro Carvalho Chehab 		buf = list_entry(q->active.next, struct cx23885_buffer,
1656453afdd9SHans Verkuil 				 queue);
1657453afdd9SHans Verkuil 		list_del(&buf->queue);
16582d700715SJunghak Sung 		vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
1659b285192aSMauro Carvalho Chehab 		dprintk(1, "[%p/%d] %s - dma=0x%08lx\n",
16602d700715SJunghak Sung 			buf, buf->vb.vb2_buf.index, reason,
16612d700715SJunghak Sung 			(unsigned long)buf->risc.dma);
1662b285192aSMauro Carvalho Chehab 	}
1663b285192aSMauro Carvalho Chehab 	spin_unlock_irqrestore(&port->slock, flags);
1664b285192aSMauro Carvalho Chehab }
1665b285192aSMauro Carvalho Chehab 
cx23885_cancel_buffers(struct cx23885_tsport * port)1666b285192aSMauro Carvalho Chehab void cx23885_cancel_buffers(struct cx23885_tsport *port)
1667b285192aSMauro Carvalho Chehab {
1668b285192aSMauro Carvalho Chehab 	dprintk(1, "%s()\n", __func__);
1669b285192aSMauro Carvalho Chehab 	cx23885_stop_dma(port);
1670453afdd9SHans Verkuil 	do_cancel_buffers(port, "cancel");
1671b285192aSMauro Carvalho Chehab }
1672b285192aSMauro Carvalho Chehab 
cx23885_irq_417(struct cx23885_dev * dev,u32 status)1673b285192aSMauro Carvalho Chehab int cx23885_irq_417(struct cx23885_dev *dev, u32 status)
1674b285192aSMauro Carvalho Chehab {
1675b285192aSMauro Carvalho Chehab 	/* FIXME: port1 assumption here. */
1676b285192aSMauro Carvalho Chehab 	struct cx23885_tsport *port = &dev->ts1;
1677b285192aSMauro Carvalho Chehab 	int count = 0;
1678b285192aSMauro Carvalho Chehab 	int handled = 0;
1679b285192aSMauro Carvalho Chehab 
1680b285192aSMauro Carvalho Chehab 	if (status == 0)
1681b285192aSMauro Carvalho Chehab 		return handled;
1682b285192aSMauro Carvalho Chehab 
1683b285192aSMauro Carvalho Chehab 	count = cx_read(port->reg_gpcnt);
1684b285192aSMauro Carvalho Chehab 	dprintk(7, "status: 0x%08x  mask: 0x%08x count: 0x%x\n",
1685b285192aSMauro Carvalho Chehab 		status, cx_read(port->reg_ts_int_msk), count);
1686b285192aSMauro Carvalho Chehab 
1687b285192aSMauro Carvalho Chehab 	if ((status & VID_B_MSK_BAD_PKT)         ||
1688b285192aSMauro Carvalho Chehab 		(status & VID_B_MSK_OPC_ERR)     ||
1689b285192aSMauro Carvalho Chehab 		(status & VID_B_MSK_VBI_OPC_ERR) ||
1690b285192aSMauro Carvalho Chehab 		(status & VID_B_MSK_SYNC)        ||
1691b285192aSMauro Carvalho Chehab 		(status & VID_B_MSK_VBI_SYNC)    ||
1692b285192aSMauro Carvalho Chehab 		(status & VID_B_MSK_OF)          ||
1693b285192aSMauro Carvalho Chehab 		(status & VID_B_MSK_VBI_OF)) {
1694e39682b5SMauro Carvalho Chehab 		pr_err("%s: V4L mpeg risc op code error, status = 0x%x\n",
169507ab29e1SMauro Carvalho Chehab 		       dev->name, status);
1696b285192aSMauro Carvalho Chehab 		if (status & VID_B_MSK_BAD_PKT)
1697b285192aSMauro Carvalho Chehab 			dprintk(1, "        VID_B_MSK_BAD_PKT\n");
1698b285192aSMauro Carvalho Chehab 		if (status & VID_B_MSK_OPC_ERR)
1699b285192aSMauro Carvalho Chehab 			dprintk(1, "        VID_B_MSK_OPC_ERR\n");
1700b285192aSMauro Carvalho Chehab 		if (status & VID_B_MSK_VBI_OPC_ERR)
1701b285192aSMauro Carvalho Chehab 			dprintk(1, "        VID_B_MSK_VBI_OPC_ERR\n");
1702b285192aSMauro Carvalho Chehab 		if (status & VID_B_MSK_SYNC)
1703b285192aSMauro Carvalho Chehab 			dprintk(1, "        VID_B_MSK_SYNC\n");
1704b285192aSMauro Carvalho Chehab 		if (status & VID_B_MSK_VBI_SYNC)
1705b285192aSMauro Carvalho Chehab 			dprintk(1, "        VID_B_MSK_VBI_SYNC\n");
1706b285192aSMauro Carvalho Chehab 		if (status & VID_B_MSK_OF)
1707b285192aSMauro Carvalho Chehab 			dprintk(1, "        VID_B_MSK_OF\n");
1708b285192aSMauro Carvalho Chehab 		if (status & VID_B_MSK_VBI_OF)
1709b285192aSMauro Carvalho Chehab 			dprintk(1, "        VID_B_MSK_VBI_OF\n");
1710b285192aSMauro Carvalho Chehab 
1711b285192aSMauro Carvalho Chehab 		cx_clear(port->reg_dma_ctl, port->dma_ctl_val);
1712b285192aSMauro Carvalho Chehab 		cx23885_sram_channel_dump(dev,
1713b285192aSMauro Carvalho Chehab 			&dev->sram_channels[port->sram_chno]);
1714b285192aSMauro Carvalho Chehab 		cx23885_417_check_encoder(dev);
1715b285192aSMauro Carvalho Chehab 	} else if (status & VID_B_MSK_RISCI1) {
1716b285192aSMauro Carvalho Chehab 		dprintk(7, "        VID_B_MSK_RISCI1\n");
1717b285192aSMauro Carvalho Chehab 		spin_lock(&port->slock);
1718b285192aSMauro Carvalho Chehab 		cx23885_wakeup(port, &port->mpegq, count);
1719b285192aSMauro Carvalho Chehab 		spin_unlock(&port->slock);
1720b285192aSMauro Carvalho Chehab 	}
1721b285192aSMauro Carvalho Chehab 	if (status) {
1722b285192aSMauro Carvalho Chehab 		cx_write(port->reg_ts_int_stat, status);
1723b285192aSMauro Carvalho Chehab 		handled = 1;
1724b285192aSMauro Carvalho Chehab 	}
1725b285192aSMauro Carvalho Chehab 
1726b285192aSMauro Carvalho Chehab 	return handled;
1727b285192aSMauro Carvalho Chehab }
1728b285192aSMauro Carvalho Chehab 
cx23885_irq_ts(struct cx23885_tsport * port,u32 status)1729b285192aSMauro Carvalho Chehab static int cx23885_irq_ts(struct cx23885_tsport *port, u32 status)
1730b285192aSMauro Carvalho Chehab {
1731b285192aSMauro Carvalho Chehab 	struct cx23885_dev *dev = port->dev;
1732b285192aSMauro Carvalho Chehab 	int handled = 0;
1733b285192aSMauro Carvalho Chehab 	u32 count;
1734b285192aSMauro Carvalho Chehab 
1735b285192aSMauro Carvalho Chehab 	if ((status & VID_BC_MSK_OPC_ERR) ||
1736b285192aSMauro Carvalho Chehab 		(status & VID_BC_MSK_BAD_PKT) ||
1737b285192aSMauro Carvalho Chehab 		(status & VID_BC_MSK_SYNC) ||
1738b285192aSMauro Carvalho Chehab 		(status & VID_BC_MSK_OF)) {
1739b285192aSMauro Carvalho Chehab 
1740b285192aSMauro Carvalho Chehab 		if (status & VID_BC_MSK_OPC_ERR)
1741b285192aSMauro Carvalho Chehab 			dprintk(7, " (VID_BC_MSK_OPC_ERR 0x%08x)\n",
1742b285192aSMauro Carvalho Chehab 				VID_BC_MSK_OPC_ERR);
1743b285192aSMauro Carvalho Chehab 
1744b285192aSMauro Carvalho Chehab 		if (status & VID_BC_MSK_BAD_PKT)
1745b285192aSMauro Carvalho Chehab 			dprintk(7, " (VID_BC_MSK_BAD_PKT 0x%08x)\n",
1746b285192aSMauro Carvalho Chehab 				VID_BC_MSK_BAD_PKT);
1747b285192aSMauro Carvalho Chehab 
1748b285192aSMauro Carvalho Chehab 		if (status & VID_BC_MSK_SYNC)
1749b285192aSMauro Carvalho Chehab 			dprintk(7, " (VID_BC_MSK_SYNC    0x%08x)\n",
1750b285192aSMauro Carvalho Chehab 				VID_BC_MSK_SYNC);
1751b285192aSMauro Carvalho Chehab 
1752b285192aSMauro Carvalho Chehab 		if (status & VID_BC_MSK_OF)
1753b285192aSMauro Carvalho Chehab 			dprintk(7, " (VID_BC_MSK_OF      0x%08x)\n",
1754b285192aSMauro Carvalho Chehab 				VID_BC_MSK_OF);
1755b285192aSMauro Carvalho Chehab 
1756e39682b5SMauro Carvalho Chehab 		pr_err("%s: mpeg risc op code error\n", dev->name);
1757b285192aSMauro Carvalho Chehab 
1758b285192aSMauro Carvalho Chehab 		cx_clear(port->reg_dma_ctl, port->dma_ctl_val);
1759b285192aSMauro Carvalho Chehab 		cx23885_sram_channel_dump(dev,
1760b285192aSMauro Carvalho Chehab 			&dev->sram_channels[port->sram_chno]);
1761b285192aSMauro Carvalho Chehab 
1762b285192aSMauro Carvalho Chehab 	} else if (status & VID_BC_MSK_RISCI1) {
1763b285192aSMauro Carvalho Chehab 
1764b285192aSMauro Carvalho Chehab 		dprintk(7, " (RISCI1            0x%08x)\n", VID_BC_MSK_RISCI1);
1765b285192aSMauro Carvalho Chehab 
1766b285192aSMauro Carvalho Chehab 		spin_lock(&port->slock);
1767b285192aSMauro Carvalho Chehab 		count = cx_read(port->reg_gpcnt);
1768b285192aSMauro Carvalho Chehab 		cx23885_wakeup(port, &port->mpegq, count);
1769b285192aSMauro Carvalho Chehab 		spin_unlock(&port->slock);
1770b285192aSMauro Carvalho Chehab 
1771b285192aSMauro Carvalho Chehab 	}
1772b285192aSMauro Carvalho Chehab 	if (status) {
1773b285192aSMauro Carvalho Chehab 		cx_write(port->reg_ts_int_stat, status);
1774b285192aSMauro Carvalho Chehab 		handled = 1;
1775b285192aSMauro Carvalho Chehab 	}
1776b285192aSMauro Carvalho Chehab 
1777b285192aSMauro Carvalho Chehab 	return handled;
1778b285192aSMauro Carvalho Chehab }
1779b285192aSMauro Carvalho Chehab 
cx23885_irq(int irq,void * dev_id)1780b285192aSMauro Carvalho Chehab static irqreturn_t cx23885_irq(int irq, void *dev_id)
1781b285192aSMauro Carvalho Chehab {
1782b285192aSMauro Carvalho Chehab 	struct cx23885_dev *dev = dev_id;
1783b285192aSMauro Carvalho Chehab 	struct cx23885_tsport *ts1 = &dev->ts1;
1784b285192aSMauro Carvalho Chehab 	struct cx23885_tsport *ts2 = &dev->ts2;
1785b285192aSMauro Carvalho Chehab 	u32 pci_status, pci_mask;
1786b285192aSMauro Carvalho Chehab 	u32 vida_status, vida_mask;
1787b285192aSMauro Carvalho Chehab 	u32 audint_status, audint_mask;
1788b285192aSMauro Carvalho Chehab 	u32 ts1_status, ts1_mask;
1789b285192aSMauro Carvalho Chehab 	u32 ts2_status, ts2_mask;
1790b285192aSMauro Carvalho Chehab 	int vida_count = 0, ts1_count = 0, ts2_count = 0, handled = 0;
1791b285192aSMauro Carvalho Chehab 	int audint_count = 0;
1792b285192aSMauro Carvalho Chehab 	bool subdev_handled;
1793b285192aSMauro Carvalho Chehab 
1794b285192aSMauro Carvalho Chehab 	pci_status = cx_read(PCI_INT_STAT);
1795b285192aSMauro Carvalho Chehab 	pci_mask = cx23885_irq_get_mask(dev);
17963b8315f3SBrad Love 	if ((pci_status & pci_mask) == 0) {
17973b8315f3SBrad Love 		dprintk(7, "pci_status: 0x%08x  pci_mask: 0x%08x\n",
17983b8315f3SBrad Love 			pci_status, pci_mask);
17993b8315f3SBrad Love 		goto out;
18003b8315f3SBrad Love 	}
18013b8315f3SBrad Love 
1802b285192aSMauro Carvalho Chehab 	vida_status = cx_read(VID_A_INT_STAT);
1803b285192aSMauro Carvalho Chehab 	vida_mask = cx_read(VID_A_INT_MSK);
1804b285192aSMauro Carvalho Chehab 	audint_status = cx_read(AUDIO_INT_INT_STAT);
1805b285192aSMauro Carvalho Chehab 	audint_mask = cx_read(AUDIO_INT_INT_MSK);
1806b285192aSMauro Carvalho Chehab 	ts1_status = cx_read(VID_B_INT_STAT);
1807b285192aSMauro Carvalho Chehab 	ts1_mask = cx_read(VID_B_INT_MSK);
1808b285192aSMauro Carvalho Chehab 	ts2_status = cx_read(VID_C_INT_STAT);
1809b285192aSMauro Carvalho Chehab 	ts2_mask = cx_read(VID_C_INT_MSK);
1810b285192aSMauro Carvalho Chehab 
18113b8315f3SBrad Love 	if (((pci_status & pci_mask) == 0) &&
18123b8315f3SBrad Love 		((ts2_status & ts2_mask) == 0) &&
18133b8315f3SBrad Love 		((ts1_status & ts1_mask) == 0))
1814b285192aSMauro Carvalho Chehab 		goto out;
1815b285192aSMauro Carvalho Chehab 
1816b285192aSMauro Carvalho Chehab 	vida_count = cx_read(VID_A_GPCNT);
1817b285192aSMauro Carvalho Chehab 	audint_count = cx_read(AUD_INT_A_GPCNT);
1818b285192aSMauro Carvalho Chehab 	ts1_count = cx_read(ts1->reg_gpcnt);
1819b285192aSMauro Carvalho Chehab 	ts2_count = cx_read(ts2->reg_gpcnt);
1820b285192aSMauro Carvalho Chehab 	dprintk(7, "pci_status: 0x%08x  pci_mask: 0x%08x\n",
1821b285192aSMauro Carvalho Chehab 		pci_status, pci_mask);
1822b285192aSMauro Carvalho Chehab 	dprintk(7, "vida_status: 0x%08x vida_mask: 0x%08x count: 0x%x\n",
1823b285192aSMauro Carvalho Chehab 		vida_status, vida_mask, vida_count);
1824b285192aSMauro Carvalho Chehab 	dprintk(7, "audint_status: 0x%08x audint_mask: 0x%08x count: 0x%x\n",
1825b285192aSMauro Carvalho Chehab 		audint_status, audint_mask, audint_count);
1826b285192aSMauro Carvalho Chehab 	dprintk(7, "ts1_status: 0x%08x  ts1_mask: 0x%08x count: 0x%x\n",
1827b285192aSMauro Carvalho Chehab 		ts1_status, ts1_mask, ts1_count);
1828b285192aSMauro Carvalho Chehab 	dprintk(7, "ts2_status: 0x%08x  ts2_mask: 0x%08x count: 0x%x\n",
1829b285192aSMauro Carvalho Chehab 		ts2_status, ts2_mask, ts2_count);
1830b285192aSMauro Carvalho Chehab 
1831b285192aSMauro Carvalho Chehab 	if (pci_status & (PCI_MSK_RISC_RD | PCI_MSK_RISC_WR |
1832b285192aSMauro Carvalho Chehab 			  PCI_MSK_AL_RD   | PCI_MSK_AL_WR   | PCI_MSK_APB_DMA |
1833b285192aSMauro Carvalho Chehab 			  PCI_MSK_VID_C   | PCI_MSK_VID_B   | PCI_MSK_VID_A   |
1834b285192aSMauro Carvalho Chehab 			  PCI_MSK_AUD_INT | PCI_MSK_AUD_EXT |
1835b285192aSMauro Carvalho Chehab 			  PCI_MSK_GPIO0   | PCI_MSK_GPIO1   |
1836b285192aSMauro Carvalho Chehab 			  PCI_MSK_AV_CORE | PCI_MSK_IR)) {
1837b285192aSMauro Carvalho Chehab 
1838b285192aSMauro Carvalho Chehab 		if (pci_status & PCI_MSK_RISC_RD)
1839b285192aSMauro Carvalho Chehab 			dprintk(7, " (PCI_MSK_RISC_RD   0x%08x)\n",
1840b285192aSMauro Carvalho Chehab 				PCI_MSK_RISC_RD);
1841b285192aSMauro Carvalho Chehab 
1842b285192aSMauro Carvalho Chehab 		if (pci_status & PCI_MSK_RISC_WR)
1843b285192aSMauro Carvalho Chehab 			dprintk(7, " (PCI_MSK_RISC_WR   0x%08x)\n",
1844b285192aSMauro Carvalho Chehab 				PCI_MSK_RISC_WR);
1845b285192aSMauro Carvalho Chehab 
1846b285192aSMauro Carvalho Chehab 		if (pci_status & PCI_MSK_AL_RD)
1847b285192aSMauro Carvalho Chehab 			dprintk(7, " (PCI_MSK_AL_RD     0x%08x)\n",
1848b285192aSMauro Carvalho Chehab 				PCI_MSK_AL_RD);
1849b285192aSMauro Carvalho Chehab 
1850b285192aSMauro Carvalho Chehab 		if (pci_status & PCI_MSK_AL_WR)
1851b285192aSMauro Carvalho Chehab 			dprintk(7, " (PCI_MSK_AL_WR     0x%08x)\n",
1852b285192aSMauro Carvalho Chehab 				PCI_MSK_AL_WR);
1853b285192aSMauro Carvalho Chehab 
1854b285192aSMauro Carvalho Chehab 		if (pci_status & PCI_MSK_APB_DMA)
1855b285192aSMauro Carvalho Chehab 			dprintk(7, " (PCI_MSK_APB_DMA   0x%08x)\n",
1856b285192aSMauro Carvalho Chehab 				PCI_MSK_APB_DMA);
1857b285192aSMauro Carvalho Chehab 
1858b285192aSMauro Carvalho Chehab 		if (pci_status & PCI_MSK_VID_C)
1859b285192aSMauro Carvalho Chehab 			dprintk(7, " (PCI_MSK_VID_C     0x%08x)\n",
1860b285192aSMauro Carvalho Chehab 				PCI_MSK_VID_C);
1861b285192aSMauro Carvalho Chehab 
1862b285192aSMauro Carvalho Chehab 		if (pci_status & PCI_MSK_VID_B)
1863b285192aSMauro Carvalho Chehab 			dprintk(7, " (PCI_MSK_VID_B     0x%08x)\n",
1864b285192aSMauro Carvalho Chehab 				PCI_MSK_VID_B);
1865b285192aSMauro Carvalho Chehab 
1866b285192aSMauro Carvalho Chehab 		if (pci_status & PCI_MSK_VID_A)
1867b285192aSMauro Carvalho Chehab 			dprintk(7, " (PCI_MSK_VID_A     0x%08x)\n",
1868b285192aSMauro Carvalho Chehab 				PCI_MSK_VID_A);
1869b285192aSMauro Carvalho Chehab 
1870b285192aSMauro Carvalho Chehab 		if (pci_status & PCI_MSK_AUD_INT)
1871b285192aSMauro Carvalho Chehab 			dprintk(7, " (PCI_MSK_AUD_INT   0x%08x)\n",
1872b285192aSMauro Carvalho Chehab 				PCI_MSK_AUD_INT);
1873b285192aSMauro Carvalho Chehab 
1874b285192aSMauro Carvalho Chehab 		if (pci_status & PCI_MSK_AUD_EXT)
1875b285192aSMauro Carvalho Chehab 			dprintk(7, " (PCI_MSK_AUD_EXT   0x%08x)\n",
1876b285192aSMauro Carvalho Chehab 				PCI_MSK_AUD_EXT);
1877b285192aSMauro Carvalho Chehab 
1878b285192aSMauro Carvalho Chehab 		if (pci_status & PCI_MSK_GPIO0)
1879b285192aSMauro Carvalho Chehab 			dprintk(7, " (PCI_MSK_GPIO0     0x%08x)\n",
1880b285192aSMauro Carvalho Chehab 				PCI_MSK_GPIO0);
1881b285192aSMauro Carvalho Chehab 
1882b285192aSMauro Carvalho Chehab 		if (pci_status & PCI_MSK_GPIO1)
1883b285192aSMauro Carvalho Chehab 			dprintk(7, " (PCI_MSK_GPIO1     0x%08x)\n",
1884b285192aSMauro Carvalho Chehab 				PCI_MSK_GPIO1);
1885b285192aSMauro Carvalho Chehab 
1886b285192aSMauro Carvalho Chehab 		if (pci_status & PCI_MSK_AV_CORE)
1887b285192aSMauro Carvalho Chehab 			dprintk(7, " (PCI_MSK_AV_CORE   0x%08x)\n",
1888b285192aSMauro Carvalho Chehab 				PCI_MSK_AV_CORE);
1889b285192aSMauro Carvalho Chehab 
1890b285192aSMauro Carvalho Chehab 		if (pci_status & PCI_MSK_IR)
1891b285192aSMauro Carvalho Chehab 			dprintk(7, " (PCI_MSK_IR        0x%08x)\n",
1892b285192aSMauro Carvalho Chehab 				PCI_MSK_IR);
1893b285192aSMauro Carvalho Chehab 	}
1894b285192aSMauro Carvalho Chehab 
1895b285192aSMauro Carvalho Chehab 	if (cx23885_boards[dev->board].ci_type == 1 &&
1896b285192aSMauro Carvalho Chehab 			(pci_status & (PCI_MSK_GPIO1 | PCI_MSK_GPIO0)))
1897b285192aSMauro Carvalho Chehab 		handled += netup_ci_slot_status(dev, pci_status);
1898b285192aSMauro Carvalho Chehab 
1899b285192aSMauro Carvalho Chehab 	if (cx23885_boards[dev->board].ci_type == 2 &&
1900b285192aSMauro Carvalho Chehab 			(pci_status & PCI_MSK_GPIO0))
1901b285192aSMauro Carvalho Chehab 		handled += altera_ci_irq(dev);
1902b285192aSMauro Carvalho Chehab 
1903b285192aSMauro Carvalho Chehab 	if (ts1_status) {
1904b285192aSMauro Carvalho Chehab 		if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB)
1905b285192aSMauro Carvalho Chehab 			handled += cx23885_irq_ts(ts1, ts1_status);
1906b285192aSMauro Carvalho Chehab 		else
1907b285192aSMauro Carvalho Chehab 		if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER)
1908b285192aSMauro Carvalho Chehab 			handled += cx23885_irq_417(dev, ts1_status);
1909b285192aSMauro Carvalho Chehab 	}
1910b285192aSMauro Carvalho Chehab 
1911b285192aSMauro Carvalho Chehab 	if (ts2_status) {
1912b285192aSMauro Carvalho Chehab 		if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB)
1913b285192aSMauro Carvalho Chehab 			handled += cx23885_irq_ts(ts2, ts2_status);
1914b285192aSMauro Carvalho Chehab 		else
1915b285192aSMauro Carvalho Chehab 		if (cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER)
1916b285192aSMauro Carvalho Chehab 			handled += cx23885_irq_417(dev, ts2_status);
1917b285192aSMauro Carvalho Chehab 	}
1918b285192aSMauro Carvalho Chehab 
1919b285192aSMauro Carvalho Chehab 	if (vida_status)
1920b285192aSMauro Carvalho Chehab 		handled += cx23885_video_irq(dev, vida_status);
1921b285192aSMauro Carvalho Chehab 
1922b285192aSMauro Carvalho Chehab 	if (audint_status)
1923b285192aSMauro Carvalho Chehab 		handled += cx23885_audio_irq(dev, audint_status, audint_mask);
1924b285192aSMauro Carvalho Chehab 
1925b285192aSMauro Carvalho Chehab 	if (pci_status & PCI_MSK_IR) {
1926b285192aSMauro Carvalho Chehab 		subdev_handled = false;
1927b285192aSMauro Carvalho Chehab 		v4l2_subdev_call(dev->sd_ir, core, interrupt_service_routine,
1928b285192aSMauro Carvalho Chehab 				 pci_status, &subdev_handled);
1929b285192aSMauro Carvalho Chehab 		if (subdev_handled)
1930b285192aSMauro Carvalho Chehab 			handled++;
1931b285192aSMauro Carvalho Chehab 	}
1932b285192aSMauro Carvalho Chehab 
1933b285192aSMauro Carvalho Chehab 	if ((pci_status & pci_mask) & PCI_MSK_AV_CORE) {
1934b285192aSMauro Carvalho Chehab 		cx23885_irq_disable(dev, PCI_MSK_AV_CORE);
1935c21412f5SLuis Alves 		schedule_work(&dev->cx25840_work);
1936b285192aSMauro Carvalho Chehab 		handled++;
1937b285192aSMauro Carvalho Chehab 	}
1938b285192aSMauro Carvalho Chehab 
1939b285192aSMauro Carvalho Chehab 	if (handled)
19403b8315f3SBrad Love 		cx_write(PCI_INT_STAT, pci_status & pci_mask);
1941b285192aSMauro Carvalho Chehab out:
1942b285192aSMauro Carvalho Chehab 	return IRQ_RETVAL(handled);
1943b285192aSMauro Carvalho Chehab }
1944b285192aSMauro Carvalho Chehab 
cx23885_v4l2_dev_notify(struct v4l2_subdev * sd,unsigned int notification,void * arg)1945b285192aSMauro Carvalho Chehab static void cx23885_v4l2_dev_notify(struct v4l2_subdev *sd,
1946b285192aSMauro Carvalho Chehab 				    unsigned int notification, void *arg)
1947b285192aSMauro Carvalho Chehab {
1948b285192aSMauro Carvalho Chehab 	struct cx23885_dev *dev;
1949b285192aSMauro Carvalho Chehab 
1950b285192aSMauro Carvalho Chehab 	if (sd == NULL)
1951b285192aSMauro Carvalho Chehab 		return;
1952b285192aSMauro Carvalho Chehab 
1953b285192aSMauro Carvalho Chehab 	dev = to_cx23885(sd->v4l2_dev);
1954b285192aSMauro Carvalho Chehab 
1955b285192aSMauro Carvalho Chehab 	switch (notification) {
1956b285192aSMauro Carvalho Chehab 	case V4L2_SUBDEV_IR_RX_NOTIFY: /* Possibly called in an IRQ context */
1957b285192aSMauro Carvalho Chehab 		if (sd == dev->sd_ir)
1958b285192aSMauro Carvalho Chehab 			cx23885_ir_rx_v4l2_dev_notify(sd, *(u32 *)arg);
1959b285192aSMauro Carvalho Chehab 		break;
1960b285192aSMauro Carvalho Chehab 	case V4L2_SUBDEV_IR_TX_NOTIFY: /* Possibly called in an IRQ context */
1961b285192aSMauro Carvalho Chehab 		if (sd == dev->sd_ir)
1962b285192aSMauro Carvalho Chehab 			cx23885_ir_tx_v4l2_dev_notify(sd, *(u32 *)arg);
1963b285192aSMauro Carvalho Chehab 		break;
1964b285192aSMauro Carvalho Chehab 	}
1965b285192aSMauro Carvalho Chehab }
1966b285192aSMauro Carvalho Chehab 
cx23885_v4l2_dev_notify_init(struct cx23885_dev * dev)1967b285192aSMauro Carvalho Chehab static void cx23885_v4l2_dev_notify_init(struct cx23885_dev *dev)
1968b285192aSMauro Carvalho Chehab {
1969b285192aSMauro Carvalho Chehab 	INIT_WORK(&dev->cx25840_work, cx23885_av_work_handler);
1970b285192aSMauro Carvalho Chehab 	INIT_WORK(&dev->ir_rx_work, cx23885_ir_rx_work_handler);
1971b285192aSMauro Carvalho Chehab 	INIT_WORK(&dev->ir_tx_work, cx23885_ir_tx_work_handler);
1972b285192aSMauro Carvalho Chehab 	dev->v4l2_dev.notify = cx23885_v4l2_dev_notify;
1973b285192aSMauro Carvalho Chehab }
1974b285192aSMauro Carvalho Chehab 
encoder_on_portb(struct cx23885_dev * dev)1975b285192aSMauro Carvalho Chehab static inline int encoder_on_portb(struct cx23885_dev *dev)
1976b285192aSMauro Carvalho Chehab {
1977b285192aSMauro Carvalho Chehab 	return cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER;
1978b285192aSMauro Carvalho Chehab }
1979b285192aSMauro Carvalho Chehab 
encoder_on_portc(struct cx23885_dev * dev)1980b285192aSMauro Carvalho Chehab static inline int encoder_on_portc(struct cx23885_dev *dev)
1981b285192aSMauro Carvalho Chehab {
1982b285192aSMauro Carvalho Chehab 	return cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER;
1983b285192aSMauro Carvalho Chehab }
1984b285192aSMauro Carvalho Chehab 
1985b285192aSMauro Carvalho Chehab /* Mask represents 32 different GPIOs, GPIO's are split into multiple
1986b285192aSMauro Carvalho Chehab  * registers depending on the board configuration (and whether the
1987b285192aSMauro Carvalho Chehab  * 417 encoder (wi it's own GPIO's) are present. Each GPIO bit will
1988b285192aSMauro Carvalho Chehab  * be pushed into the correct hardware register, regardless of the
1989b285192aSMauro Carvalho Chehab  * physical location. Certain registers are shared so we sanity check
1990b285192aSMauro Carvalho Chehab  * and report errors if we think we're tampering with a GPIo that might
1991b285192aSMauro Carvalho Chehab  * be assigned to the encoder (and used for the host bus).
1992b285192aSMauro Carvalho Chehab  *
199316790554SMauro Carvalho Chehab  * GPIO  2 through  0 - On the cx23885 bridge
199416790554SMauro Carvalho Chehab  * GPIO 18 through  3 - On the cx23417 host bus interface
199516790554SMauro Carvalho Chehab  * GPIO 23 through 19 - On the cx25840 a/v core
1996b285192aSMauro Carvalho Chehab  */
cx23885_gpio_set(struct cx23885_dev * dev,u32 mask)1997b285192aSMauro Carvalho Chehab void cx23885_gpio_set(struct cx23885_dev *dev, u32 mask)
1998b285192aSMauro Carvalho Chehab {
1999b285192aSMauro Carvalho Chehab 	if (mask & 0x7)
2000b285192aSMauro Carvalho Chehab 		cx_set(GP0_IO, mask & 0x7);
2001b285192aSMauro Carvalho Chehab 
2002b285192aSMauro Carvalho Chehab 	if (mask & 0x0007fff8) {
2003b285192aSMauro Carvalho Chehab 		if (encoder_on_portb(dev) || encoder_on_portc(dev))
2004e39682b5SMauro Carvalho Chehab 			pr_err("%s: Setting GPIO on encoder ports\n",
2005b285192aSMauro Carvalho Chehab 				dev->name);
2006b285192aSMauro Carvalho Chehab 		cx_set(MC417_RWD, (mask & 0x0007fff8) >> 3);
2007b285192aSMauro Carvalho Chehab 	}
2008b285192aSMauro Carvalho Chehab 
2009b285192aSMauro Carvalho Chehab 	/* TODO: 23-19 */
2010b285192aSMauro Carvalho Chehab 	if (mask & 0x00f80000)
2011e39682b5SMauro Carvalho Chehab 		pr_info("%s: Unsupported\n", dev->name);
2012b285192aSMauro Carvalho Chehab }
2013b285192aSMauro Carvalho Chehab 
cx23885_gpio_clear(struct cx23885_dev * dev,u32 mask)2014b285192aSMauro Carvalho Chehab void cx23885_gpio_clear(struct cx23885_dev *dev, u32 mask)
2015b285192aSMauro Carvalho Chehab {
2016b285192aSMauro Carvalho Chehab 	if (mask & 0x00000007)
2017b285192aSMauro Carvalho Chehab 		cx_clear(GP0_IO, mask & 0x7);
2018b285192aSMauro Carvalho Chehab 
2019b285192aSMauro Carvalho Chehab 	if (mask & 0x0007fff8) {
2020b285192aSMauro Carvalho Chehab 		if (encoder_on_portb(dev) || encoder_on_portc(dev))
2021e39682b5SMauro Carvalho Chehab 			pr_err("%s: Clearing GPIO moving on encoder ports\n",
2022b285192aSMauro Carvalho Chehab 				dev->name);
2023b285192aSMauro Carvalho Chehab 		cx_clear(MC417_RWD, (mask & 0x7fff8) >> 3);
2024b285192aSMauro Carvalho Chehab 	}
2025b285192aSMauro Carvalho Chehab 
2026b285192aSMauro Carvalho Chehab 	/* TODO: 23-19 */
2027b285192aSMauro Carvalho Chehab 	if (mask & 0x00f80000)
2028e39682b5SMauro Carvalho Chehab 		pr_info("%s: Unsupported\n", dev->name);
2029b285192aSMauro Carvalho Chehab }
2030b285192aSMauro Carvalho Chehab 
cx23885_gpio_get(struct cx23885_dev * dev,u32 mask)2031b285192aSMauro Carvalho Chehab u32 cx23885_gpio_get(struct cx23885_dev *dev, u32 mask)
2032b285192aSMauro Carvalho Chehab {
2033b285192aSMauro Carvalho Chehab 	if (mask & 0x00000007)
2034b285192aSMauro Carvalho Chehab 		return (cx_read(GP0_IO) >> 8) & mask & 0x7;
2035b285192aSMauro Carvalho Chehab 
2036b285192aSMauro Carvalho Chehab 	if (mask & 0x0007fff8) {
2037b285192aSMauro Carvalho Chehab 		if (encoder_on_portb(dev) || encoder_on_portc(dev))
2038e39682b5SMauro Carvalho Chehab 			pr_err("%s: Reading GPIO moving on encoder ports\n",
2039b285192aSMauro Carvalho Chehab 				dev->name);
2040b285192aSMauro Carvalho Chehab 		return (cx_read(MC417_RWD) & ((mask & 0x7fff8) >> 3)) << 3;
2041b285192aSMauro Carvalho Chehab 	}
2042b285192aSMauro Carvalho Chehab 
2043b285192aSMauro Carvalho Chehab 	/* TODO: 23-19 */
2044b285192aSMauro Carvalho Chehab 	if (mask & 0x00f80000)
2045e39682b5SMauro Carvalho Chehab 		pr_info("%s: Unsupported\n", dev->name);
2046b285192aSMauro Carvalho Chehab 
2047b285192aSMauro Carvalho Chehab 	return 0;
2048b285192aSMauro Carvalho Chehab }
2049b285192aSMauro Carvalho Chehab 
cx23885_gpio_enable(struct cx23885_dev * dev,u32 mask,int asoutput)2050b285192aSMauro Carvalho Chehab void cx23885_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput)
2051b285192aSMauro Carvalho Chehab {
2052b285192aSMauro Carvalho Chehab 	if ((mask & 0x00000007) && asoutput)
2053b285192aSMauro Carvalho Chehab 		cx_set(GP0_IO, (mask & 0x7) << 16);
2054b285192aSMauro Carvalho Chehab 	else if ((mask & 0x00000007) && !asoutput)
2055b285192aSMauro Carvalho Chehab 		cx_clear(GP0_IO, (mask & 0x7) << 16);
2056b285192aSMauro Carvalho Chehab 
2057b285192aSMauro Carvalho Chehab 	if (mask & 0x0007fff8) {
2058b285192aSMauro Carvalho Chehab 		if (encoder_on_portb(dev) || encoder_on_portc(dev))
2059e39682b5SMauro Carvalho Chehab 			pr_err("%s: Enabling GPIO on encoder ports\n",
2060b285192aSMauro Carvalho Chehab 				dev->name);
2061b285192aSMauro Carvalho Chehab 	}
2062b285192aSMauro Carvalho Chehab 
2063b285192aSMauro Carvalho Chehab 	/* MC417_OEN is active low for output, write 1 for an input */
2064b285192aSMauro Carvalho Chehab 	if ((mask & 0x0007fff8) && asoutput)
2065b285192aSMauro Carvalho Chehab 		cx_clear(MC417_OEN, (mask & 0x7fff8) >> 3);
2066b285192aSMauro Carvalho Chehab 
2067b285192aSMauro Carvalho Chehab 	else if ((mask & 0x0007fff8) && !asoutput)
2068b285192aSMauro Carvalho Chehab 		cx_set(MC417_OEN, (mask & 0x7fff8) >> 3);
2069b285192aSMauro Carvalho Chehab 
2070b285192aSMauro Carvalho Chehab 	/* TODO: 23-19 */
2071b285192aSMauro Carvalho Chehab }
2072b285192aSMauro Carvalho Chehab 
20734bd46aa0SBrad Love static struct {
20744bd46aa0SBrad Love 	int vendor, dev;
20754bd46aa0SBrad Love } const broken_dev_id[] = {
20764bd46aa0SBrad Love 	/* According with
20774bd46aa0SBrad Love 	 * https://openbenchmarking.org/system/1703021-RI-AMDZEN08075/Ryzen%207%201800X/lspci,
20784bd46aa0SBrad Love 	 * 0x1451 is PCI ID for the IOMMU found on Ryzen
20794bd46aa0SBrad Love 	 */
20804bd46aa0SBrad Love 	{ PCI_VENDOR_ID_AMD, 0x1451 },
2081dbf0b3a7SDaniel Lee Kruse 	/* According to sudo lspci -nn,
2082dbf0b3a7SDaniel Lee Kruse 	 * 0x1423 is the PCI ID for the IOMMU found on Kaveri
2083dbf0b3a7SDaniel Lee Kruse 	 */
2084dbf0b3a7SDaniel Lee Kruse 	{ PCI_VENDOR_ID_AMD, 0x1423 },
20855f864cfbSBrad Love 	/* 0x1481 is the PCI ID for the IOMMU found on Starship/Matisse
20865f864cfbSBrad Love 	 */
20875f864cfbSBrad Love 	{ PCI_VENDOR_ID_AMD, 0x1481 },
20885f864cfbSBrad Love 	/* 0x1419 is the PCI ID for the IOMMU found on 15h (Models 10h-1fh) family
20895f864cfbSBrad Love 	 */
20905f864cfbSBrad Love 	{ PCI_VENDOR_ID_AMD, 0x1419 },
2091a7985e3cSDaniel Lee Kruse 	/* 0x1631 is the PCI ID for the IOMMU found on Renoir/Cezanne
2092a7985e3cSDaniel Lee Kruse 	 */
2093a7985e3cSDaniel Lee Kruse 	{ PCI_VENDOR_ID_AMD, 0x1631 },
20945f864cfbSBrad Love 	/* 0x5a23 is the PCI ID for the IOMMU found on RD890S/RD990
20955f864cfbSBrad Love 	 */
20965f864cfbSBrad Love 	{ PCI_VENDOR_ID_ATI, 0x5a23 },
20974bd46aa0SBrad Love };
20984bd46aa0SBrad Love 
cx23885_does_need_dma_reset(void)20994bd46aa0SBrad Love static bool cx23885_does_need_dma_reset(void)
21004bd46aa0SBrad Love {
21014bd46aa0SBrad Love 	int i;
21024bd46aa0SBrad Love 	struct pci_dev *pdev = NULL;
21034bd46aa0SBrad Love 
21044bd46aa0SBrad Love 	if (dma_reset_workaround == 0)
21054bd46aa0SBrad Love 		return false;
21064bd46aa0SBrad Love 	else if (dma_reset_workaround == 2)
21074bd46aa0SBrad Love 		return true;
21084bd46aa0SBrad Love 
21094bd46aa0SBrad Love 	for (i = 0; i < ARRAY_SIZE(broken_dev_id); i++) {
21104bd46aa0SBrad Love 		pdev = pci_get_device(broken_dev_id[i].vendor,
21114bd46aa0SBrad Love 				      broken_dev_id[i].dev, NULL);
21124bd46aa0SBrad Love 		if (pdev) {
21134bd46aa0SBrad Love 			pci_dev_put(pdev);
21144bd46aa0SBrad Love 			return true;
21154bd46aa0SBrad Love 		}
21164bd46aa0SBrad Love 	}
21174bd46aa0SBrad Love 	return false;
21184bd46aa0SBrad Love }
21194bd46aa0SBrad Love 
cx23885_initdev(struct pci_dev * pci_dev,const struct pci_device_id * pci_id)21204c62e976SGreg Kroah-Hartman static int cx23885_initdev(struct pci_dev *pci_dev,
2121b285192aSMauro Carvalho Chehab 			   const struct pci_device_id *pci_id)
2122b285192aSMauro Carvalho Chehab {
2123b285192aSMauro Carvalho Chehab 	struct cx23885_dev *dev;
2124da59a4deSHans Verkuil 	struct v4l2_ctrl_handler *hdl;
2125b285192aSMauro Carvalho Chehab 	int err;
2126b285192aSMauro Carvalho Chehab 
2127b285192aSMauro Carvalho Chehab 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
2128b285192aSMauro Carvalho Chehab 	if (NULL == dev)
2129b285192aSMauro Carvalho Chehab 		return -ENOMEM;
2130b285192aSMauro Carvalho Chehab 
21314bd46aa0SBrad Love 	dev->need_dma_reset = cx23885_does_need_dma_reset();
21324bd46aa0SBrad Love 
2133b285192aSMauro Carvalho Chehab 	err = v4l2_device_register(&pci_dev->dev, &dev->v4l2_dev);
2134b285192aSMauro Carvalho Chehab 	if (err < 0)
2135b285192aSMauro Carvalho Chehab 		goto fail_free;
2136b285192aSMauro Carvalho Chehab 
2137da59a4deSHans Verkuil 	hdl = &dev->ctrl_handler;
2138da59a4deSHans Verkuil 	v4l2_ctrl_handler_init(hdl, 6);
2139da59a4deSHans Verkuil 	if (hdl->error) {
2140da59a4deSHans Verkuil 		err = hdl->error;
2141da59a4deSHans Verkuil 		goto fail_ctrl;
2142da59a4deSHans Verkuil 	}
2143da59a4deSHans Verkuil 	dev->v4l2_dev.ctrl_handler = hdl;
2144da59a4deSHans Verkuil 
2145b285192aSMauro Carvalho Chehab 	/* Prepare to handle notifications from subdevices */
2146b285192aSMauro Carvalho Chehab 	cx23885_v4l2_dev_notify_init(dev);
2147b285192aSMauro Carvalho Chehab 
2148b285192aSMauro Carvalho Chehab 	/* pci init */
2149b285192aSMauro Carvalho Chehab 	dev->pci = pci_dev;
2150b285192aSMauro Carvalho Chehab 	if (pci_enable_device(pci_dev)) {
2151b285192aSMauro Carvalho Chehab 		err = -EIO;
2152da59a4deSHans Verkuil 		goto fail_ctrl;
2153b285192aSMauro Carvalho Chehab 	}
2154b285192aSMauro Carvalho Chehab 
2155b285192aSMauro Carvalho Chehab 	if (cx23885_dev_setup(dev) < 0) {
2156b285192aSMauro Carvalho Chehab 		err = -EINVAL;
2157da59a4deSHans Verkuil 		goto fail_ctrl;
2158b285192aSMauro Carvalho Chehab 	}
2159b285192aSMauro Carvalho Chehab 
2160b285192aSMauro Carvalho Chehab 	/* print pci info */
2161b285192aSMauro Carvalho Chehab 	dev->pci_rev = pci_dev->revision;
2162b285192aSMauro Carvalho Chehab 	pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER,  &dev->pci_lat);
2163e39682b5SMauro Carvalho Chehab 	pr_info("%s/0: found at %s, rev: %d, irq: %d, latency: %d, mmio: 0x%llx\n",
216407ab29e1SMauro Carvalho Chehab 	       dev->name,
2165b285192aSMauro Carvalho Chehab 	       pci_name(pci_dev), dev->pci_rev, pci_dev->irq,
2166b285192aSMauro Carvalho Chehab 	       dev->pci_lat,
2167b285192aSMauro Carvalho Chehab 		(unsigned long long)pci_resource_start(pci_dev, 0));
2168b285192aSMauro Carvalho Chehab 
2169b285192aSMauro Carvalho Chehab 	pci_set_master(pci_dev);
21707a77379fSChristophe JAILLET 	err = dma_set_mask(&pci_dev->dev, 0xffffffff);
21711a47de6eSChristoph Hellwig 	if (err) {
2172e39682b5SMauro Carvalho Chehab 		pr_err("%s/0: Oops: no 32bit PCI DMA ???\n", dev->name);
2173e8123311SZheyu Ma 		goto fail_dma_set_mask;
2174b285192aSMauro Carvalho Chehab 	}
2175b285192aSMauro Carvalho Chehab 
2176b285192aSMauro Carvalho Chehab 	err = request_irq(pci_dev->irq, cx23885_irq,
21773e018fe4SMichael Opdenacker 			  IRQF_SHARED, dev->name, dev);
2178b285192aSMauro Carvalho Chehab 	if (err < 0) {
2179e39682b5SMauro Carvalho Chehab 		pr_err("%s: can't get IRQ %d\n",
2180b285192aSMauro Carvalho Chehab 		       dev->name, pci_dev->irq);
2181e8123311SZheyu Ma 		goto fail_dma_set_mask;
2182b285192aSMauro Carvalho Chehab 	}
2183b285192aSMauro Carvalho Chehab 
2184b285192aSMauro Carvalho Chehab 	switch (dev->board) {
2185b285192aSMauro Carvalho Chehab 	case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
2186b285192aSMauro Carvalho Chehab 		cx23885_irq_add_enable(dev, PCI_MSK_GPIO1 | PCI_MSK_GPIO0);
2187b285192aSMauro Carvalho Chehab 		break;
2188b285192aSMauro Carvalho Chehab 	case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF:
2189b285192aSMauro Carvalho Chehab 		cx23885_irq_add_enable(dev, PCI_MSK_GPIO0);
2190b285192aSMauro Carvalho Chehab 		break;
2191b285192aSMauro Carvalho Chehab 	}
2192b285192aSMauro Carvalho Chehab 
2193b285192aSMauro Carvalho Chehab 	/*
2194b285192aSMauro Carvalho Chehab 	 * The CX2388[58] IR controller can start firing interrupts when
2195b285192aSMauro Carvalho Chehab 	 * enabled, so these have to take place after the cx23885_irq() handler
2196b285192aSMauro Carvalho Chehab 	 * is hooked up by the call to request_irq() above.
2197b285192aSMauro Carvalho Chehab 	 */
2198b285192aSMauro Carvalho Chehab 	cx23885_ir_pci_int_enable(dev);
2199b285192aSMauro Carvalho Chehab 	cx23885_input_init(dev);
2200b285192aSMauro Carvalho Chehab 
2201b285192aSMauro Carvalho Chehab 	return 0;
2202b285192aSMauro Carvalho Chehab 
2203e8123311SZheyu Ma fail_dma_set_mask:
2204b285192aSMauro Carvalho Chehab 	cx23885_dev_unregister(dev);
2205da59a4deSHans Verkuil fail_ctrl:
2206da59a4deSHans Verkuil 	v4l2_ctrl_handler_free(hdl);
2207b285192aSMauro Carvalho Chehab 	v4l2_device_unregister(&dev->v4l2_dev);
2208b285192aSMauro Carvalho Chehab fail_free:
2209b285192aSMauro Carvalho Chehab 	kfree(dev);
2210b285192aSMauro Carvalho Chehab 	return err;
2211b285192aSMauro Carvalho Chehab }
2212b285192aSMauro Carvalho Chehab 
cx23885_finidev(struct pci_dev * pci_dev)22134c62e976SGreg Kroah-Hartman static void cx23885_finidev(struct pci_dev *pci_dev)
2214b285192aSMauro Carvalho Chehab {
2215b285192aSMauro Carvalho Chehab 	struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
2216b285192aSMauro Carvalho Chehab 	struct cx23885_dev *dev = to_cx23885(v4l2_dev);
2217b285192aSMauro Carvalho Chehab 
2218b285192aSMauro Carvalho Chehab 	cx23885_input_fini(dev);
2219b285192aSMauro Carvalho Chehab 	cx23885_ir_fini(dev);
2220b285192aSMauro Carvalho Chehab 
2221b285192aSMauro Carvalho Chehab 	cx23885_shutdown(dev);
2222b285192aSMauro Carvalho Chehab 
2223b285192aSMauro Carvalho Chehab 	/* unregister stuff */
2224b285192aSMauro Carvalho Chehab 	free_irq(pci_dev->irq, dev);
2225b285192aSMauro Carvalho Chehab 
22268d4d9329SHans Verkuil 	pci_disable_device(pci_dev);
22278d4d9329SHans Verkuil 
2228b285192aSMauro Carvalho Chehab 	cx23885_dev_unregister(dev);
2229da59a4deSHans Verkuil 	v4l2_ctrl_handler_free(&dev->ctrl_handler);
2230b285192aSMauro Carvalho Chehab 	v4l2_device_unregister(v4l2_dev);
2231b285192aSMauro Carvalho Chehab 	kfree(dev);
2232b285192aSMauro Carvalho Chehab }
2233b285192aSMauro Carvalho Chehab 
22340fcefb39SArvind Yadav static const struct pci_device_id cx23885_pci_tbl[] = {
2235b285192aSMauro Carvalho Chehab 	{
2236b285192aSMauro Carvalho Chehab 		/* CX23885 */
2237b285192aSMauro Carvalho Chehab 		.vendor       = 0x14f1,
2238b285192aSMauro Carvalho Chehab 		.device       = 0x8852,
2239b285192aSMauro Carvalho Chehab 		.subvendor    = PCI_ANY_ID,
2240b285192aSMauro Carvalho Chehab 		.subdevice    = PCI_ANY_ID,
2241b285192aSMauro Carvalho Chehab 	}, {
2242b285192aSMauro Carvalho Chehab 		/* CX23887 Rev 2 */
2243b285192aSMauro Carvalho Chehab 		.vendor       = 0x14f1,
2244b285192aSMauro Carvalho Chehab 		.device       = 0x8880,
2245b285192aSMauro Carvalho Chehab 		.subvendor    = PCI_ANY_ID,
2246b285192aSMauro Carvalho Chehab 		.subdevice    = PCI_ANY_ID,
2247b285192aSMauro Carvalho Chehab 	}, {
2248b285192aSMauro Carvalho Chehab 		/* --- end of list --- */
2249b285192aSMauro Carvalho Chehab 	}
2250b285192aSMauro Carvalho Chehab };
2251b285192aSMauro Carvalho Chehab MODULE_DEVICE_TABLE(pci, cx23885_pci_tbl);
2252b285192aSMauro Carvalho Chehab 
2253b285192aSMauro Carvalho Chehab static struct pci_driver cx23885_pci_driver = {
2254b285192aSMauro Carvalho Chehab 	.name     = "cx23885",
2255b285192aSMauro Carvalho Chehab 	.id_table = cx23885_pci_tbl,
2256b285192aSMauro Carvalho Chehab 	.probe    = cx23885_initdev,
22574c62e976SGreg Kroah-Hartman 	.remove   = cx23885_finidev,
2258b285192aSMauro Carvalho Chehab };
2259b285192aSMauro Carvalho Chehab 
cx23885_init(void)2260b285192aSMauro Carvalho Chehab static int __init cx23885_init(void)
2261b285192aSMauro Carvalho Chehab {
2262e39682b5SMauro Carvalho Chehab 	pr_info("cx23885 driver version %s loaded\n",
2263b285192aSMauro Carvalho Chehab 		CX23885_VERSION);
2264b285192aSMauro Carvalho Chehab 	return pci_register_driver(&cx23885_pci_driver);
2265b285192aSMauro Carvalho Chehab }
2266b285192aSMauro Carvalho Chehab 
cx23885_fini(void)2267b285192aSMauro Carvalho Chehab static void __exit cx23885_fini(void)
2268b285192aSMauro Carvalho Chehab {
2269b285192aSMauro Carvalho Chehab 	pci_unregister_driver(&cx23885_pci_driver);
2270b285192aSMauro Carvalho Chehab }
2271b285192aSMauro Carvalho Chehab 
2272b285192aSMauro Carvalho Chehab module_init(cx23885_init);
2273b285192aSMauro Carvalho Chehab module_exit(cx23885_fini);
2274