1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2b285192aSMauro Carvalho Chehab /*
3b285192aSMauro Carvalho Chehab  *  Driver for the Conexant CX25821 PCIe bridge
4b285192aSMauro Carvalho Chehab  *
5b285192aSMauro Carvalho Chehab  *  Copyright (C) 2009 Conexant Systems Inc.
6b285192aSMauro Carvalho Chehab  *  Authors  <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
7b285192aSMauro Carvalho Chehab  *  Based on Steven Toth <stoth@linuxtv.org> cx23885 driver
8b285192aSMauro Carvalho Chehab  */
9b285192aSMauro Carvalho Chehab 
10b285192aSMauro Carvalho Chehab #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
11b285192aSMauro Carvalho Chehab 
12b285192aSMauro Carvalho Chehab #include <linux/i2c.h>
13b285192aSMauro Carvalho Chehab #include <linux/slab.h>
14b285192aSMauro Carvalho Chehab #include "cx25821.h"
15b285192aSMauro Carvalho Chehab #include "cx25821-sram.h"
16b285192aSMauro Carvalho Chehab #include "cx25821-video.h"
17b285192aSMauro Carvalho Chehab 
18b285192aSMauro Carvalho Chehab MODULE_DESCRIPTION("Driver for Athena cards");
19b285192aSMauro Carvalho Chehab MODULE_AUTHOR("Shu Lin - Hiep Huynh");
20b285192aSMauro Carvalho Chehab MODULE_LICENSE("GPL");
21b285192aSMauro Carvalho Chehab 
22b285192aSMauro Carvalho Chehab static unsigned int debug;
23b285192aSMauro Carvalho Chehab module_param(debug, int, 0644);
24b285192aSMauro Carvalho Chehab MODULE_PARM_DESC(debug, "enable debug messages");
25b285192aSMauro Carvalho Chehab 
26b285192aSMauro Carvalho Chehab static unsigned int card[] = {[0 ... (CX25821_MAXBOARDS - 1)] = UNSET };
27b285192aSMauro Carvalho Chehab module_param_array(card, int, NULL, 0444);
28b285192aSMauro Carvalho Chehab MODULE_PARM_DESC(card, "card type");
29b285192aSMauro Carvalho Chehab 
30bfef0d35SHans Verkuil const struct sram_channel cx25821_sram_channels[] = {
31b285192aSMauro Carvalho Chehab 	[SRAM_CH00] = {
32b285192aSMauro Carvalho Chehab 		.i = SRAM_CH00,
33b285192aSMauro Carvalho Chehab 		.name = "VID A",
34b285192aSMauro Carvalho Chehab 		.cmds_start = VID_A_DOWN_CMDS,
35b285192aSMauro Carvalho Chehab 		.ctrl_start = VID_A_IQ,
36b285192aSMauro Carvalho Chehab 		.cdt = VID_A_CDT,
37b285192aSMauro Carvalho Chehab 		.fifo_start = VID_A_DOWN_CLUSTER_1,
38b285192aSMauro Carvalho Chehab 		.fifo_size = (VID_CLUSTER_SIZE << 2),
39b285192aSMauro Carvalho Chehab 		.ptr1_reg = DMA1_PTR1,
40b285192aSMauro Carvalho Chehab 		.ptr2_reg = DMA1_PTR2,
41b285192aSMauro Carvalho Chehab 		.cnt1_reg = DMA1_CNT1,
42b285192aSMauro Carvalho Chehab 		.cnt2_reg = DMA1_CNT2,
43b285192aSMauro Carvalho Chehab 		.int_msk = VID_A_INT_MSK,
44b285192aSMauro Carvalho Chehab 		.int_stat = VID_A_INT_STAT,
45b285192aSMauro Carvalho Chehab 		.int_mstat = VID_A_INT_MSTAT,
46b285192aSMauro Carvalho Chehab 		.dma_ctl = VID_DST_A_DMA_CTL,
47b285192aSMauro Carvalho Chehab 		.gpcnt_ctl = VID_DST_A_GPCNT_CTL,
48b285192aSMauro Carvalho Chehab 		.gpcnt = VID_DST_A_GPCNT,
49b285192aSMauro Carvalho Chehab 		.vip_ctl = VID_DST_A_VIP_CTL,
50b285192aSMauro Carvalho Chehab 		.pix_frmt = VID_DST_A_PIX_FRMT,
51b285192aSMauro Carvalho Chehab 	},
52b285192aSMauro Carvalho Chehab 
53b285192aSMauro Carvalho Chehab 	[SRAM_CH01] = {
54b285192aSMauro Carvalho Chehab 		.i = SRAM_CH01,
55b285192aSMauro Carvalho Chehab 		.name = "VID B",
56b285192aSMauro Carvalho Chehab 		.cmds_start = VID_B_DOWN_CMDS,
57b285192aSMauro Carvalho Chehab 		.ctrl_start = VID_B_IQ,
58b285192aSMauro Carvalho Chehab 		.cdt = VID_B_CDT,
59b285192aSMauro Carvalho Chehab 		.fifo_start = VID_B_DOWN_CLUSTER_1,
60b285192aSMauro Carvalho Chehab 		.fifo_size = (VID_CLUSTER_SIZE << 2),
61b285192aSMauro Carvalho Chehab 		.ptr1_reg = DMA2_PTR1,
62b285192aSMauro Carvalho Chehab 		.ptr2_reg = DMA2_PTR2,
63b285192aSMauro Carvalho Chehab 		.cnt1_reg = DMA2_CNT1,
64b285192aSMauro Carvalho Chehab 		.cnt2_reg = DMA2_CNT2,
65b285192aSMauro Carvalho Chehab 		.int_msk = VID_B_INT_MSK,
66b285192aSMauro Carvalho Chehab 		.int_stat = VID_B_INT_STAT,
67b285192aSMauro Carvalho Chehab 		.int_mstat = VID_B_INT_MSTAT,
68b285192aSMauro Carvalho Chehab 		.dma_ctl = VID_DST_B_DMA_CTL,
69b285192aSMauro Carvalho Chehab 		.gpcnt_ctl = VID_DST_B_GPCNT_CTL,
70b285192aSMauro Carvalho Chehab 		.gpcnt = VID_DST_B_GPCNT,
71b285192aSMauro Carvalho Chehab 		.vip_ctl = VID_DST_B_VIP_CTL,
72b285192aSMauro Carvalho Chehab 		.pix_frmt = VID_DST_B_PIX_FRMT,
73b285192aSMauro Carvalho Chehab 	},
74b285192aSMauro Carvalho Chehab 
75b285192aSMauro Carvalho Chehab 	[SRAM_CH02] = {
76b285192aSMauro Carvalho Chehab 		.i = SRAM_CH02,
77b285192aSMauro Carvalho Chehab 		.name = "VID C",
78b285192aSMauro Carvalho Chehab 		.cmds_start = VID_C_DOWN_CMDS,
79b285192aSMauro Carvalho Chehab 		.ctrl_start = VID_C_IQ,
80b285192aSMauro Carvalho Chehab 		.cdt = VID_C_CDT,
81b285192aSMauro Carvalho Chehab 		.fifo_start = VID_C_DOWN_CLUSTER_1,
82b285192aSMauro Carvalho Chehab 		.fifo_size = (VID_CLUSTER_SIZE << 2),
83b285192aSMauro Carvalho Chehab 		.ptr1_reg = DMA3_PTR1,
84b285192aSMauro Carvalho Chehab 		.ptr2_reg = DMA3_PTR2,
85b285192aSMauro Carvalho Chehab 		.cnt1_reg = DMA3_CNT1,
86b285192aSMauro Carvalho Chehab 		.cnt2_reg = DMA3_CNT2,
87b285192aSMauro Carvalho Chehab 		.int_msk = VID_C_INT_MSK,
88b285192aSMauro Carvalho Chehab 		.int_stat = VID_C_INT_STAT,
89b285192aSMauro Carvalho Chehab 		.int_mstat = VID_C_INT_MSTAT,
90b285192aSMauro Carvalho Chehab 		.dma_ctl = VID_DST_C_DMA_CTL,
91b285192aSMauro Carvalho Chehab 		.gpcnt_ctl = VID_DST_C_GPCNT_CTL,
92b285192aSMauro Carvalho Chehab 		.gpcnt = VID_DST_C_GPCNT,
93b285192aSMauro Carvalho Chehab 		.vip_ctl = VID_DST_C_VIP_CTL,
94b285192aSMauro Carvalho Chehab 		.pix_frmt = VID_DST_C_PIX_FRMT,
95b285192aSMauro Carvalho Chehab 	},
96b285192aSMauro Carvalho Chehab 
97b285192aSMauro Carvalho Chehab 	[SRAM_CH03] = {
98b285192aSMauro Carvalho Chehab 		.i = SRAM_CH03,
99b285192aSMauro Carvalho Chehab 		.name = "VID D",
100b285192aSMauro Carvalho Chehab 		.cmds_start = VID_D_DOWN_CMDS,
101b285192aSMauro Carvalho Chehab 		.ctrl_start = VID_D_IQ,
102b285192aSMauro Carvalho Chehab 		.cdt = VID_D_CDT,
103b285192aSMauro Carvalho Chehab 		.fifo_start = VID_D_DOWN_CLUSTER_1,
104b285192aSMauro Carvalho Chehab 		.fifo_size = (VID_CLUSTER_SIZE << 2),
105b285192aSMauro Carvalho Chehab 		.ptr1_reg = DMA4_PTR1,
106b285192aSMauro Carvalho Chehab 		.ptr2_reg = DMA4_PTR2,
107b285192aSMauro Carvalho Chehab 		.cnt1_reg = DMA4_CNT1,
108b285192aSMauro Carvalho Chehab 		.cnt2_reg = DMA4_CNT2,
109b285192aSMauro Carvalho Chehab 		.int_msk = VID_D_INT_MSK,
110b285192aSMauro Carvalho Chehab 		.int_stat = VID_D_INT_STAT,
111b285192aSMauro Carvalho Chehab 		.int_mstat = VID_D_INT_MSTAT,
112b285192aSMauro Carvalho Chehab 		.dma_ctl = VID_DST_D_DMA_CTL,
113b285192aSMauro Carvalho Chehab 		.gpcnt_ctl = VID_DST_D_GPCNT_CTL,
114b285192aSMauro Carvalho Chehab 		.gpcnt = VID_DST_D_GPCNT,
115b285192aSMauro Carvalho Chehab 		.vip_ctl = VID_DST_D_VIP_CTL,
116b285192aSMauro Carvalho Chehab 		.pix_frmt = VID_DST_D_PIX_FRMT,
117b285192aSMauro Carvalho Chehab 	},
118b285192aSMauro Carvalho Chehab 
119b285192aSMauro Carvalho Chehab 	[SRAM_CH04] = {
120b285192aSMauro Carvalho Chehab 		.i = SRAM_CH04,
121b285192aSMauro Carvalho Chehab 		.name = "VID E",
122b285192aSMauro Carvalho Chehab 		.cmds_start = VID_E_DOWN_CMDS,
123b285192aSMauro Carvalho Chehab 		.ctrl_start = VID_E_IQ,
124b285192aSMauro Carvalho Chehab 		.cdt = VID_E_CDT,
125b285192aSMauro Carvalho Chehab 		.fifo_start = VID_E_DOWN_CLUSTER_1,
126b285192aSMauro Carvalho Chehab 		.fifo_size = (VID_CLUSTER_SIZE << 2),
127b285192aSMauro Carvalho Chehab 		.ptr1_reg = DMA5_PTR1,
128b285192aSMauro Carvalho Chehab 		.ptr2_reg = DMA5_PTR2,
129b285192aSMauro Carvalho Chehab 		.cnt1_reg = DMA5_CNT1,
130b285192aSMauro Carvalho Chehab 		.cnt2_reg = DMA5_CNT2,
131b285192aSMauro Carvalho Chehab 		.int_msk = VID_E_INT_MSK,
132b285192aSMauro Carvalho Chehab 		.int_stat = VID_E_INT_STAT,
133b285192aSMauro Carvalho Chehab 		.int_mstat = VID_E_INT_MSTAT,
134b285192aSMauro Carvalho Chehab 		.dma_ctl = VID_DST_E_DMA_CTL,
135b285192aSMauro Carvalho Chehab 		.gpcnt_ctl = VID_DST_E_GPCNT_CTL,
136b285192aSMauro Carvalho Chehab 		.gpcnt = VID_DST_E_GPCNT,
137b285192aSMauro Carvalho Chehab 		.vip_ctl = VID_DST_E_VIP_CTL,
138b285192aSMauro Carvalho Chehab 		.pix_frmt = VID_DST_E_PIX_FRMT,
139b285192aSMauro Carvalho Chehab 	},
140b285192aSMauro Carvalho Chehab 
141b285192aSMauro Carvalho Chehab 	[SRAM_CH05] = {
142b285192aSMauro Carvalho Chehab 		.i = SRAM_CH05,
143b285192aSMauro Carvalho Chehab 		.name = "VID F",
144b285192aSMauro Carvalho Chehab 		.cmds_start = VID_F_DOWN_CMDS,
145b285192aSMauro Carvalho Chehab 		.ctrl_start = VID_F_IQ,
146b285192aSMauro Carvalho Chehab 		.cdt = VID_F_CDT,
147b285192aSMauro Carvalho Chehab 		.fifo_start = VID_F_DOWN_CLUSTER_1,
148b285192aSMauro Carvalho Chehab 		.fifo_size = (VID_CLUSTER_SIZE << 2),
149b285192aSMauro Carvalho Chehab 		.ptr1_reg = DMA6_PTR1,
150b285192aSMauro Carvalho Chehab 		.ptr2_reg = DMA6_PTR2,
151b285192aSMauro Carvalho Chehab 		.cnt1_reg = DMA6_CNT1,
152b285192aSMauro Carvalho Chehab 		.cnt2_reg = DMA6_CNT2,
153b285192aSMauro Carvalho Chehab 		.int_msk = VID_F_INT_MSK,
154b285192aSMauro Carvalho Chehab 		.int_stat = VID_F_INT_STAT,
155b285192aSMauro Carvalho Chehab 		.int_mstat = VID_F_INT_MSTAT,
156b285192aSMauro Carvalho Chehab 		.dma_ctl = VID_DST_F_DMA_CTL,
157b285192aSMauro Carvalho Chehab 		.gpcnt_ctl = VID_DST_F_GPCNT_CTL,
158b285192aSMauro Carvalho Chehab 		.gpcnt = VID_DST_F_GPCNT,
159b285192aSMauro Carvalho Chehab 		.vip_ctl = VID_DST_F_VIP_CTL,
160b285192aSMauro Carvalho Chehab 		.pix_frmt = VID_DST_F_PIX_FRMT,
161b285192aSMauro Carvalho Chehab 	},
162b285192aSMauro Carvalho Chehab 
163b285192aSMauro Carvalho Chehab 	[SRAM_CH06] = {
164b285192aSMauro Carvalho Chehab 		.i = SRAM_CH06,
165b285192aSMauro Carvalho Chehab 		.name = "VID G",
166b285192aSMauro Carvalho Chehab 		.cmds_start = VID_G_DOWN_CMDS,
167b285192aSMauro Carvalho Chehab 		.ctrl_start = VID_G_IQ,
168b285192aSMauro Carvalho Chehab 		.cdt = VID_G_CDT,
169b285192aSMauro Carvalho Chehab 		.fifo_start = VID_G_DOWN_CLUSTER_1,
170b285192aSMauro Carvalho Chehab 		.fifo_size = (VID_CLUSTER_SIZE << 2),
171b285192aSMauro Carvalho Chehab 		.ptr1_reg = DMA7_PTR1,
172b285192aSMauro Carvalho Chehab 		.ptr2_reg = DMA7_PTR2,
173b285192aSMauro Carvalho Chehab 		.cnt1_reg = DMA7_CNT1,
174b285192aSMauro Carvalho Chehab 		.cnt2_reg = DMA7_CNT2,
175b285192aSMauro Carvalho Chehab 		.int_msk = VID_G_INT_MSK,
176b285192aSMauro Carvalho Chehab 		.int_stat = VID_G_INT_STAT,
177b285192aSMauro Carvalho Chehab 		.int_mstat = VID_G_INT_MSTAT,
178b285192aSMauro Carvalho Chehab 		.dma_ctl = VID_DST_G_DMA_CTL,
179b285192aSMauro Carvalho Chehab 		.gpcnt_ctl = VID_DST_G_GPCNT_CTL,
180b285192aSMauro Carvalho Chehab 		.gpcnt = VID_DST_G_GPCNT,
181b285192aSMauro Carvalho Chehab 		.vip_ctl = VID_DST_G_VIP_CTL,
182b285192aSMauro Carvalho Chehab 		.pix_frmt = VID_DST_G_PIX_FRMT,
183b285192aSMauro Carvalho Chehab 	},
184b285192aSMauro Carvalho Chehab 
185b285192aSMauro Carvalho Chehab 	[SRAM_CH07] = {
186b285192aSMauro Carvalho Chehab 		.i = SRAM_CH07,
187b285192aSMauro Carvalho Chehab 		.name = "VID H",
188b285192aSMauro Carvalho Chehab 		.cmds_start = VID_H_DOWN_CMDS,
189b285192aSMauro Carvalho Chehab 		.ctrl_start = VID_H_IQ,
190b285192aSMauro Carvalho Chehab 		.cdt = VID_H_CDT,
191b285192aSMauro Carvalho Chehab 		.fifo_start = VID_H_DOWN_CLUSTER_1,
192b285192aSMauro Carvalho Chehab 		.fifo_size = (VID_CLUSTER_SIZE << 2),
193b285192aSMauro Carvalho Chehab 		.ptr1_reg = DMA8_PTR1,
194b285192aSMauro Carvalho Chehab 		.ptr2_reg = DMA8_PTR2,
195b285192aSMauro Carvalho Chehab 		.cnt1_reg = DMA8_CNT1,
196b285192aSMauro Carvalho Chehab 		.cnt2_reg = DMA8_CNT2,
197b285192aSMauro Carvalho Chehab 		.int_msk = VID_H_INT_MSK,
198b285192aSMauro Carvalho Chehab 		.int_stat = VID_H_INT_STAT,
199b285192aSMauro Carvalho Chehab 		.int_mstat = VID_H_INT_MSTAT,
200b285192aSMauro Carvalho Chehab 		.dma_ctl = VID_DST_H_DMA_CTL,
201b285192aSMauro Carvalho Chehab 		.gpcnt_ctl = VID_DST_H_GPCNT_CTL,
202b285192aSMauro Carvalho Chehab 		.gpcnt = VID_DST_H_GPCNT,
203b285192aSMauro Carvalho Chehab 		.vip_ctl = VID_DST_H_VIP_CTL,
204b285192aSMauro Carvalho Chehab 		.pix_frmt = VID_DST_H_PIX_FRMT,
205b285192aSMauro Carvalho Chehab 	},
206b285192aSMauro Carvalho Chehab 
207b285192aSMauro Carvalho Chehab 	[SRAM_CH08] = {
208b285192aSMauro Carvalho Chehab 		.name = "audio from",
209b285192aSMauro Carvalho Chehab 		.cmds_start = AUD_A_DOWN_CMDS,
210b285192aSMauro Carvalho Chehab 		.ctrl_start = AUD_A_IQ,
211b285192aSMauro Carvalho Chehab 		.cdt = AUD_A_CDT,
212b285192aSMauro Carvalho Chehab 		.fifo_start = AUD_A_DOWN_CLUSTER_1,
213b285192aSMauro Carvalho Chehab 		.fifo_size = AUDIO_CLUSTER_SIZE * 3,
214b285192aSMauro Carvalho Chehab 		.ptr1_reg = DMA17_PTR1,
215b285192aSMauro Carvalho Chehab 		.ptr2_reg = DMA17_PTR2,
216b285192aSMauro Carvalho Chehab 		.cnt1_reg = DMA17_CNT1,
217b285192aSMauro Carvalho Chehab 		.cnt2_reg = DMA17_CNT2,
218b285192aSMauro Carvalho Chehab 	},
219b285192aSMauro Carvalho Chehab 
220b285192aSMauro Carvalho Chehab 	[SRAM_CH09] = {
221b285192aSMauro Carvalho Chehab 		.i = SRAM_CH09,
222b285192aSMauro Carvalho Chehab 		.name = "VID Upstream I",
223b285192aSMauro Carvalho Chehab 		.cmds_start = VID_I_UP_CMDS,
224b285192aSMauro Carvalho Chehab 		.ctrl_start = VID_I_IQ,
225b285192aSMauro Carvalho Chehab 		.cdt = VID_I_CDT,
226b285192aSMauro Carvalho Chehab 		.fifo_start = VID_I_UP_CLUSTER_1,
227b285192aSMauro Carvalho Chehab 		.fifo_size = (VID_CLUSTER_SIZE << 2),
228b285192aSMauro Carvalho Chehab 		.ptr1_reg = DMA15_PTR1,
229b285192aSMauro Carvalho Chehab 		.ptr2_reg = DMA15_PTR2,
230b285192aSMauro Carvalho Chehab 		.cnt1_reg = DMA15_CNT1,
231b285192aSMauro Carvalho Chehab 		.cnt2_reg = DMA15_CNT2,
232b285192aSMauro Carvalho Chehab 		.int_msk = VID_I_INT_MSK,
233b285192aSMauro Carvalho Chehab 		.int_stat = VID_I_INT_STAT,
234b285192aSMauro Carvalho Chehab 		.int_mstat = VID_I_INT_MSTAT,
235b285192aSMauro Carvalho Chehab 		.dma_ctl = VID_SRC_I_DMA_CTL,
236b285192aSMauro Carvalho Chehab 		.gpcnt_ctl = VID_SRC_I_GPCNT_CTL,
237b285192aSMauro Carvalho Chehab 		.gpcnt = VID_SRC_I_GPCNT,
238b285192aSMauro Carvalho Chehab 
239b285192aSMauro Carvalho Chehab 		.vid_fmt_ctl = VID_SRC_I_FMT_CTL,
240b285192aSMauro Carvalho Chehab 		.vid_active_ctl1 = VID_SRC_I_ACTIVE_CTL1,
241b285192aSMauro Carvalho Chehab 		.vid_active_ctl2 = VID_SRC_I_ACTIVE_CTL2,
242b285192aSMauro Carvalho Chehab 		.vid_cdt_size = VID_SRC_I_CDT_SZ,
243b285192aSMauro Carvalho Chehab 		.irq_bit = 8,
244b285192aSMauro Carvalho Chehab 	},
245b285192aSMauro Carvalho Chehab 
246b285192aSMauro Carvalho Chehab 	[SRAM_CH10] = {
247b285192aSMauro Carvalho Chehab 		.i = SRAM_CH10,
248b285192aSMauro Carvalho Chehab 		.name = "VID Upstream J",
249b285192aSMauro Carvalho Chehab 		.cmds_start = VID_J_UP_CMDS,
250b285192aSMauro Carvalho Chehab 		.ctrl_start = VID_J_IQ,
251b285192aSMauro Carvalho Chehab 		.cdt = VID_J_CDT,
252b285192aSMauro Carvalho Chehab 		.fifo_start = VID_J_UP_CLUSTER_1,
253b285192aSMauro Carvalho Chehab 		.fifo_size = (VID_CLUSTER_SIZE << 2),
254b285192aSMauro Carvalho Chehab 		.ptr1_reg = DMA16_PTR1,
255b285192aSMauro Carvalho Chehab 		.ptr2_reg = DMA16_PTR2,
256b285192aSMauro Carvalho Chehab 		.cnt1_reg = DMA16_CNT1,
257b285192aSMauro Carvalho Chehab 		.cnt2_reg = DMA16_CNT2,
258b285192aSMauro Carvalho Chehab 		.int_msk = VID_J_INT_MSK,
259b285192aSMauro Carvalho Chehab 		.int_stat = VID_J_INT_STAT,
260b285192aSMauro Carvalho Chehab 		.int_mstat = VID_J_INT_MSTAT,
261b285192aSMauro Carvalho Chehab 		.dma_ctl = VID_SRC_J_DMA_CTL,
262b285192aSMauro Carvalho Chehab 		.gpcnt_ctl = VID_SRC_J_GPCNT_CTL,
263b285192aSMauro Carvalho Chehab 		.gpcnt = VID_SRC_J_GPCNT,
264b285192aSMauro Carvalho Chehab 
265b285192aSMauro Carvalho Chehab 		.vid_fmt_ctl = VID_SRC_J_FMT_CTL,
266b285192aSMauro Carvalho Chehab 		.vid_active_ctl1 = VID_SRC_J_ACTIVE_CTL1,
267b285192aSMauro Carvalho Chehab 		.vid_active_ctl2 = VID_SRC_J_ACTIVE_CTL2,
268b285192aSMauro Carvalho Chehab 		.vid_cdt_size = VID_SRC_J_CDT_SZ,
269b285192aSMauro Carvalho Chehab 		.irq_bit = 9,
270b285192aSMauro Carvalho Chehab 	},
271b285192aSMauro Carvalho Chehab 
272b285192aSMauro Carvalho Chehab 	[SRAM_CH11] = {
273b285192aSMauro Carvalho Chehab 		.i = SRAM_CH11,
274b285192aSMauro Carvalho Chehab 		.name = "Audio Upstream Channel B",
275b285192aSMauro Carvalho Chehab 		.cmds_start = AUD_B_UP_CMDS,
276b285192aSMauro Carvalho Chehab 		.ctrl_start = AUD_B_IQ,
277b285192aSMauro Carvalho Chehab 		.cdt = AUD_B_CDT,
278b285192aSMauro Carvalho Chehab 		.fifo_start = AUD_B_UP_CLUSTER_1,
279b285192aSMauro Carvalho Chehab 		.fifo_size = (AUDIO_CLUSTER_SIZE * 3),
280b285192aSMauro Carvalho Chehab 		.ptr1_reg = DMA22_PTR1,
281b285192aSMauro Carvalho Chehab 		.ptr2_reg = DMA22_PTR2,
282b285192aSMauro Carvalho Chehab 		.cnt1_reg = DMA22_CNT1,
283b285192aSMauro Carvalho Chehab 		.cnt2_reg = DMA22_CNT2,
284b285192aSMauro Carvalho Chehab 		.int_msk = AUD_B_INT_MSK,
285b285192aSMauro Carvalho Chehab 		.int_stat = AUD_B_INT_STAT,
286b285192aSMauro Carvalho Chehab 		.int_mstat = AUD_B_INT_MSTAT,
287b285192aSMauro Carvalho Chehab 		.dma_ctl = AUD_INT_DMA_CTL,
288b285192aSMauro Carvalho Chehab 		.gpcnt_ctl = AUD_B_GPCNT_CTL,
289b285192aSMauro Carvalho Chehab 		.gpcnt = AUD_B_GPCNT,
290b285192aSMauro Carvalho Chehab 		.aud_length = AUD_B_LNGTH,
291b285192aSMauro Carvalho Chehab 		.aud_cfg = AUD_B_CFG,
292b285192aSMauro Carvalho Chehab 		.fld_aud_fifo_en = FLD_AUD_SRC_B_FIFO_EN,
293b285192aSMauro Carvalho Chehab 		.fld_aud_risc_en = FLD_AUD_SRC_B_RISC_EN,
294b285192aSMauro Carvalho Chehab 		.irq_bit = 11,
295b285192aSMauro Carvalho Chehab 	},
296b285192aSMauro Carvalho Chehab };
297b285192aSMauro Carvalho Chehab EXPORT_SYMBOL(cx25821_sram_channels);
298b285192aSMauro Carvalho Chehab 
cx25821_risc_decode(u32 risc)299b285192aSMauro Carvalho Chehab static int cx25821_risc_decode(u32 risc)
300b285192aSMauro Carvalho Chehab {
301b285192aSMauro Carvalho Chehab 	static const char * const instr[16] = {
302b285192aSMauro Carvalho Chehab 		[RISC_SYNC >> 28] = "sync",
303b285192aSMauro Carvalho Chehab 		[RISC_WRITE >> 28] = "write",
304b285192aSMauro Carvalho Chehab 		[RISC_WRITEC >> 28] = "writec",
305b285192aSMauro Carvalho Chehab 		[RISC_READ >> 28] = "read",
306b285192aSMauro Carvalho Chehab 		[RISC_READC >> 28] = "readc",
307b285192aSMauro Carvalho Chehab 		[RISC_JUMP >> 28] = "jump",
308b285192aSMauro Carvalho Chehab 		[RISC_SKIP >> 28] = "skip",
309b285192aSMauro Carvalho Chehab 		[RISC_WRITERM >> 28] = "writerm",
310b285192aSMauro Carvalho Chehab 		[RISC_WRITECM >> 28] = "writecm",
311b285192aSMauro Carvalho Chehab 		[RISC_WRITECR >> 28] = "writecr",
312b285192aSMauro Carvalho Chehab 	};
313b285192aSMauro Carvalho Chehab 	static const int incr[16] = {
314b285192aSMauro Carvalho Chehab 		[RISC_WRITE >> 28] = 3,
315b285192aSMauro Carvalho Chehab 		[RISC_JUMP >> 28] = 3,
316b285192aSMauro Carvalho Chehab 		[RISC_SKIP >> 28] = 1,
317b285192aSMauro Carvalho Chehab 		[RISC_SYNC >> 28] = 1,
318b285192aSMauro Carvalho Chehab 		[RISC_WRITERM >> 28] = 3,
319b285192aSMauro Carvalho Chehab 		[RISC_WRITECM >> 28] = 3,
320b285192aSMauro Carvalho Chehab 		[RISC_WRITECR >> 28] = 4,
321b285192aSMauro Carvalho Chehab 	};
322b285192aSMauro Carvalho Chehab 	static const char * const bits[] = {
323b285192aSMauro Carvalho Chehab 		"12", "13", "14", "resync",
324b285192aSMauro Carvalho Chehab 		"cnt0", "cnt1", "18", "19",
325b285192aSMauro Carvalho Chehab 		"20", "21", "22", "23",
326b285192aSMauro Carvalho Chehab 		"irq1", "irq2", "eol", "sol",
327b285192aSMauro Carvalho Chehab 	};
328b285192aSMauro Carvalho Chehab 	int i;
329b285192aSMauro Carvalho Chehab 
330b285192aSMauro Carvalho Chehab 	pr_cont("0x%08x [ %s",
331b285192aSMauro Carvalho Chehab 		risc, instr[risc >> 28] ? instr[risc >> 28] : "INVALID");
332b285192aSMauro Carvalho Chehab 	for (i = ARRAY_SIZE(bits) - 1; i >= 0; i--) {
333b285192aSMauro Carvalho Chehab 		if (risc & (1 << (i + 12)))
334b285192aSMauro Carvalho Chehab 			pr_cont(" %s", bits[i]);
335b285192aSMauro Carvalho Chehab 	}
336b285192aSMauro Carvalho Chehab 	pr_cont(" count=%d ]\n", risc & 0xfff);
337b285192aSMauro Carvalho Chehab 	return incr[risc >> 28] ? incr[risc >> 28] : 1;
338b285192aSMauro Carvalho Chehab }
339b285192aSMauro Carvalho Chehab 
cx25821_registers_init(struct cx25821_dev * dev)340b285192aSMauro Carvalho Chehab static void cx25821_registers_init(struct cx25821_dev *dev)
341b285192aSMauro Carvalho Chehab {
342b285192aSMauro Carvalho Chehab 	u32 tmp;
343b285192aSMauro Carvalho Chehab 
344b285192aSMauro Carvalho Chehab 	/* enable RUN_RISC in Pecos */
345b285192aSMauro Carvalho Chehab 	cx_write(DEV_CNTRL2, 0x20);
346b285192aSMauro Carvalho Chehab 
347b285192aSMauro Carvalho Chehab 	/* Set the master PCI interrupt masks to enable video, audio, MBIF,
348b285192aSMauro Carvalho Chehab 	 * and GPIO interrupts
349b285192aSMauro Carvalho Chehab 	 * I2C interrupt masking is handled by the I2C objects themselves. */
350b285192aSMauro Carvalho Chehab 	cx_write(PCI_INT_MSK, 0x2001FFFF);
351b285192aSMauro Carvalho Chehab 
352b285192aSMauro Carvalho Chehab 	tmp = cx_read(RDR_TLCTL0);
353b285192aSMauro Carvalho Chehab 	tmp &= ~FLD_CFG_RCB_CK_EN;	/* Clear the RCB_CK_EN bit */
354b285192aSMauro Carvalho Chehab 	cx_write(RDR_TLCTL0, tmp);
355b285192aSMauro Carvalho Chehab 
356b285192aSMauro Carvalho Chehab 	/* PLL-A setting for the Audio Master Clock */
357b285192aSMauro Carvalho Chehab 	cx_write(PLL_A_INT_FRAC, 0x9807A58B);
358b285192aSMauro Carvalho Chehab 
359b285192aSMauro Carvalho Chehab 	/* PLL_A_POST = 0x1C, PLL_A_OUT_TO_PIN = 0x1 */
360b285192aSMauro Carvalho Chehab 	cx_write(PLL_A_POST_STAT_BIST, 0x8000019C);
361b285192aSMauro Carvalho Chehab 
362b285192aSMauro Carvalho Chehab 	/* clear reset bit [31] */
363b285192aSMauro Carvalho Chehab 	tmp = cx_read(PLL_A_INT_FRAC);
364b285192aSMauro Carvalho Chehab 	cx_write(PLL_A_INT_FRAC, tmp & 0x7FFFFFFF);
365b285192aSMauro Carvalho Chehab 
366b285192aSMauro Carvalho Chehab 	/* PLL-B setting for Mobilygen Host Bus Interface */
367b285192aSMauro Carvalho Chehab 	cx_write(PLL_B_INT_FRAC, 0x9883A86F);
368b285192aSMauro Carvalho Chehab 
369b285192aSMauro Carvalho Chehab 	/* PLL_B_POST = 0xD, PLL_B_OUT_TO_PIN = 0x0 */
370b285192aSMauro Carvalho Chehab 	cx_write(PLL_B_POST_STAT_BIST, 0x8000018D);
371b285192aSMauro Carvalho Chehab 
372b285192aSMauro Carvalho Chehab 	/* clear reset bit [31] */
373b285192aSMauro Carvalho Chehab 	tmp = cx_read(PLL_B_INT_FRAC);
374b285192aSMauro Carvalho Chehab 	cx_write(PLL_B_INT_FRAC, tmp & 0x7FFFFFFF);
375b285192aSMauro Carvalho Chehab 
376b285192aSMauro Carvalho Chehab 	/* PLL-C setting for video upstream channel */
377b285192aSMauro Carvalho Chehab 	cx_write(PLL_C_INT_FRAC, 0x96A0EA3F);
378b285192aSMauro Carvalho Chehab 
379b285192aSMauro Carvalho Chehab 	/* PLL_C_POST = 0x3, PLL_C_OUT_TO_PIN = 0x0 */
380b285192aSMauro Carvalho Chehab 	cx_write(PLL_C_POST_STAT_BIST, 0x80000103);
381b285192aSMauro Carvalho Chehab 
382b285192aSMauro Carvalho Chehab 	/* clear reset bit [31] */
383b285192aSMauro Carvalho Chehab 	tmp = cx_read(PLL_C_INT_FRAC);
384b285192aSMauro Carvalho Chehab 	cx_write(PLL_C_INT_FRAC, tmp & 0x7FFFFFFF);
385b285192aSMauro Carvalho Chehab 
386b285192aSMauro Carvalho Chehab 	/* PLL-D setting for audio upstream channel */
387b285192aSMauro Carvalho Chehab 	cx_write(PLL_D_INT_FRAC, 0x98757F5B);
388b285192aSMauro Carvalho Chehab 
389b285192aSMauro Carvalho Chehab 	/* PLL_D_POST = 0x13, PLL_D_OUT_TO_PIN = 0x0 */
390b285192aSMauro Carvalho Chehab 	cx_write(PLL_D_POST_STAT_BIST, 0x80000113);
391b285192aSMauro Carvalho Chehab 
392b285192aSMauro Carvalho Chehab 	/* clear reset bit [31] */
393b285192aSMauro Carvalho Chehab 	tmp = cx_read(PLL_D_INT_FRAC);
394b285192aSMauro Carvalho Chehab 	cx_write(PLL_D_INT_FRAC, tmp & 0x7FFFFFFF);
395b285192aSMauro Carvalho Chehab 
396b285192aSMauro Carvalho Chehab 	/* This selects the PLL C clock source for the video upstream channel
397b285192aSMauro Carvalho Chehab 	 * I and J */
398b285192aSMauro Carvalho Chehab 	tmp = cx_read(VID_CH_CLK_SEL);
399b285192aSMauro Carvalho Chehab 	cx_write(VID_CH_CLK_SEL, (tmp & 0x00FFFFFF) | 0x24000000);
400b285192aSMauro Carvalho Chehab 
401b285192aSMauro Carvalho Chehab 	/* 656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface for
402b285192aSMauro Carvalho Chehab 	 * channel A-C
403b285192aSMauro Carvalho Chehab 	 * select 656/VIP DST for downstream Channel A - C */
404b285192aSMauro Carvalho Chehab 	tmp = cx_read(VID_CH_MODE_SEL);
405b285192aSMauro Carvalho Chehab 	/* cx_write( VID_CH_MODE_SEL, tmp | 0x1B0001FF); */
406b285192aSMauro Carvalho Chehab 	cx_write(VID_CH_MODE_SEL, tmp & 0xFFFFFE00);
407b285192aSMauro Carvalho Chehab 
408b285192aSMauro Carvalho Chehab 	/* enables 656 port I and J as output */
409b285192aSMauro Carvalho Chehab 	tmp = cx_read(CLK_RST);
410b285192aSMauro Carvalho Chehab 	/* use external ALT_PLL_REF pin as its reference clock instead */
411b285192aSMauro Carvalho Chehab 	tmp |= FLD_USE_ALT_PLL_REF;
412b285192aSMauro Carvalho Chehab 	cx_write(CLK_RST, tmp & ~(FLD_VID_I_CLK_NOE | FLD_VID_J_CLK_NOE));
413b285192aSMauro Carvalho Chehab 
41465155a9bSJia-Ju Bai 	msleep(100);
415b285192aSMauro Carvalho Chehab }
416b285192aSMauro Carvalho Chehab 
cx25821_sram_channel_setup(struct cx25821_dev * dev,const struct sram_channel * ch,unsigned int bpl,u32 risc)417b285192aSMauro Carvalho Chehab int cx25821_sram_channel_setup(struct cx25821_dev *dev,
418bfef0d35SHans Verkuil 			       const struct sram_channel *ch,
419b285192aSMauro Carvalho Chehab 			       unsigned int bpl, u32 risc)
420b285192aSMauro Carvalho Chehab {
421b285192aSMauro Carvalho Chehab 	unsigned int i, lines;
422b285192aSMauro Carvalho Chehab 	u32 cdt;
423b285192aSMauro Carvalho Chehab 
424b285192aSMauro Carvalho Chehab 	if (ch->cmds_start == 0) {
425b285192aSMauro Carvalho Chehab 		cx_write(ch->ptr1_reg, 0);
426b285192aSMauro Carvalho Chehab 		cx_write(ch->ptr2_reg, 0);
427b285192aSMauro Carvalho Chehab 		cx_write(ch->cnt2_reg, 0);
428b285192aSMauro Carvalho Chehab 		cx_write(ch->cnt1_reg, 0);
429b285192aSMauro Carvalho Chehab 		return 0;
430b285192aSMauro Carvalho Chehab 	}
431b285192aSMauro Carvalho Chehab 
432b285192aSMauro Carvalho Chehab 	bpl = (bpl + 7) & ~7;	/* alignment */
433b285192aSMauro Carvalho Chehab 	cdt = ch->cdt;
434b285192aSMauro Carvalho Chehab 	lines = ch->fifo_size / bpl;
435b285192aSMauro Carvalho Chehab 
436b285192aSMauro Carvalho Chehab 	if (lines > 4)
437b285192aSMauro Carvalho Chehab 		lines = 4;
438b285192aSMauro Carvalho Chehab 
439b285192aSMauro Carvalho Chehab 	BUG_ON(lines < 2);
440b285192aSMauro Carvalho Chehab 
441b285192aSMauro Carvalho Chehab 	cx_write(8 + 0, RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
442b285192aSMauro Carvalho Chehab 	cx_write(8 + 4, 8);
443b285192aSMauro Carvalho Chehab 	cx_write(8 + 8, 0);
444b285192aSMauro Carvalho Chehab 
445b285192aSMauro Carvalho Chehab 	/* write CDT */
446b285192aSMauro Carvalho Chehab 	for (i = 0; i < lines; i++) {
447b285192aSMauro Carvalho Chehab 		cx_write(cdt + 16 * i, ch->fifo_start + bpl * i);
448b285192aSMauro Carvalho Chehab 		cx_write(cdt + 16 * i + 4, 0);
449b285192aSMauro Carvalho Chehab 		cx_write(cdt + 16 * i + 8, 0);
450b285192aSMauro Carvalho Chehab 		cx_write(cdt + 16 * i + 12, 0);
451b285192aSMauro Carvalho Chehab 	}
452b285192aSMauro Carvalho Chehab 
453b285192aSMauro Carvalho Chehab 	/* init the first cdt buffer */
454b285192aSMauro Carvalho Chehab 	for (i = 0; i < 128; i++)
455b285192aSMauro Carvalho Chehab 		cx_write(ch->fifo_start + 4 * i, i);
456b285192aSMauro Carvalho Chehab 
457b285192aSMauro Carvalho Chehab 	/* write CMDS */
458b285192aSMauro Carvalho Chehab 	if (ch->jumponly)
459b285192aSMauro Carvalho Chehab 		cx_write(ch->cmds_start + 0, 8);
460b285192aSMauro Carvalho Chehab 	else
461b285192aSMauro Carvalho Chehab 		cx_write(ch->cmds_start + 0, risc);
462b285192aSMauro Carvalho Chehab 
463b285192aSMauro Carvalho Chehab 	cx_write(ch->cmds_start + 4, 0);	/* 64 bits 63-32 */
464b285192aSMauro Carvalho Chehab 	cx_write(ch->cmds_start + 8, cdt);
465b285192aSMauro Carvalho Chehab 	cx_write(ch->cmds_start + 12, (lines * 16) >> 3);
466b285192aSMauro Carvalho Chehab 	cx_write(ch->cmds_start + 16, ch->ctrl_start);
467b285192aSMauro Carvalho Chehab 
468b285192aSMauro Carvalho Chehab 	if (ch->jumponly)
469b285192aSMauro Carvalho Chehab 		cx_write(ch->cmds_start + 20, 0x80000000 | (64 >> 2));
470b285192aSMauro Carvalho Chehab 	else
471b285192aSMauro Carvalho Chehab 		cx_write(ch->cmds_start + 20, 64 >> 2);
472b285192aSMauro Carvalho Chehab 
473b285192aSMauro Carvalho Chehab 	for (i = 24; i < 80; i += 4)
474b285192aSMauro Carvalho Chehab 		cx_write(ch->cmds_start + i, 0);
475b285192aSMauro Carvalho Chehab 
476b285192aSMauro Carvalho Chehab 	/* fill registers */
477b285192aSMauro Carvalho Chehab 	cx_write(ch->ptr1_reg, ch->fifo_start);
478b285192aSMauro Carvalho Chehab 	cx_write(ch->ptr2_reg, cdt);
479b285192aSMauro Carvalho Chehab 	cx_write(ch->cnt2_reg, (lines * 16) >> 3);
480b285192aSMauro Carvalho Chehab 	cx_write(ch->cnt1_reg, (bpl >> 3) - 1);
481b285192aSMauro Carvalho Chehab 
482b285192aSMauro Carvalho Chehab 	return 0;
483b285192aSMauro Carvalho Chehab }
484b285192aSMauro Carvalho Chehab 
cx25821_sram_channel_setup_audio(struct cx25821_dev * dev,const struct sram_channel * ch,unsigned int bpl,u32 risc)485b285192aSMauro Carvalho Chehab int cx25821_sram_channel_setup_audio(struct cx25821_dev *dev,
486bfef0d35SHans Verkuil 				     const struct sram_channel *ch,
487b285192aSMauro Carvalho Chehab 				     unsigned int bpl, u32 risc)
488b285192aSMauro Carvalho Chehab {
489b285192aSMauro Carvalho Chehab 	unsigned int i, lines;
490b285192aSMauro Carvalho Chehab 	u32 cdt;
491b285192aSMauro Carvalho Chehab 
492b285192aSMauro Carvalho Chehab 	if (ch->cmds_start == 0) {
493b285192aSMauro Carvalho Chehab 		cx_write(ch->ptr1_reg, 0);
494b285192aSMauro Carvalho Chehab 		cx_write(ch->ptr2_reg, 0);
495b285192aSMauro Carvalho Chehab 		cx_write(ch->cnt2_reg, 0);
496b285192aSMauro Carvalho Chehab 		cx_write(ch->cnt1_reg, 0);
497b285192aSMauro Carvalho Chehab 		return 0;
498b285192aSMauro Carvalho Chehab 	}
499b285192aSMauro Carvalho Chehab 
500b285192aSMauro Carvalho Chehab 	bpl = (bpl + 7) & ~7;	/* alignment */
501b285192aSMauro Carvalho Chehab 	cdt = ch->cdt;
502b285192aSMauro Carvalho Chehab 	lines = ch->fifo_size / bpl;
503b285192aSMauro Carvalho Chehab 
504b285192aSMauro Carvalho Chehab 	if (lines > 3)
505b285192aSMauro Carvalho Chehab 		lines = 3;	/* for AUDIO */
506b285192aSMauro Carvalho Chehab 
507b285192aSMauro Carvalho Chehab 	BUG_ON(lines < 2);
508b285192aSMauro Carvalho Chehab 
509b285192aSMauro Carvalho Chehab 	cx_write(8 + 0, RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
510b285192aSMauro Carvalho Chehab 	cx_write(8 + 4, 8);
511b285192aSMauro Carvalho Chehab 	cx_write(8 + 8, 0);
512b285192aSMauro Carvalho Chehab 
513b285192aSMauro Carvalho Chehab 	/* write CDT */
514b285192aSMauro Carvalho Chehab 	for (i = 0; i < lines; i++) {
515b285192aSMauro Carvalho Chehab 		cx_write(cdt + 16 * i, ch->fifo_start + bpl * i);
516b285192aSMauro Carvalho Chehab 		cx_write(cdt + 16 * i + 4, 0);
517b285192aSMauro Carvalho Chehab 		cx_write(cdt + 16 * i + 8, 0);
518b285192aSMauro Carvalho Chehab 		cx_write(cdt + 16 * i + 12, 0);
519b285192aSMauro Carvalho Chehab 	}
520b285192aSMauro Carvalho Chehab 
521b285192aSMauro Carvalho Chehab 	/* write CMDS */
522b285192aSMauro Carvalho Chehab 	if (ch->jumponly)
523b285192aSMauro Carvalho Chehab 		cx_write(ch->cmds_start + 0, 8);
524b285192aSMauro Carvalho Chehab 	else
525b285192aSMauro Carvalho Chehab 		cx_write(ch->cmds_start + 0, risc);
526b285192aSMauro Carvalho Chehab 
527b285192aSMauro Carvalho Chehab 	cx_write(ch->cmds_start + 4, 0);	/* 64 bits 63-32 */
528b285192aSMauro Carvalho Chehab 	cx_write(ch->cmds_start + 8, cdt);
529b285192aSMauro Carvalho Chehab 	cx_write(ch->cmds_start + 12, (lines * 16) >> 3);
530b285192aSMauro Carvalho Chehab 	cx_write(ch->cmds_start + 16, ch->ctrl_start);
531b285192aSMauro Carvalho Chehab 
532b285192aSMauro Carvalho Chehab 	/* IQ size */
533b285192aSMauro Carvalho Chehab 	if (ch->jumponly)
534b285192aSMauro Carvalho Chehab 		cx_write(ch->cmds_start + 20, 0x80000000 | (64 >> 2));
535b285192aSMauro Carvalho Chehab 	else
536b285192aSMauro Carvalho Chehab 		cx_write(ch->cmds_start + 20, 64 >> 2);
537b285192aSMauro Carvalho Chehab 
538b285192aSMauro Carvalho Chehab 	/* zero out */
539b285192aSMauro Carvalho Chehab 	for (i = 24; i < 80; i += 4)
540b285192aSMauro Carvalho Chehab 		cx_write(ch->cmds_start + i, 0);
541b285192aSMauro Carvalho Chehab 
542b285192aSMauro Carvalho Chehab 	/* fill registers */
543b285192aSMauro Carvalho Chehab 	cx_write(ch->ptr1_reg, ch->fifo_start);
544b285192aSMauro Carvalho Chehab 	cx_write(ch->ptr2_reg, cdt);
545b285192aSMauro Carvalho Chehab 	cx_write(ch->cnt2_reg, (lines * 16) >> 3);
546b285192aSMauro Carvalho Chehab 	cx_write(ch->cnt1_reg, (bpl >> 3) - 1);
547b285192aSMauro Carvalho Chehab 
548b285192aSMauro Carvalho Chehab 	return 0;
549b285192aSMauro Carvalho Chehab }
550b285192aSMauro Carvalho Chehab EXPORT_SYMBOL(cx25821_sram_channel_setup_audio);
551b285192aSMauro Carvalho Chehab 
cx25821_sram_channel_dump(struct cx25821_dev * dev,const struct sram_channel * ch)552bfef0d35SHans Verkuil void cx25821_sram_channel_dump(struct cx25821_dev *dev, const struct sram_channel *ch)
553b285192aSMauro Carvalho Chehab {
554b285192aSMauro Carvalho Chehab 	static char *name[] = {
555b285192aSMauro Carvalho Chehab 		"init risc lo",
556b285192aSMauro Carvalho Chehab 		"init risc hi",
557b285192aSMauro Carvalho Chehab 		"cdt base",
558b285192aSMauro Carvalho Chehab 		"cdt size",
559b285192aSMauro Carvalho Chehab 		"iq base",
560b285192aSMauro Carvalho Chehab 		"iq size",
561b285192aSMauro Carvalho Chehab 		"risc pc lo",
562b285192aSMauro Carvalho Chehab 		"risc pc hi",
563b285192aSMauro Carvalho Chehab 		"iq wr ptr",
564b285192aSMauro Carvalho Chehab 		"iq rd ptr",
565b285192aSMauro Carvalho Chehab 		"cdt current",
566b285192aSMauro Carvalho Chehab 		"pci target lo",
567b285192aSMauro Carvalho Chehab 		"pci target hi",
568b285192aSMauro Carvalho Chehab 		"line / byte",
569b285192aSMauro Carvalho Chehab 	};
570b285192aSMauro Carvalho Chehab 	u32 risc;
571b285192aSMauro Carvalho Chehab 	unsigned int i, j, n;
572b285192aSMauro Carvalho Chehab 
573b285192aSMauro Carvalho Chehab 	pr_warn("%s: %s - dma channel status dump\n", dev->name, ch->name);
574b285192aSMauro Carvalho Chehab 	for (i = 0; i < ARRAY_SIZE(name); i++)
575b285192aSMauro Carvalho Chehab 		pr_warn("cmds + 0x%2x:   %-15s: 0x%08x\n",
576b285192aSMauro Carvalho Chehab 			i * 4, name[i], cx_read(ch->cmds_start + 4 * i));
577b285192aSMauro Carvalho Chehab 
578b285192aSMauro Carvalho Chehab 	j = i * 4;
579b285192aSMauro Carvalho Chehab 	for (i = 0; i < 4;) {
580b285192aSMauro Carvalho Chehab 		risc = cx_read(ch->cmds_start + 4 * (i + 14));
581b285192aSMauro Carvalho Chehab 		pr_warn("cmds + 0x%2x:   risc%d: ", j + i * 4, i);
582b285192aSMauro Carvalho Chehab 		i += cx25821_risc_decode(risc);
583b285192aSMauro Carvalho Chehab 	}
584b285192aSMauro Carvalho Chehab 
585b285192aSMauro Carvalho Chehab 	for (i = 0; i < (64 >> 2); i += n) {
586b285192aSMauro Carvalho Chehab 		risc = cx_read(ch->ctrl_start + 4 * i);
587b285192aSMauro Carvalho Chehab 		/* No consideration for bits 63-32 */
588b285192aSMauro Carvalho Chehab 
589b285192aSMauro Carvalho Chehab 		pr_warn("ctrl + 0x%2x (0x%08x): iq %x: ",
590b285192aSMauro Carvalho Chehab 			i * 4, ch->ctrl_start + 4 * i, i);
591b285192aSMauro Carvalho Chehab 		n = cx25821_risc_decode(risc);
592b285192aSMauro Carvalho Chehab 		for (j = 1; j < n; j++) {
593b285192aSMauro Carvalho Chehab 			risc = cx_read(ch->ctrl_start + 4 * (i + j));
594b285192aSMauro Carvalho Chehab 			pr_warn("ctrl + 0x%2x :   iq %x: 0x%08x [ arg #%d ]\n",
595b285192aSMauro Carvalho Chehab 				4 * (i + j), i + j, risc, j);
596b285192aSMauro Carvalho Chehab 		}
597b285192aSMauro Carvalho Chehab 	}
598b285192aSMauro Carvalho Chehab 
599b285192aSMauro Carvalho Chehab 	pr_warn("        :   fifo: 0x%08x -> 0x%x\n",
600b285192aSMauro Carvalho Chehab 		ch->fifo_start, ch->fifo_start + ch->fifo_size);
601b285192aSMauro Carvalho Chehab 	pr_warn("        :   ctrl: 0x%08x -> 0x%x\n",
602b285192aSMauro Carvalho Chehab 		ch->ctrl_start, ch->ctrl_start + 6 * 16);
603b285192aSMauro Carvalho Chehab 	pr_warn("        :   ptr1_reg: 0x%08x\n",
604b285192aSMauro Carvalho Chehab 		cx_read(ch->ptr1_reg));
605b285192aSMauro Carvalho Chehab 	pr_warn("        :   ptr2_reg: 0x%08x\n",
606b285192aSMauro Carvalho Chehab 		cx_read(ch->ptr2_reg));
607b285192aSMauro Carvalho Chehab 	pr_warn("        :   cnt1_reg: 0x%08x\n",
608b285192aSMauro Carvalho Chehab 		cx_read(ch->cnt1_reg));
609b285192aSMauro Carvalho Chehab 	pr_warn("        :   cnt2_reg: 0x%08x\n",
610b285192aSMauro Carvalho Chehab 		cx_read(ch->cnt2_reg));
611b285192aSMauro Carvalho Chehab }
612b285192aSMauro Carvalho Chehab 
cx25821_sram_channel_dump_audio(struct cx25821_dev * dev,const struct sram_channel * ch)613b285192aSMauro Carvalho Chehab void cx25821_sram_channel_dump_audio(struct cx25821_dev *dev,
614bfef0d35SHans Verkuil 				     const struct sram_channel *ch)
615b285192aSMauro Carvalho Chehab {
616b285192aSMauro Carvalho Chehab 	static const char * const name[] = {
617b285192aSMauro Carvalho Chehab 		"init risc lo",
618b285192aSMauro Carvalho Chehab 		"init risc hi",
619b285192aSMauro Carvalho Chehab 		"cdt base",
620b285192aSMauro Carvalho Chehab 		"cdt size",
621b285192aSMauro Carvalho Chehab 		"iq base",
622b285192aSMauro Carvalho Chehab 		"iq size",
623b285192aSMauro Carvalho Chehab 		"risc pc lo",
624b285192aSMauro Carvalho Chehab 		"risc pc hi",
625b285192aSMauro Carvalho Chehab 		"iq wr ptr",
626b285192aSMauro Carvalho Chehab 		"iq rd ptr",
627b285192aSMauro Carvalho Chehab 		"cdt current",
628b285192aSMauro Carvalho Chehab 		"pci target lo",
629b285192aSMauro Carvalho Chehab 		"pci target hi",
630b285192aSMauro Carvalho Chehab 		"line / byte",
631b285192aSMauro Carvalho Chehab 	};
632b285192aSMauro Carvalho Chehab 
633b285192aSMauro Carvalho Chehab 	u32 risc, value, tmp;
634b285192aSMauro Carvalho Chehab 	unsigned int i, j, n;
635b285192aSMauro Carvalho Chehab 
636b285192aSMauro Carvalho Chehab 	pr_info("\n%s: %s - dma Audio channel status dump\n",
637b285192aSMauro Carvalho Chehab 		dev->name, ch->name);
638b285192aSMauro Carvalho Chehab 
639b285192aSMauro Carvalho Chehab 	for (i = 0; i < ARRAY_SIZE(name); i++)
640b285192aSMauro Carvalho Chehab 		pr_info("%s: cmds + 0x%2x:   %-15s: 0x%08x\n",
641b285192aSMauro Carvalho Chehab 			dev->name, i * 4, name[i],
642b285192aSMauro Carvalho Chehab 			cx_read(ch->cmds_start + 4 * i));
643b285192aSMauro Carvalho Chehab 
644b285192aSMauro Carvalho Chehab 	j = i * 4;
645b285192aSMauro Carvalho Chehab 	for (i = 0; i < 4;) {
646b285192aSMauro Carvalho Chehab 		risc = cx_read(ch->cmds_start + 4 * (i + 14));
647b285192aSMauro Carvalho Chehab 		pr_warn("cmds + 0x%2x:   risc%d: ", j + i * 4, i);
648b285192aSMauro Carvalho Chehab 		i += cx25821_risc_decode(risc);
649b285192aSMauro Carvalho Chehab 	}
650b285192aSMauro Carvalho Chehab 
651b285192aSMauro Carvalho Chehab 	for (i = 0; i < (64 >> 2); i += n) {
652b285192aSMauro Carvalho Chehab 		risc = cx_read(ch->ctrl_start + 4 * i);
653b285192aSMauro Carvalho Chehab 		/* No consideration for bits 63-32 */
654b285192aSMauro Carvalho Chehab 
655b285192aSMauro Carvalho Chehab 		pr_warn("ctrl + 0x%2x (0x%08x): iq %x: ",
656b285192aSMauro Carvalho Chehab 			i * 4, ch->ctrl_start + 4 * i, i);
657b285192aSMauro Carvalho Chehab 		n = cx25821_risc_decode(risc);
658b285192aSMauro Carvalho Chehab 
659b285192aSMauro Carvalho Chehab 		for (j = 1; j < n; j++) {
660b285192aSMauro Carvalho Chehab 			risc = cx_read(ch->ctrl_start + 4 * (i + j));
661b285192aSMauro Carvalho Chehab 			pr_warn("ctrl + 0x%2x :   iq %x: 0x%08x [ arg #%d ]\n",
662b285192aSMauro Carvalho Chehab 				4 * (i + j), i + j, risc, j);
663b285192aSMauro Carvalho Chehab 		}
664b285192aSMauro Carvalho Chehab 	}
665b285192aSMauro Carvalho Chehab 
666b285192aSMauro Carvalho Chehab 	pr_warn("        :   fifo: 0x%08x -> 0x%x\n",
667b285192aSMauro Carvalho Chehab 		ch->fifo_start, ch->fifo_start + ch->fifo_size);
668b285192aSMauro Carvalho Chehab 	pr_warn("        :   ctrl: 0x%08x -> 0x%x\n",
669b285192aSMauro Carvalho Chehab 		ch->ctrl_start, ch->ctrl_start + 6 * 16);
670b285192aSMauro Carvalho Chehab 	pr_warn("        :   ptr1_reg: 0x%08x\n",
671b285192aSMauro Carvalho Chehab 		cx_read(ch->ptr1_reg));
672b285192aSMauro Carvalho Chehab 	pr_warn("        :   ptr2_reg: 0x%08x\n",
673b285192aSMauro Carvalho Chehab 		cx_read(ch->ptr2_reg));
674b285192aSMauro Carvalho Chehab 	pr_warn("        :   cnt1_reg: 0x%08x\n",
675b285192aSMauro Carvalho Chehab 		cx_read(ch->cnt1_reg));
676b285192aSMauro Carvalho Chehab 	pr_warn("        :   cnt2_reg: 0x%08x\n",
677b285192aSMauro Carvalho Chehab 		cx_read(ch->cnt2_reg));
678b285192aSMauro Carvalho Chehab 
679b285192aSMauro Carvalho Chehab 	for (i = 0; i < 4; i++) {
680b285192aSMauro Carvalho Chehab 		risc = cx_read(ch->cmds_start + 56 + (i * 4));
681b285192aSMauro Carvalho Chehab 		pr_warn("instruction %d = 0x%x\n", i, risc);
682b285192aSMauro Carvalho Chehab 	}
683b285192aSMauro Carvalho Chehab 
684b285192aSMauro Carvalho Chehab 	/* read data from the first cdt buffer */
685b285192aSMauro Carvalho Chehab 	risc = cx_read(AUD_A_CDT);
686b285192aSMauro Carvalho Chehab 	pr_warn("\nread cdt loc=0x%x\n", risc);
687b285192aSMauro Carvalho Chehab 	for (i = 0; i < 8; i++) {
688b285192aSMauro Carvalho Chehab 		n = cx_read(risc + i * 4);
689b285192aSMauro Carvalho Chehab 		pr_cont("0x%x ", n);
690b285192aSMauro Carvalho Chehab 	}
691b285192aSMauro Carvalho Chehab 	pr_cont("\n\n");
692b285192aSMauro Carvalho Chehab 
693b285192aSMauro Carvalho Chehab 	value = cx_read(CLK_RST);
694b285192aSMauro Carvalho Chehab 	CX25821_INFO(" CLK_RST = 0x%x\n\n", value);
695b285192aSMauro Carvalho Chehab 
696b285192aSMauro Carvalho Chehab 	value = cx_read(PLL_A_POST_STAT_BIST);
697b285192aSMauro Carvalho Chehab 	CX25821_INFO(" PLL_A_POST_STAT_BIST = 0x%x\n\n", value);
698b285192aSMauro Carvalho Chehab 	value = cx_read(PLL_A_INT_FRAC);
699b285192aSMauro Carvalho Chehab 	CX25821_INFO(" PLL_A_INT_FRAC = 0x%x\n\n", value);
700b285192aSMauro Carvalho Chehab 
701b285192aSMauro Carvalho Chehab 	value = cx_read(PLL_B_POST_STAT_BIST);
702b285192aSMauro Carvalho Chehab 	CX25821_INFO(" PLL_B_POST_STAT_BIST = 0x%x\n\n", value);
703b285192aSMauro Carvalho Chehab 	value = cx_read(PLL_B_INT_FRAC);
704b285192aSMauro Carvalho Chehab 	CX25821_INFO(" PLL_B_INT_FRAC = 0x%x\n\n", value);
705b285192aSMauro Carvalho Chehab 
706b285192aSMauro Carvalho Chehab 	value = cx_read(PLL_C_POST_STAT_BIST);
707b285192aSMauro Carvalho Chehab 	CX25821_INFO(" PLL_C_POST_STAT_BIST = 0x%x\n\n", value);
708b285192aSMauro Carvalho Chehab 	value = cx_read(PLL_C_INT_FRAC);
709b285192aSMauro Carvalho Chehab 	CX25821_INFO(" PLL_C_INT_FRAC = 0x%x\n\n", value);
710b285192aSMauro Carvalho Chehab 
711b285192aSMauro Carvalho Chehab 	value = cx_read(PLL_D_POST_STAT_BIST);
712b285192aSMauro Carvalho Chehab 	CX25821_INFO(" PLL_D_POST_STAT_BIST = 0x%x\n\n", value);
713b285192aSMauro Carvalho Chehab 	value = cx_read(PLL_D_INT_FRAC);
714b285192aSMauro Carvalho Chehab 	CX25821_INFO(" PLL_D_INT_FRAC = 0x%x\n\n", value);
715b285192aSMauro Carvalho Chehab 
716b285192aSMauro Carvalho Chehab 	value = cx25821_i2c_read(&dev->i2c_bus[0], AFE_AB_DIAG_CTRL, &tmp);
717b285192aSMauro Carvalho Chehab 	CX25821_INFO(" AFE_AB_DIAG_CTRL (0x10900090) = 0x%x\n\n", value);
718b285192aSMauro Carvalho Chehab }
719b285192aSMauro Carvalho Chehab EXPORT_SYMBOL(cx25821_sram_channel_dump_audio);
720b285192aSMauro Carvalho Chehab 
cx25821_shutdown(struct cx25821_dev * dev)721b285192aSMauro Carvalho Chehab static void cx25821_shutdown(struct cx25821_dev *dev)
722b285192aSMauro Carvalho Chehab {
723b285192aSMauro Carvalho Chehab 	int i;
724b285192aSMauro Carvalho Chehab 
725b285192aSMauro Carvalho Chehab 	/* disable RISC controller */
726b285192aSMauro Carvalho Chehab 	cx_write(DEV_CNTRL2, 0);
727b285192aSMauro Carvalho Chehab 
728b285192aSMauro Carvalho Chehab 	/* Disable Video A/B activity */
729b285192aSMauro Carvalho Chehab 	for (i = 0; i < VID_CHANNEL_NUM; i++) {
730b285192aSMauro Carvalho Chehab 		cx_write(dev->channels[i].sram_channels->dma_ctl, 0);
731b285192aSMauro Carvalho Chehab 		cx_write(dev->channels[i].sram_channels->int_msk, 0);
732b285192aSMauro Carvalho Chehab 	}
733b285192aSMauro Carvalho Chehab 
734b285192aSMauro Carvalho Chehab 	for (i = VID_UPSTREAM_SRAM_CHANNEL_I;
735b285192aSMauro Carvalho Chehab 		i <= VID_UPSTREAM_SRAM_CHANNEL_J; i++) {
736b285192aSMauro Carvalho Chehab 		cx_write(dev->channels[i].sram_channels->dma_ctl, 0);
737b285192aSMauro Carvalho Chehab 		cx_write(dev->channels[i].sram_channels->int_msk, 0);
738b285192aSMauro Carvalho Chehab 	}
739b285192aSMauro Carvalho Chehab 
740b285192aSMauro Carvalho Chehab 	/* Disable Audio activity */
741b285192aSMauro Carvalho Chehab 	cx_write(AUD_INT_DMA_CTL, 0);
742b285192aSMauro Carvalho Chehab 
743b285192aSMauro Carvalho Chehab 	/* Disable Serial port */
744b285192aSMauro Carvalho Chehab 	cx_write(UART_CTL, 0);
745b285192aSMauro Carvalho Chehab 
746b285192aSMauro Carvalho Chehab 	/* Disable Interrupts */
747b285192aSMauro Carvalho Chehab 	cx_write(PCI_INT_MSK, 0);
748b285192aSMauro Carvalho Chehab 	cx_write(AUD_A_INT_MSK, 0);
749b285192aSMauro Carvalho Chehab }
750b285192aSMauro Carvalho Chehab 
cx25821_set_pixel_format(struct cx25821_dev * dev,int channel_select,u32 format)751b285192aSMauro Carvalho Chehab void cx25821_set_pixel_format(struct cx25821_dev *dev, int channel_select,
752b285192aSMauro Carvalho Chehab 			      u32 format)
753b285192aSMauro Carvalho Chehab {
754b285192aSMauro Carvalho Chehab 	if (channel_select <= 7 && channel_select >= 0) {
755b285192aSMauro Carvalho Chehab 		cx_write(dev->channels[channel_select].sram_channels->pix_frmt,
756b285192aSMauro Carvalho Chehab 				format);
757b285192aSMauro Carvalho Chehab 	}
758ea3f7ac6SHans Verkuil 	dev->channels[channel_select].pixel_formats = format;
759b285192aSMauro Carvalho Chehab }
760b285192aSMauro Carvalho Chehab 
cx25821_set_vip_mode(struct cx25821_dev * dev,const struct sram_channel * ch)761b285192aSMauro Carvalho Chehab static void cx25821_set_vip_mode(struct cx25821_dev *dev,
762bfef0d35SHans Verkuil 				 const struct sram_channel *ch)
763b285192aSMauro Carvalho Chehab {
764b285192aSMauro Carvalho Chehab 	cx_write(ch->pix_frmt, PIXEL_FRMT_422);
765b285192aSMauro Carvalho Chehab 	cx_write(ch->vip_ctl, PIXEL_ENGINE_VIP1);
766b285192aSMauro Carvalho Chehab }
767b285192aSMauro Carvalho Chehab 
cx25821_initialize(struct cx25821_dev * dev)768b285192aSMauro Carvalho Chehab static void cx25821_initialize(struct cx25821_dev *dev)
769b285192aSMauro Carvalho Chehab {
770b285192aSMauro Carvalho Chehab 	int i;
771b285192aSMauro Carvalho Chehab 
772b285192aSMauro Carvalho Chehab 	dprintk(1, "%s()\n", __func__);
773b285192aSMauro Carvalho Chehab 
774b285192aSMauro Carvalho Chehab 	cx25821_shutdown(dev);
775b285192aSMauro Carvalho Chehab 	cx_write(PCI_INT_STAT, 0xffffffff);
776b285192aSMauro Carvalho Chehab 
777b285192aSMauro Carvalho Chehab 	for (i = 0; i < VID_CHANNEL_NUM; i++)
778b285192aSMauro Carvalho Chehab 		cx_write(dev->channels[i].sram_channels->int_stat, 0xffffffff);
779b285192aSMauro Carvalho Chehab 
780b285192aSMauro Carvalho Chehab 	cx_write(AUD_A_INT_STAT, 0xffffffff);
781b285192aSMauro Carvalho Chehab 	cx_write(AUD_B_INT_STAT, 0xffffffff);
782b285192aSMauro Carvalho Chehab 	cx_write(AUD_C_INT_STAT, 0xffffffff);
783b285192aSMauro Carvalho Chehab 	cx_write(AUD_D_INT_STAT, 0xffffffff);
784b285192aSMauro Carvalho Chehab 	cx_write(AUD_E_INT_STAT, 0xffffffff);
785b285192aSMauro Carvalho Chehab 
786b285192aSMauro Carvalho Chehab 	cx_write(CLK_DELAY, cx_read(CLK_DELAY) & 0x80000000);
787b285192aSMauro Carvalho Chehab 	cx_write(PAD_CTRL, 0x12);	/* for I2C */
788b285192aSMauro Carvalho Chehab 	cx25821_registers_init(dev);	/* init Pecos registers */
78965155a9bSJia-Ju Bai 	msleep(100);
790b285192aSMauro Carvalho Chehab 
791b285192aSMauro Carvalho Chehab 	for (i = 0; i < VID_CHANNEL_NUM; i++) {
792b285192aSMauro Carvalho Chehab 		cx25821_set_vip_mode(dev, dev->channels[i].sram_channels);
793b285192aSMauro Carvalho Chehab 		cx25821_sram_channel_setup(dev, dev->channels[i].sram_channels,
794b285192aSMauro Carvalho Chehab 						1440, 0);
795b285192aSMauro Carvalho Chehab 		dev->channels[i].pixel_formats = PIXEL_FRMT_422;
796bad1f29dSHans Verkuil 		dev->channels[i].use_cif_resolution = 0;
797b285192aSMauro Carvalho Chehab 	}
798b285192aSMauro Carvalho Chehab 
799b285192aSMauro Carvalho Chehab 	/* Probably only affect Downstream */
800b285192aSMauro Carvalho Chehab 	for (i = VID_UPSTREAM_SRAM_CHANNEL_I;
801b285192aSMauro Carvalho Chehab 		i <= VID_UPSTREAM_SRAM_CHANNEL_J; i++) {
802ea3f7ac6SHans Verkuil 		dev->channels[i].pixel_formats = PIXEL_FRMT_422;
803b285192aSMauro Carvalho Chehab 		cx25821_set_vip_mode(dev, dev->channels[i].sram_channels);
804b285192aSMauro Carvalho Chehab 	}
805b285192aSMauro Carvalho Chehab 
806b285192aSMauro Carvalho Chehab 	cx25821_sram_channel_setup_audio(dev,
807b285192aSMauro Carvalho Chehab 			dev->channels[SRAM_CH08].sram_channels, 128, 0);
808b285192aSMauro Carvalho Chehab 
809b285192aSMauro Carvalho Chehab 	cx25821_gpio_init(dev);
810b285192aSMauro Carvalho Chehab }
811b285192aSMauro Carvalho Chehab 
cx25821_get_resources(struct cx25821_dev * dev)812b285192aSMauro Carvalho Chehab static int cx25821_get_resources(struct cx25821_dev *dev)
813b285192aSMauro Carvalho Chehab {
814b285192aSMauro Carvalho Chehab 	if (request_mem_region(pci_resource_start(dev->pci, 0),
815b285192aSMauro Carvalho Chehab 				pci_resource_len(dev->pci, 0), dev->name))
816b285192aSMauro Carvalho Chehab 		return 0;
817b285192aSMauro Carvalho Chehab 
818b285192aSMauro Carvalho Chehab 	pr_err("%s: can't get MMIO memory @ 0x%llx\n",
819b285192aSMauro Carvalho Chehab 		dev->name, (unsigned long long)pci_resource_start(dev->pci, 0));
820b285192aSMauro Carvalho Chehab 
821b285192aSMauro Carvalho Chehab 	return -EBUSY;
822b285192aSMauro Carvalho Chehab }
823b285192aSMauro Carvalho Chehab 
cx25821_dev_checkrevision(struct cx25821_dev * dev)824b285192aSMauro Carvalho Chehab static void cx25821_dev_checkrevision(struct cx25821_dev *dev)
825b285192aSMauro Carvalho Chehab {
826b285192aSMauro Carvalho Chehab 	dev->hwrevision = cx_read(RDR_CFG2) & 0xff;
827b285192aSMauro Carvalho Chehab 
828467870caSHans Verkuil 	pr_info("Hardware revision = 0x%02x\n", dev->hwrevision);
829b285192aSMauro Carvalho Chehab }
830b285192aSMauro Carvalho Chehab 
cx25821_iounmap(struct cx25821_dev * dev)831b285192aSMauro Carvalho Chehab static void cx25821_iounmap(struct cx25821_dev *dev)
832b285192aSMauro Carvalho Chehab {
833b285192aSMauro Carvalho Chehab 	if (dev == NULL)
834b285192aSMauro Carvalho Chehab 		return;
835b285192aSMauro Carvalho Chehab 
836b285192aSMauro Carvalho Chehab 	/* Releasing IO memory */
837b285192aSMauro Carvalho Chehab 	if (dev->lmmio != NULL) {
838b285192aSMauro Carvalho Chehab 		iounmap(dev->lmmio);
839b285192aSMauro Carvalho Chehab 		dev->lmmio = NULL;
840b285192aSMauro Carvalho Chehab 	}
841b285192aSMauro Carvalho Chehab }
842b285192aSMauro Carvalho Chehab 
cx25821_dev_setup(struct cx25821_dev * dev)843b285192aSMauro Carvalho Chehab static int cx25821_dev_setup(struct cx25821_dev *dev)
844b285192aSMauro Carvalho Chehab {
845a8f35ce3SHans Verkuil 	static unsigned int cx25821_devcount;
846b285192aSMauro Carvalho Chehab 	int i;
847b285192aSMauro Carvalho Chehab 
848b285192aSMauro Carvalho Chehab 	mutex_init(&dev->lock);
849b285192aSMauro Carvalho Chehab 
850b285192aSMauro Carvalho Chehab 	dev->nr = ++cx25821_devcount;
851b285192aSMauro Carvalho Chehab 	sprintf(dev->name, "cx25821[%d]", dev->nr);
852b285192aSMauro Carvalho Chehab 
85367300abdSColin Ian King 	if (dev->nr >= ARRAY_SIZE(card)) {
85467300abdSColin Ian King 		CX25821_INFO("dev->nr >= %zd", ARRAY_SIZE(card));
85567300abdSColin Ian King 		return -ENODEV;
85667300abdSColin Ian King 	}
857b285192aSMauro Carvalho Chehab 	if (dev->pci->device != 0x8210) {
858b285192aSMauro Carvalho Chehab 		pr_info("%s(): Exiting. Incorrect Hardware device = 0x%02x\n",
859b285192aSMauro Carvalho Chehab 			__func__, dev->pci->device);
860b671ae6bSHans Verkuil 		return -ENODEV;
861b285192aSMauro Carvalho Chehab 	}
862b671ae6bSHans Verkuil 	pr_info("Athena Hardware device = 0x%02x\n", dev->pci->device);
863b285192aSMauro Carvalho Chehab 
864b285192aSMauro Carvalho Chehab 	/* Apply a sensible clock frequency for the PCIe bridge */
865b285192aSMauro Carvalho Chehab 	dev->clk_freq = 28000000;
866f8d7ee70SHans Verkuil 	for (i = 0; i < MAX_VID_CHANNEL_NUM; i++) {
867f8d7ee70SHans Verkuil 		dev->channels[i].dev = dev;
868f8d7ee70SHans Verkuil 		dev->channels[i].id = i;
869b285192aSMauro Carvalho Chehab 		dev->channels[i].sram_channels = &cx25821_sram_channels[i];
870f8d7ee70SHans Verkuil 	}
871b285192aSMauro Carvalho Chehab 
872b285192aSMauro Carvalho Chehab 	/* board config */
873b285192aSMauro Carvalho Chehab 	dev->board = 1;		/* card[dev->nr]; */
874b285192aSMauro Carvalho Chehab 	dev->_max_num_decoders = MAX_DECODERS;
875b285192aSMauro Carvalho Chehab 
876b285192aSMauro Carvalho Chehab 	dev->pci_bus = dev->pci->bus->number;
877b285192aSMauro Carvalho Chehab 	dev->pci_slot = PCI_SLOT(dev->pci->devfn);
878b285192aSMauro Carvalho Chehab 	dev->pci_irqmask = 0x001f00;
879b285192aSMauro Carvalho Chehab 
880b285192aSMauro Carvalho Chehab 	/* External Master 1 Bus */
881b285192aSMauro Carvalho Chehab 	dev->i2c_bus[0].nr = 0;
882b285192aSMauro Carvalho Chehab 	dev->i2c_bus[0].dev = dev;
883b285192aSMauro Carvalho Chehab 	dev->i2c_bus[0].reg_stat = I2C1_STAT;
884b285192aSMauro Carvalho Chehab 	dev->i2c_bus[0].reg_ctrl = I2C1_CTRL;
885b285192aSMauro Carvalho Chehab 	dev->i2c_bus[0].reg_addr = I2C1_ADDR;
886b285192aSMauro Carvalho Chehab 	dev->i2c_bus[0].reg_rdata = I2C1_RDATA;
887b285192aSMauro Carvalho Chehab 	dev->i2c_bus[0].reg_wdata = I2C1_WDATA;
888b285192aSMauro Carvalho Chehab 	dev->i2c_bus[0].i2c_period = (0x07 << 24);	/* 1.95MHz */
889b285192aSMauro Carvalho Chehab 
890b285192aSMauro Carvalho Chehab 	if (cx25821_get_resources(dev) < 0) {
891b285192aSMauro Carvalho Chehab 		pr_err("%s: No more PCIe resources for subsystem: %04x:%04x\n",
892b285192aSMauro Carvalho Chehab 		       dev->name, dev->pci->subsystem_vendor,
893b285192aSMauro Carvalho Chehab 		       dev->pci->subsystem_device);
894b285192aSMauro Carvalho Chehab 
895b285192aSMauro Carvalho Chehab 		cx25821_devcount--;
896b285192aSMauro Carvalho Chehab 		return -EBUSY;
897b285192aSMauro Carvalho Chehab 	}
898b285192aSMauro Carvalho Chehab 
899b285192aSMauro Carvalho Chehab 	/* PCIe stuff */
900b285192aSMauro Carvalho Chehab 	dev->base_io_addr = pci_resource_start(dev->pci, 0);
901b285192aSMauro Carvalho Chehab 
902b285192aSMauro Carvalho Chehab 	if (!dev->base_io_addr) {
903b285192aSMauro Carvalho Chehab 		CX25821_ERR("No PCI Memory resources, exiting!\n");
904b285192aSMauro Carvalho Chehab 		return -ENODEV;
905b285192aSMauro Carvalho Chehab 	}
906b285192aSMauro Carvalho Chehab 
907b285192aSMauro Carvalho Chehab 	dev->lmmio = ioremap(dev->base_io_addr, pci_resource_len(dev->pci, 0));
908b285192aSMauro Carvalho Chehab 
909b285192aSMauro Carvalho Chehab 	if (!dev->lmmio) {
910b285192aSMauro Carvalho Chehab 		CX25821_ERR("ioremap failed, maybe increasing __VMALLOC_RESERVE in page.h\n");
911b285192aSMauro Carvalho Chehab 		cx25821_iounmap(dev);
912b285192aSMauro Carvalho Chehab 		return -ENOMEM;
913b285192aSMauro Carvalho Chehab 	}
914b285192aSMauro Carvalho Chehab 
915b285192aSMauro Carvalho Chehab 	dev->bmmio = (u8 __iomem *) dev->lmmio;
916b285192aSMauro Carvalho Chehab 
917b285192aSMauro Carvalho Chehab 	pr_info("%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
918b285192aSMauro Carvalho Chehab 		dev->name, dev->pci->subsystem_vendor,
919b285192aSMauro Carvalho Chehab 		dev->pci->subsystem_device, cx25821_boards[dev->board].name,
920b285192aSMauro Carvalho Chehab 		dev->board, card[dev->nr] == dev->board ?
921b285192aSMauro Carvalho Chehab 		"insmod option" : "autodetected");
922b285192aSMauro Carvalho Chehab 
923b285192aSMauro Carvalho Chehab 	/* init hardware */
924b285192aSMauro Carvalho Chehab 	cx25821_initialize(dev);
925b285192aSMauro Carvalho Chehab 
926b285192aSMauro Carvalho Chehab 	cx25821_i2c_register(&dev->i2c_bus[0]);
927b285192aSMauro Carvalho Chehab /*  cx25821_i2c_register(&dev->i2c_bus[1]);
928b285192aSMauro Carvalho Chehab  *  cx25821_i2c_register(&dev->i2c_bus[2]); */
929b285192aSMauro Carvalho Chehab 
930b285192aSMauro Carvalho Chehab 	if (medusa_video_init(dev) < 0)
931b285192aSMauro Carvalho Chehab 		CX25821_ERR("%s(): Failed to initialize medusa!\n", __func__);
932b285192aSMauro Carvalho Chehab 
933b285192aSMauro Carvalho Chehab 	cx25821_video_register(dev);
934b285192aSMauro Carvalho Chehab 
935b285192aSMauro Carvalho Chehab 	cx25821_dev_checkrevision(dev);
936b285192aSMauro Carvalho Chehab 	return 0;
937b285192aSMauro Carvalho Chehab }
938b285192aSMauro Carvalho Chehab 
cx25821_dev_unregister(struct cx25821_dev * dev)939b285192aSMauro Carvalho Chehab void cx25821_dev_unregister(struct cx25821_dev *dev)
940b285192aSMauro Carvalho Chehab {
941b285192aSMauro Carvalho Chehab 	int i;
942b285192aSMauro Carvalho Chehab 
943b285192aSMauro Carvalho Chehab 	if (!dev->base_io_addr)
944b285192aSMauro Carvalho Chehab 		return;
945b285192aSMauro Carvalho Chehab 
946b285192aSMauro Carvalho Chehab 	release_mem_region(dev->base_io_addr, pci_resource_len(dev->pci, 0));
947b285192aSMauro Carvalho Chehab 
948b6f21dc3SHans Verkuil 	for (i = 0; i < MAX_VID_CAP_CHANNEL_NUM - 1; i++) {
94931b32073SHans Verkuil 		if (i == SRAM_CH08) /* audio channel */
95031b32073SHans Verkuil 			continue;
951b6f21dc3SHans Verkuil 		/*
952b6f21dc3SHans Verkuil 		 * TODO: enable when video output is properly
953b6f21dc3SHans Verkuil 		 * supported.
9547087d31bSHans Verkuil 		if (i == SRAM_CH09 || i == SRAM_CH10)
9557087d31bSHans Verkuil 			cx25821_free_mem_upstream(&dev->channels[i]);
956b6f21dc3SHans Verkuil 		 */
957b285192aSMauro Carvalho Chehab 		cx25821_video_unregister(dev, i);
958b285192aSMauro Carvalho Chehab 	}
959b285192aSMauro Carvalho Chehab 
960b285192aSMauro Carvalho Chehab 	cx25821_i2c_unregister(&dev->i2c_bus[0]);
961b285192aSMauro Carvalho Chehab 	cx25821_iounmap(dev);
962b285192aSMauro Carvalho Chehab }
963b285192aSMauro Carvalho Chehab EXPORT_SYMBOL(cx25821_dev_unregister);
964b285192aSMauro Carvalho Chehab 
cx25821_riscmem_alloc(struct pci_dev * pci,struct cx25821_riscmem * risc,unsigned int size)9655ede94c7SHans Verkuil int cx25821_riscmem_alloc(struct pci_dev *pci,
9665ede94c7SHans Verkuil 		       struct cx25821_riscmem *risc,
9675ede94c7SHans Verkuil 		       unsigned int size)
9685ede94c7SHans Verkuil {
9695ede94c7SHans Verkuil 	__le32 *cpu;
9705ede94c7SHans Verkuil 	dma_addr_t dma = 0;
9715ede94c7SHans Verkuil 
972b2de3643SChristophe JAILLET 	if (risc->cpu && risc->size < size) {
973bb5d4180SChristophe JAILLET 		dma_free_coherent(&pci->dev, risc->size, risc->cpu, risc->dma);
974b2de3643SChristophe JAILLET 		risc->cpu = NULL;
975b2de3643SChristophe JAILLET 	}
9765ede94c7SHans Verkuil 	if (NULL == risc->cpu) {
977bb5d4180SChristophe JAILLET 		cpu = dma_alloc_coherent(&pci->dev, size, &dma, GFP_KERNEL);
9785ede94c7SHans Verkuil 		if (NULL == cpu)
9795ede94c7SHans Verkuil 			return -ENOMEM;
9805ede94c7SHans Verkuil 		risc->cpu  = cpu;
9815ede94c7SHans Verkuil 		risc->dma  = dma;
9825ede94c7SHans Verkuil 		risc->size = size;
9835ede94c7SHans Verkuil 	}
9845ede94c7SHans Verkuil 	return 0;
9855ede94c7SHans Verkuil }
9865ede94c7SHans Verkuil EXPORT_SYMBOL(cx25821_riscmem_alloc);
9875ede94c7SHans Verkuil 
cx25821_risc_field(__le32 * rp,struct scatterlist * sglist,unsigned int offset,u32 sync_line,unsigned int bpl,unsigned int padding,unsigned int lines,bool jump)988b285192aSMauro Carvalho Chehab static __le32 *cx25821_risc_field(__le32 * rp, struct scatterlist *sglist,
989b285192aSMauro Carvalho Chehab 				  unsigned int offset, u32 sync_line,
990b285192aSMauro Carvalho Chehab 				  unsigned int bpl, unsigned int padding,
991b671ae6bSHans Verkuil 				  unsigned int lines, bool jump)
992b285192aSMauro Carvalho Chehab {
993b285192aSMauro Carvalho Chehab 	struct scatterlist *sg;
994b285192aSMauro Carvalho Chehab 	unsigned int line, todo;
995b285192aSMauro Carvalho Chehab 
996b671ae6bSHans Verkuil 	if (jump) {
997b671ae6bSHans Verkuil 		*(rp++) = cpu_to_le32(RISC_JUMP);
998b671ae6bSHans Verkuil 		*(rp++) = cpu_to_le32(0);
999b671ae6bSHans Verkuil 		*(rp++) = cpu_to_le32(0); /* bits 63-32 */
1000b671ae6bSHans Verkuil 	}
1001b671ae6bSHans Verkuil 
1002b285192aSMauro Carvalho Chehab 	/* sync instruction */
1003b285192aSMauro Carvalho Chehab 	if (sync_line != NO_SYNC_LINE)
1004b285192aSMauro Carvalho Chehab 		*(rp++) = cpu_to_le32(RISC_RESYNC | sync_line);
1005b285192aSMauro Carvalho Chehab 
1006b285192aSMauro Carvalho Chehab 	/* scan lines */
1007b285192aSMauro Carvalho Chehab 	sg = sglist;
1008b285192aSMauro Carvalho Chehab 	for (line = 0; line < lines; line++) {
1009b285192aSMauro Carvalho Chehab 		while (offset && offset >= sg_dma_len(sg)) {
1010b285192aSMauro Carvalho Chehab 			offset -= sg_dma_len(sg);
1011872dfcfeSHans Verkuil 			sg = sg_next(sg);
1012b285192aSMauro Carvalho Chehab 		}
1013b285192aSMauro Carvalho Chehab 		if (bpl <= sg_dma_len(sg) - offset) {
1014b285192aSMauro Carvalho Chehab 			/* fits into current chunk */
1015b285192aSMauro Carvalho Chehab 			*(rp++) = cpu_to_le32(RISC_WRITE | RISC_SOL | RISC_EOL |
1016b285192aSMauro Carvalho Chehab 					bpl);
1017b285192aSMauro Carvalho Chehab 			*(rp++) = cpu_to_le32(sg_dma_address(sg) + offset);
1018b285192aSMauro Carvalho Chehab 			*(rp++) = cpu_to_le32(0);	/* bits 63-32 */
1019b285192aSMauro Carvalho Chehab 			offset += bpl;
1020b285192aSMauro Carvalho Chehab 		} else {
1021b285192aSMauro Carvalho Chehab 			/* scanline needs to be split */
1022b285192aSMauro Carvalho Chehab 			todo = bpl;
1023b285192aSMauro Carvalho Chehab 			*(rp++) = cpu_to_le32(RISC_WRITE | RISC_SOL |
1024b285192aSMauro Carvalho Chehab 					(sg_dma_len(sg) - offset));
1025b285192aSMauro Carvalho Chehab 			*(rp++) = cpu_to_le32(sg_dma_address(sg) + offset);
1026b285192aSMauro Carvalho Chehab 			*(rp++) = cpu_to_le32(0);	/* bits 63-32 */
1027b285192aSMauro Carvalho Chehab 			todo -= (sg_dma_len(sg) - offset);
1028b285192aSMauro Carvalho Chehab 			offset = 0;
1029872dfcfeSHans Verkuil 			sg = sg_next(sg);
1030b285192aSMauro Carvalho Chehab 			while (todo > sg_dma_len(sg)) {
1031b285192aSMauro Carvalho Chehab 				*(rp++) = cpu_to_le32(RISC_WRITE |
1032b285192aSMauro Carvalho Chehab 						sg_dma_len(sg));
1033b285192aSMauro Carvalho Chehab 				*(rp++) = cpu_to_le32(sg_dma_address(sg));
1034b285192aSMauro Carvalho Chehab 				*(rp++) = cpu_to_le32(0);	/* bits 63-32 */
1035b285192aSMauro Carvalho Chehab 				todo -= sg_dma_len(sg);
1036872dfcfeSHans Verkuil 				sg = sg_next(sg);
1037b285192aSMauro Carvalho Chehab 			}
1038b285192aSMauro Carvalho Chehab 			*(rp++) = cpu_to_le32(RISC_WRITE | RISC_EOL | todo);
1039b285192aSMauro Carvalho Chehab 			*(rp++) = cpu_to_le32(sg_dma_address(sg));
1040b285192aSMauro Carvalho Chehab 			*(rp++) = cpu_to_le32(0);	/* bits 63-32 */
1041b285192aSMauro Carvalho Chehab 			offset += todo;
1042b285192aSMauro Carvalho Chehab 		}
1043b285192aSMauro Carvalho Chehab 
1044b285192aSMauro Carvalho Chehab 		offset += padding;
1045b285192aSMauro Carvalho Chehab 	}
1046b285192aSMauro Carvalho Chehab 
1047b285192aSMauro Carvalho Chehab 	return rp;
1048b285192aSMauro Carvalho Chehab }
1049b285192aSMauro Carvalho Chehab 
cx25821_risc_buffer(struct pci_dev * pci,struct cx25821_riscmem * risc,struct scatterlist * sglist,unsigned int top_offset,unsigned int bottom_offset,unsigned int bpl,unsigned int padding,unsigned int lines)10505ede94c7SHans Verkuil int cx25821_risc_buffer(struct pci_dev *pci, struct cx25821_riscmem *risc,
1051b285192aSMauro Carvalho Chehab 			struct scatterlist *sglist, unsigned int top_offset,
1052b285192aSMauro Carvalho Chehab 			unsigned int bottom_offset, unsigned int bpl,
1053b285192aSMauro Carvalho Chehab 			unsigned int padding, unsigned int lines)
1054b285192aSMauro Carvalho Chehab {
1055b285192aSMauro Carvalho Chehab 	u32 instructions;
1056b285192aSMauro Carvalho Chehab 	u32 fields;
1057b285192aSMauro Carvalho Chehab 	__le32 *rp;
1058b285192aSMauro Carvalho Chehab 	int rc;
1059b285192aSMauro Carvalho Chehab 
1060b285192aSMauro Carvalho Chehab 	fields = 0;
1061b285192aSMauro Carvalho Chehab 	if (UNSET != top_offset)
1062b285192aSMauro Carvalho Chehab 		fields++;
1063b285192aSMauro Carvalho Chehab 	if (UNSET != bottom_offset)
1064b285192aSMauro Carvalho Chehab 		fields++;
1065b285192aSMauro Carvalho Chehab 
1066b285192aSMauro Carvalho Chehab 	/* estimate risc mem: worst case is one write per page border +
1067b671ae6bSHans Verkuil 	   one write per scan line + syncs + jump (all 3 dwords).  Padding
1068b285192aSMauro Carvalho Chehab 	   can cause next bpl to start close to a page border.  First DMA
1069b285192aSMauro Carvalho Chehab 	   region may be smaller than PAGE_SIZE */
1070b285192aSMauro Carvalho Chehab 	/* write and jump need and extra dword */
1071b285192aSMauro Carvalho Chehab 	instructions = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE +
1072b285192aSMauro Carvalho Chehab 			lines);
1073b671ae6bSHans Verkuil 	instructions += 5;
10745ede94c7SHans Verkuil 	rc = cx25821_riscmem_alloc(pci, risc, instructions * 12);
1075b285192aSMauro Carvalho Chehab 
1076b285192aSMauro Carvalho Chehab 	if (rc < 0)
1077b285192aSMauro Carvalho Chehab 		return rc;
1078b285192aSMauro Carvalho Chehab 
1079b285192aSMauro Carvalho Chehab 	/* write risc instructions */
1080b285192aSMauro Carvalho Chehab 	rp = risc->cpu;
1081b285192aSMauro Carvalho Chehab 
1082b285192aSMauro Carvalho Chehab 	if (UNSET != top_offset) {
1083b285192aSMauro Carvalho Chehab 		rp = cx25821_risc_field(rp, sglist, top_offset, 0, bpl, padding,
1084b671ae6bSHans Verkuil 					lines, true);
1085b285192aSMauro Carvalho Chehab 	}
1086b285192aSMauro Carvalho Chehab 
1087b285192aSMauro Carvalho Chehab 	if (UNSET != bottom_offset) {
1088b285192aSMauro Carvalho Chehab 		rp = cx25821_risc_field(rp, sglist, bottom_offset, 0x200, bpl,
1089b671ae6bSHans Verkuil 					padding, lines, UNSET == top_offset);
1090b285192aSMauro Carvalho Chehab 	}
1091b285192aSMauro Carvalho Chehab 
1092b285192aSMauro Carvalho Chehab 	/* save pointer to jmp instruction address */
1093b285192aSMauro Carvalho Chehab 	risc->jmp = rp;
1094b671ae6bSHans Verkuil 	BUG_ON((risc->jmp - risc->cpu + 3) * sizeof(*risc->cpu) > risc->size);
1095b285192aSMauro Carvalho Chehab 
1096b285192aSMauro Carvalho Chehab 	return 0;
1097b285192aSMauro Carvalho Chehab }
1098b285192aSMauro Carvalho Chehab 
cx25821_risc_field_audio(__le32 * rp,struct scatterlist * sglist,unsigned int offset,u32 sync_line,unsigned int bpl,unsigned int padding,unsigned int lines,unsigned int lpi)1099b285192aSMauro Carvalho Chehab static __le32 *cx25821_risc_field_audio(__le32 * rp, struct scatterlist *sglist,
1100b285192aSMauro Carvalho Chehab 					unsigned int offset, u32 sync_line,
1101b285192aSMauro Carvalho Chehab 					unsigned int bpl, unsigned int padding,
1102b285192aSMauro Carvalho Chehab 					unsigned int lines, unsigned int lpi)
1103b285192aSMauro Carvalho Chehab {
1104b285192aSMauro Carvalho Chehab 	struct scatterlist *sg;
1105b285192aSMauro Carvalho Chehab 	unsigned int line, todo, sol;
1106b285192aSMauro Carvalho Chehab 
1107b285192aSMauro Carvalho Chehab 	/* sync instruction */
1108b285192aSMauro Carvalho Chehab 	if (sync_line != NO_SYNC_LINE)
1109b285192aSMauro Carvalho Chehab 		*(rp++) = cpu_to_le32(RISC_RESYNC | sync_line);
1110b285192aSMauro Carvalho Chehab 
1111b285192aSMauro Carvalho Chehab 	/* scan lines */
1112b285192aSMauro Carvalho Chehab 	sg = sglist;
1113b285192aSMauro Carvalho Chehab 	for (line = 0; line < lines; line++) {
1114b285192aSMauro Carvalho Chehab 		while (offset && offset >= sg_dma_len(sg)) {
1115b285192aSMauro Carvalho Chehab 			offset -= sg_dma_len(sg);
1116872dfcfeSHans Verkuil 			sg = sg_next(sg);
1117b285192aSMauro Carvalho Chehab 		}
1118b285192aSMauro Carvalho Chehab 
1119b285192aSMauro Carvalho Chehab 		if (lpi && line > 0 && !(line % lpi))
1120b285192aSMauro Carvalho Chehab 			sol = RISC_SOL | RISC_IRQ1 | RISC_CNT_INC;
1121b285192aSMauro Carvalho Chehab 		else
1122b285192aSMauro Carvalho Chehab 			sol = RISC_SOL;
1123b285192aSMauro Carvalho Chehab 
1124b285192aSMauro Carvalho Chehab 		if (bpl <= sg_dma_len(sg) - offset) {
1125b285192aSMauro Carvalho Chehab 			/* fits into current chunk */
1126b285192aSMauro Carvalho Chehab 			*(rp++) = cpu_to_le32(RISC_WRITE | sol | RISC_EOL |
1127b285192aSMauro Carvalho Chehab 					bpl);
1128b285192aSMauro Carvalho Chehab 			*(rp++) = cpu_to_le32(sg_dma_address(sg) + offset);
1129b285192aSMauro Carvalho Chehab 			*(rp++) = cpu_to_le32(0);	/* bits 63-32 */
1130b285192aSMauro Carvalho Chehab 			offset += bpl;
1131b285192aSMauro Carvalho Chehab 		} else {
1132b285192aSMauro Carvalho Chehab 			/* scanline needs to be split */
1133b285192aSMauro Carvalho Chehab 			todo = bpl;
1134b285192aSMauro Carvalho Chehab 			*(rp++) = cpu_to_le32(RISC_WRITE | sol |
1135b285192aSMauro Carvalho Chehab 					(sg_dma_len(sg) - offset));
1136b285192aSMauro Carvalho Chehab 			*(rp++) = cpu_to_le32(sg_dma_address(sg) + offset);
1137b285192aSMauro Carvalho Chehab 			*(rp++) = cpu_to_le32(0);	/* bits 63-32 */
1138b285192aSMauro Carvalho Chehab 			todo -= (sg_dma_len(sg) - offset);
1139b285192aSMauro Carvalho Chehab 			offset = 0;
1140872dfcfeSHans Verkuil 			sg = sg_next(sg);
1141b285192aSMauro Carvalho Chehab 			while (todo > sg_dma_len(sg)) {
1142b285192aSMauro Carvalho Chehab 				*(rp++) = cpu_to_le32(RISC_WRITE |
1143b285192aSMauro Carvalho Chehab 						sg_dma_len(sg));
1144b285192aSMauro Carvalho Chehab 				*(rp++) = cpu_to_le32(sg_dma_address(sg));
1145b285192aSMauro Carvalho Chehab 				*(rp++) = cpu_to_le32(0);	/* bits 63-32 */
1146b285192aSMauro Carvalho Chehab 				todo -= sg_dma_len(sg);
1147872dfcfeSHans Verkuil 				sg = sg_next(sg);
1148b285192aSMauro Carvalho Chehab 			}
1149b285192aSMauro Carvalho Chehab 			*(rp++) = cpu_to_le32(RISC_WRITE | RISC_EOL | todo);
1150b285192aSMauro Carvalho Chehab 			*(rp++) = cpu_to_le32(sg_dma_address(sg));
1151b285192aSMauro Carvalho Chehab 			*(rp++) = cpu_to_le32(0);	/* bits 63-32 */
1152b285192aSMauro Carvalho Chehab 			offset += todo;
1153b285192aSMauro Carvalho Chehab 		}
1154b285192aSMauro Carvalho Chehab 		offset += padding;
1155b285192aSMauro Carvalho Chehab 	}
1156b285192aSMauro Carvalho Chehab 
1157b285192aSMauro Carvalho Chehab 	return rp;
1158b285192aSMauro Carvalho Chehab }
1159b285192aSMauro Carvalho Chehab 
cx25821_risc_databuffer_audio(struct pci_dev * pci,struct cx25821_riscmem * risc,struct scatterlist * sglist,unsigned int bpl,unsigned int lines,unsigned int lpi)1160b285192aSMauro Carvalho Chehab int cx25821_risc_databuffer_audio(struct pci_dev *pci,
11615ede94c7SHans Verkuil 				  struct cx25821_riscmem *risc,
1162b285192aSMauro Carvalho Chehab 				  struct scatterlist *sglist,
1163b285192aSMauro Carvalho Chehab 				  unsigned int bpl,
1164b285192aSMauro Carvalho Chehab 				  unsigned int lines, unsigned int lpi)
1165b285192aSMauro Carvalho Chehab {
1166b285192aSMauro Carvalho Chehab 	u32 instructions;
1167b285192aSMauro Carvalho Chehab 	__le32 *rp;
1168b285192aSMauro Carvalho Chehab 	int rc;
1169b285192aSMauro Carvalho Chehab 
1170b285192aSMauro Carvalho Chehab 	/* estimate risc mem: worst case is one write per page border +
1171b285192aSMauro Carvalho Chehab 	   one write per scan line + syncs + jump (all 2 dwords).  Here
1172b285192aSMauro Carvalho Chehab 	   there is no padding and no sync.  First DMA region may be smaller
1173b285192aSMauro Carvalho Chehab 	   than PAGE_SIZE */
1174b285192aSMauro Carvalho Chehab 	/* Jump and write need an extra dword */
1175b285192aSMauro Carvalho Chehab 	instructions = 1 + (bpl * lines) / PAGE_SIZE + lines;
1176b285192aSMauro Carvalho Chehab 	instructions += 1;
1177b285192aSMauro Carvalho Chehab 
11785ede94c7SHans Verkuil 	rc = cx25821_riscmem_alloc(pci, risc, instructions * 12);
1179b285192aSMauro Carvalho Chehab 	if (rc < 0)
1180b285192aSMauro Carvalho Chehab 		return rc;
1181b285192aSMauro Carvalho Chehab 
1182b285192aSMauro Carvalho Chehab 	/* write risc instructions */
1183b285192aSMauro Carvalho Chehab 	rp = risc->cpu;
1184b285192aSMauro Carvalho Chehab 	rp = cx25821_risc_field_audio(rp, sglist, 0, NO_SYNC_LINE, bpl, 0,
1185b285192aSMauro Carvalho Chehab 				      lines, lpi);
1186b285192aSMauro Carvalho Chehab 
1187b285192aSMauro Carvalho Chehab 	/* save pointer to jmp instruction address */
1188b285192aSMauro Carvalho Chehab 	risc->jmp = rp;
1189b285192aSMauro Carvalho Chehab 	BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
1190b285192aSMauro Carvalho Chehab 	return 0;
1191b285192aSMauro Carvalho Chehab }
1192b285192aSMauro Carvalho Chehab EXPORT_SYMBOL(cx25821_risc_databuffer_audio);
1193b285192aSMauro Carvalho Chehab 
cx25821_free_buffer(struct cx25821_dev * dev,struct cx25821_buffer * buf)1194b671ae6bSHans Verkuil void cx25821_free_buffer(struct cx25821_dev *dev, struct cx25821_buffer *buf)
1195b285192aSMauro Carvalho Chehab {
1196b671ae6bSHans Verkuil 	if (WARN_ON(buf->risc.size == 0))
1197b671ae6bSHans Verkuil 		return;
1198bb5d4180SChristophe JAILLET 	dma_free_coherent(&dev->pci->dev, buf->risc.size, buf->risc.cpu,
1199bb5d4180SChristophe JAILLET 			  buf->risc.dma);
1200b671ae6bSHans Verkuil 	memset(&buf->risc, 0, sizeof(buf->risc));
1201b285192aSMauro Carvalho Chehab }
1202b285192aSMauro Carvalho Chehab 
cx25821_irq(int irq,void * dev_id)1203b285192aSMauro Carvalho Chehab static irqreturn_t cx25821_irq(int irq, void *dev_id)
1204b285192aSMauro Carvalho Chehab {
1205b285192aSMauro Carvalho Chehab 	struct cx25821_dev *dev = dev_id;
1206b285192aSMauro Carvalho Chehab 	u32 pci_status;
1207b285192aSMauro Carvalho Chehab 	u32 vid_status;
1208b285192aSMauro Carvalho Chehab 	int i, handled = 0;
1209b285192aSMauro Carvalho Chehab 	u32 mask[8] = { 1, 2, 4, 8, 16, 32, 64, 128 };
1210b285192aSMauro Carvalho Chehab 
1211b285192aSMauro Carvalho Chehab 	pci_status = cx_read(PCI_INT_STAT);
1212b285192aSMauro Carvalho Chehab 
1213b285192aSMauro Carvalho Chehab 	if (pci_status == 0)
1214b285192aSMauro Carvalho Chehab 		goto out;
1215b285192aSMauro Carvalho Chehab 
1216b285192aSMauro Carvalho Chehab 	for (i = 0; i < VID_CHANNEL_NUM; i++) {
1217b285192aSMauro Carvalho Chehab 		if (pci_status & mask[i]) {
1218b285192aSMauro Carvalho Chehab 			vid_status = cx_read(dev->channels[i].
1219b285192aSMauro Carvalho Chehab 				sram_channels->int_stat);
1220b285192aSMauro Carvalho Chehab 
1221b285192aSMauro Carvalho Chehab 			if (vid_status)
1222b285192aSMauro Carvalho Chehab 				handled += cx25821_video_irq(dev, i,
1223b285192aSMauro Carvalho Chehab 						vid_status);
1224b285192aSMauro Carvalho Chehab 
1225b285192aSMauro Carvalho Chehab 			cx_write(PCI_INT_STAT, mask[i]);
1226b285192aSMauro Carvalho Chehab 		}
1227b285192aSMauro Carvalho Chehab 	}
1228b285192aSMauro Carvalho Chehab 
1229b285192aSMauro Carvalho Chehab out:
1230b285192aSMauro Carvalho Chehab 	return IRQ_RETVAL(handled);
1231b285192aSMauro Carvalho Chehab }
1232b285192aSMauro Carvalho Chehab 
cx25821_print_irqbits(char * name,char * tag,char ** strings,int len,u32 bits,u32 mask)1233b285192aSMauro Carvalho Chehab void cx25821_print_irqbits(char *name, char *tag, char **strings,
1234b285192aSMauro Carvalho Chehab 			   int len, u32 bits, u32 mask)
1235b285192aSMauro Carvalho Chehab {
1236b285192aSMauro Carvalho Chehab 	unsigned int i;
1237b285192aSMauro Carvalho Chehab 
1238b285192aSMauro Carvalho Chehab 	printk(KERN_DEBUG pr_fmt("%s: %s [0x%x]"), name, tag, bits);
1239b285192aSMauro Carvalho Chehab 
1240b285192aSMauro Carvalho Chehab 	for (i = 0; i < len; i++) {
1241b285192aSMauro Carvalho Chehab 		if (!(bits & (1 << i)))
1242b285192aSMauro Carvalho Chehab 			continue;
1243b285192aSMauro Carvalho Chehab 		if (strings[i])
1244b285192aSMauro Carvalho Chehab 			pr_cont(" %s", strings[i]);
1245b285192aSMauro Carvalho Chehab 		else
1246b285192aSMauro Carvalho Chehab 			pr_cont(" %d", i);
1247b285192aSMauro Carvalho Chehab 		if (!(mask & (1 << i)))
1248b285192aSMauro Carvalho Chehab 			continue;
1249b285192aSMauro Carvalho Chehab 		pr_cont("*");
1250b285192aSMauro Carvalho Chehab 	}
1251b285192aSMauro Carvalho Chehab 	pr_cont("\n");
1252b285192aSMauro Carvalho Chehab }
1253b285192aSMauro Carvalho Chehab EXPORT_SYMBOL(cx25821_print_irqbits);
1254b285192aSMauro Carvalho Chehab 
cx25821_dev_get(struct pci_dev * pci)1255b285192aSMauro Carvalho Chehab struct cx25821_dev *cx25821_dev_get(struct pci_dev *pci)
1256b285192aSMauro Carvalho Chehab {
1257b285192aSMauro Carvalho Chehab 	struct cx25821_dev *dev = pci_get_drvdata(pci);
1258b285192aSMauro Carvalho Chehab 	return dev;
1259b285192aSMauro Carvalho Chehab }
1260b285192aSMauro Carvalho Chehab EXPORT_SYMBOL(cx25821_dev_get);
1261b285192aSMauro Carvalho Chehab 
cx25821_initdev(struct pci_dev * pci_dev,const struct pci_device_id * pci_id)12624c62e976SGreg Kroah-Hartman static int cx25821_initdev(struct pci_dev *pci_dev,
1263b285192aSMauro Carvalho Chehab 			   const struct pci_device_id *pci_id)
1264b285192aSMauro Carvalho Chehab {
1265b285192aSMauro Carvalho Chehab 	struct cx25821_dev *dev;
1266b285192aSMauro Carvalho Chehab 	int err = 0;
1267b285192aSMauro Carvalho Chehab 
1268b285192aSMauro Carvalho Chehab 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
1269b285192aSMauro Carvalho Chehab 	if (NULL == dev)
1270b285192aSMauro Carvalho Chehab 		return -ENOMEM;
1271b285192aSMauro Carvalho Chehab 
1272b285192aSMauro Carvalho Chehab 	err = v4l2_device_register(&pci_dev->dev, &dev->v4l2_dev);
1273b285192aSMauro Carvalho Chehab 	if (err < 0)
1274b285192aSMauro Carvalho Chehab 		goto fail_free;
1275b285192aSMauro Carvalho Chehab 
1276b285192aSMauro Carvalho Chehab 	/* pci init */
1277b285192aSMauro Carvalho Chehab 	dev->pci = pci_dev;
1278b285192aSMauro Carvalho Chehab 	if (pci_enable_device(pci_dev)) {
1279b285192aSMauro Carvalho Chehab 		err = -EIO;
1280b285192aSMauro Carvalho Chehab 
1281b285192aSMauro Carvalho Chehab 		pr_info("pci enable failed!\n");
1282b285192aSMauro Carvalho Chehab 
1283b285192aSMauro Carvalho Chehab 		goto fail_unregister_device;
1284b285192aSMauro Carvalho Chehab 	}
1285b285192aSMauro Carvalho Chehab 
1286b671ae6bSHans Verkuil 	err = cx25821_dev_setup(dev);
1287b671ae6bSHans Verkuil 	if (err)
12882bc46b3aSHans Verkuil 		goto fail_unregister_pci;
1289b671ae6bSHans Verkuil 
1290b285192aSMauro Carvalho Chehab 	/* print pci info */
1291b285192aSMauro Carvalho Chehab 	pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev);
1292b285192aSMauro Carvalho Chehab 	pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat);
1293b285192aSMauro Carvalho Chehab 	pr_info("%s/0: found at %s, rev: %d, irq: %d, latency: %d, mmio: 0x%llx\n",
1294b285192aSMauro Carvalho Chehab 		dev->name, pci_name(pci_dev), dev->pci_rev, pci_dev->irq,
1295b285192aSMauro Carvalho Chehab 		dev->pci_lat, (unsigned long long)dev->base_io_addr);
1296b285192aSMauro Carvalho Chehab 
1297b285192aSMauro Carvalho Chehab 	pci_set_master(pci_dev);
1298bb5d4180SChristophe JAILLET 	err = dma_set_mask(&pci_dev->dev, 0xffffffff);
12991a47de6eSChristoph Hellwig 	if (err) {
1300b285192aSMauro Carvalho Chehab 		pr_err("%s/0: Oops: no 32bit PCI DMA ???\n", dev->name);
1301b285192aSMauro Carvalho Chehab 		err = -EIO;
1302b285192aSMauro Carvalho Chehab 		goto fail_irq;
1303b285192aSMauro Carvalho Chehab 	}
1304b285192aSMauro Carvalho Chehab 
1305b285192aSMauro Carvalho Chehab 	err = request_irq(pci_dev->irq, cx25821_irq,
1306b285192aSMauro Carvalho Chehab 			IRQF_SHARED, dev->name, dev);
1307b285192aSMauro Carvalho Chehab 
1308b285192aSMauro Carvalho Chehab 	if (err < 0) {
1309b285192aSMauro Carvalho Chehab 		pr_err("%s: can't get IRQ %d\n", dev->name, pci_dev->irq);
1310b285192aSMauro Carvalho Chehab 		goto fail_irq;
1311b285192aSMauro Carvalho Chehab 	}
1312b285192aSMauro Carvalho Chehab 
1313b285192aSMauro Carvalho Chehab 	return 0;
1314b285192aSMauro Carvalho Chehab 
1315b285192aSMauro Carvalho Chehab fail_irq:
1316b285192aSMauro Carvalho Chehab 	pr_info("cx25821_initdev() can't get IRQ !\n");
1317b285192aSMauro Carvalho Chehab 	cx25821_dev_unregister(dev);
1318b285192aSMauro Carvalho Chehab 
1319b285192aSMauro Carvalho Chehab fail_unregister_pci:
1320b285192aSMauro Carvalho Chehab 	pci_disable_device(pci_dev);
1321b285192aSMauro Carvalho Chehab fail_unregister_device:
1322b285192aSMauro Carvalho Chehab 	v4l2_device_unregister(&dev->v4l2_dev);
1323b285192aSMauro Carvalho Chehab 
1324b285192aSMauro Carvalho Chehab fail_free:
1325b285192aSMauro Carvalho Chehab 	kfree(dev);
1326b285192aSMauro Carvalho Chehab 	return err;
1327b285192aSMauro Carvalho Chehab }
1328b285192aSMauro Carvalho Chehab 
cx25821_finidev(struct pci_dev * pci_dev)13294c62e976SGreg Kroah-Hartman static void cx25821_finidev(struct pci_dev *pci_dev)
1330b285192aSMauro Carvalho Chehab {
1331b285192aSMauro Carvalho Chehab 	struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
1332b285192aSMauro Carvalho Chehab 	struct cx25821_dev *dev = get_cx25821(v4l2_dev);
1333b285192aSMauro Carvalho Chehab 
1334b285192aSMauro Carvalho Chehab 	cx25821_shutdown(dev);
1335b285192aSMauro Carvalho Chehab 
1336b285192aSMauro Carvalho Chehab 	/* unregister stuff */
1337b285192aSMauro Carvalho Chehab 	if (pci_dev->irq)
1338b285192aSMauro Carvalho Chehab 		free_irq(pci_dev->irq, dev);
1339*2203436aSZheyu Ma 	pci_disable_device(pci_dev);
1340b285192aSMauro Carvalho Chehab 
1341b285192aSMauro Carvalho Chehab 	cx25821_dev_unregister(dev);
1342b285192aSMauro Carvalho Chehab 	v4l2_device_unregister(v4l2_dev);
1343b285192aSMauro Carvalho Chehab 	kfree(dev);
1344b285192aSMauro Carvalho Chehab }
1345b285192aSMauro Carvalho Chehab 
1346f1b84d36SJingoo Han static const struct pci_device_id cx25821_pci_tbl[] = {
1347b285192aSMauro Carvalho Chehab 	{
1348b285192aSMauro Carvalho Chehab 		/* CX25821 Athena */
1349b285192aSMauro Carvalho Chehab 		.vendor = 0x14f1,
1350b285192aSMauro Carvalho Chehab 		.device = 0x8210,
1351b285192aSMauro Carvalho Chehab 		.subvendor = 0x14f1,
1352b285192aSMauro Carvalho Chehab 		.subdevice = 0x0920,
1353b285192aSMauro Carvalho Chehab 	}, {
1354b285192aSMauro Carvalho Chehab 		/* CX25821 No Brand */
1355b285192aSMauro Carvalho Chehab 		.vendor = 0x14f1,
1356b285192aSMauro Carvalho Chehab 		.device = 0x8210,
1357b285192aSMauro Carvalho Chehab 		.subvendor = 0x0000,
1358b285192aSMauro Carvalho Chehab 		.subdevice = 0x0000,
1359b285192aSMauro Carvalho Chehab 	}, {
1360b285192aSMauro Carvalho Chehab 		/* --- end of list --- */
1361b285192aSMauro Carvalho Chehab 	}
1362b285192aSMauro Carvalho Chehab };
1363b285192aSMauro Carvalho Chehab 
1364b285192aSMauro Carvalho Chehab MODULE_DEVICE_TABLE(pci, cx25821_pci_tbl);
1365b285192aSMauro Carvalho Chehab 
1366b285192aSMauro Carvalho Chehab static struct pci_driver cx25821_pci_driver = {
1367b285192aSMauro Carvalho Chehab 	.name = "cx25821",
1368b285192aSMauro Carvalho Chehab 	.id_table = cx25821_pci_tbl,
1369b285192aSMauro Carvalho Chehab 	.probe = cx25821_initdev,
13704c62e976SGreg Kroah-Hartman 	.remove = cx25821_finidev,
1371b285192aSMauro Carvalho Chehab };
1372b285192aSMauro Carvalho Chehab 
cx25821_init(void)1373b285192aSMauro Carvalho Chehab static int __init cx25821_init(void)
1374b285192aSMauro Carvalho Chehab {
1375d1044776SMauro Carvalho Chehab 	pr_info("driver loaded\n");
1376b285192aSMauro Carvalho Chehab 	return pci_register_driver(&cx25821_pci_driver);
1377b285192aSMauro Carvalho Chehab }
1378b285192aSMauro Carvalho Chehab 
cx25821_fini(void)1379b285192aSMauro Carvalho Chehab static void __exit cx25821_fini(void)
1380b285192aSMauro Carvalho Chehab {
1381b285192aSMauro Carvalho Chehab 	pci_unregister_driver(&cx25821_pci_driver);
1382b285192aSMauro Carvalho Chehab }
1383b285192aSMauro Carvalho Chehab 
1384b285192aSMauro Carvalho Chehab module_init(cx25821_init);
1385b285192aSMauro Carvalho Chehab module_exit(cx25821_fini);
1386