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