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