1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Driver for the Conexant CX25821 PCIe bridge |
4 | * |
5 | * Copyright (C) 2009 Conexant Systems Inc. |
6 | * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com> |
7 | * Based on Steven Toth <stoth@linuxtv.org> cx23885 driver |
8 | */ |
9 | |
10 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
11 | |
12 | #include <linux/i2c.h> |
13 | #include <linux/slab.h> |
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 | |
22 | static unsigned int debug; |
23 | module_param(debug, int, 0644); |
24 | MODULE_PARM_DESC(debug, "enable debug messages" ); |
25 | |
26 | static unsigned int card[] = {[0 ... (CX25821_MAXBOARDS - 1)] = UNSET }; |
27 | module_param_array(card, int, NULL, 0444); |
28 | MODULE_PARM_DESC(card, "card type" ); |
29 | |
30 | const struct sram_channel cx25821_sram_channels[] = { |
31 | [SRAM_CH00] = { |
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 | }, |
52 | |
53 | [SRAM_CH01] = { |
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 | }, |
74 | |
75 | [SRAM_CH02] = { |
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 | }, |
96 | |
97 | [SRAM_CH03] = { |
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 | }, |
118 | |
119 | [SRAM_CH04] = { |
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 | }, |
140 | |
141 | [SRAM_CH05] = { |
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 | }, |
162 | |
163 | [SRAM_CH06] = { |
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 | }, |
184 | |
185 | [SRAM_CH07] = { |
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 | }, |
206 | |
207 | [SRAM_CH08] = { |
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 | }, |
219 | |
220 | [SRAM_CH09] = { |
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 | }, |
245 | |
246 | [SRAM_CH10] = { |
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 | }, |
271 | |
272 | [SRAM_CH11] = { |
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 | }, |
296 | }; |
297 | EXPORT_SYMBOL(cx25821_sram_channels); |
298 | |
299 | static int cx25821_risc_decode(u32 risc) |
300 | { |
301 | static const char * const instr[16] = { |
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 | }; |
313 | static const int incr[16] = { |
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 | }; |
322 | static const char * const bits[] = { |
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 | |
330 | pr_cont("0x%08x [ %s" , |
331 | risc, instr[risc >> 28] ? instr[risc >> 28] : "INVALID" ); |
332 | for (i = ARRAY_SIZE(bits) - 1; i >= 0; i--) { |
333 | if (risc & (1 << (i + 12))) |
334 | pr_cont(" %s" , bits[i]); |
335 | } |
336 | pr_cont(" count=%d ]\n" , risc & 0xfff); |
337 | return incr[risc >> 28] ? incr[risc >> 28] : 1; |
338 | } |
339 | |
340 | static void cx25821_registers_init(struct cx25821_dev *dev) |
341 | { |
342 | u32 tmp; |
343 | |
344 | /* enable RUN_RISC in Pecos */ |
345 | cx_write(DEV_CNTRL2, 0x20); |
346 | |
347 | /* Set the master PCI interrupt masks to enable video, audio, MBIF, |
348 | * and GPIO interrupts |
349 | * I2C interrupt masking is handled by the I2C objects themselves. */ |
350 | cx_write(PCI_INT_MSK, 0x2001FFFF); |
351 | |
352 | tmp = cx_read(RDR_TLCTL0); |
353 | tmp &= ~FLD_CFG_RCB_CK_EN; /* Clear the RCB_CK_EN bit */ |
354 | cx_write(RDR_TLCTL0, tmp); |
355 | |
356 | /* PLL-A setting for the Audio Master Clock */ |
357 | cx_write(PLL_A_INT_FRAC, 0x9807A58B); |
358 | |
359 | /* PLL_A_POST = 0x1C, PLL_A_OUT_TO_PIN = 0x1 */ |
360 | cx_write(PLL_A_POST_STAT_BIST, 0x8000019C); |
361 | |
362 | /* clear reset bit [31] */ |
363 | tmp = cx_read(PLL_A_INT_FRAC); |
364 | cx_write(PLL_A_INT_FRAC, tmp & 0x7FFFFFFF); |
365 | |
366 | /* PLL-B setting for Mobilygen Host Bus Interface */ |
367 | cx_write(PLL_B_INT_FRAC, 0x9883A86F); |
368 | |
369 | /* PLL_B_POST = 0xD, PLL_B_OUT_TO_PIN = 0x0 */ |
370 | cx_write(PLL_B_POST_STAT_BIST, 0x8000018D); |
371 | |
372 | /* clear reset bit [31] */ |
373 | tmp = cx_read(PLL_B_INT_FRAC); |
374 | cx_write(PLL_B_INT_FRAC, tmp & 0x7FFFFFFF); |
375 | |
376 | /* PLL-C setting for video upstream channel */ |
377 | cx_write(PLL_C_INT_FRAC, 0x96A0EA3F); |
378 | |
379 | /* PLL_C_POST = 0x3, PLL_C_OUT_TO_PIN = 0x0 */ |
380 | cx_write(PLL_C_POST_STAT_BIST, 0x80000103); |
381 | |
382 | /* clear reset bit [31] */ |
383 | tmp = cx_read(PLL_C_INT_FRAC); |
384 | cx_write(PLL_C_INT_FRAC, tmp & 0x7FFFFFFF); |
385 | |
386 | /* PLL-D setting for audio upstream channel */ |
387 | cx_write(PLL_D_INT_FRAC, 0x98757F5B); |
388 | |
389 | /* PLL_D_POST = 0x13, PLL_D_OUT_TO_PIN = 0x0 */ |
390 | cx_write(PLL_D_POST_STAT_BIST, 0x80000113); |
391 | |
392 | /* clear reset bit [31] */ |
393 | tmp = cx_read(PLL_D_INT_FRAC); |
394 | cx_write(PLL_D_INT_FRAC, tmp & 0x7FFFFFFF); |
395 | |
396 | /* This selects the PLL C clock source for the video upstream channel |
397 | * I and J */ |
398 | tmp = cx_read(VID_CH_CLK_SEL); |
399 | cx_write(VID_CH_CLK_SEL, (tmp & 0x00FFFFFF) | 0x24000000); |
400 | |
401 | /* 656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface for |
402 | * channel A-C |
403 | * select 656/VIP DST for downstream Channel A - C */ |
404 | tmp = cx_read(VID_CH_MODE_SEL); |
405 | /* cx_write( VID_CH_MODE_SEL, tmp | 0x1B0001FF); */ |
406 | cx_write(VID_CH_MODE_SEL, tmp & 0xFFFFFE00); |
407 | |
408 | /* enables 656 port I and J as output */ |
409 | tmp = cx_read(CLK_RST); |
410 | /* use external ALT_PLL_REF pin as its reference clock instead */ |
411 | tmp |= FLD_USE_ALT_PLL_REF; |
412 | cx_write(CLK_RST, tmp & ~(FLD_VID_I_CLK_NOE | FLD_VID_J_CLK_NOE)); |
413 | |
414 | msleep(msecs: 100); |
415 | } |
416 | |
417 | int cx25821_sram_channel_setup(struct cx25821_dev *dev, |
418 | const struct sram_channel *ch, |
419 | unsigned int bpl, u32 risc) |
420 | { |
421 | unsigned int i, lines; |
422 | u32 cdt; |
423 | |
424 | if (ch->cmds_start == 0) { |
425 | cx_write(ch->ptr1_reg, 0); |
426 | cx_write(ch->ptr2_reg, 0); |
427 | cx_write(ch->cnt2_reg, 0); |
428 | cx_write(ch->cnt1_reg, 0); |
429 | return 0; |
430 | } |
431 | |
432 | bpl = (bpl + 7) & ~7; /* alignment */ |
433 | cdt = ch->cdt; |
434 | lines = ch->fifo_size / bpl; |
435 | |
436 | if (lines > 4) |
437 | lines = 4; |
438 | |
439 | BUG_ON(lines < 2); |
440 | |
441 | cx_write(8 + 0, RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); |
442 | cx_write(8 + 4, 8); |
443 | cx_write(8 + 8, 0); |
444 | |
445 | /* write CDT */ |
446 | for (i = 0; i < lines; i++) { |
447 | cx_write(cdt + 16 * i, ch->fifo_start + bpl * i); |
448 | cx_write(cdt + 16 * i + 4, 0); |
449 | cx_write(cdt + 16 * i + 8, 0); |
450 | cx_write(cdt + 16 * i + 12, 0); |
451 | } |
452 | |
453 | /* init the first cdt buffer */ |
454 | for (i = 0; i < 128; i++) |
455 | cx_write(ch->fifo_start + 4 * i, i); |
456 | |
457 | /* write CMDS */ |
458 | if (ch->jumponly) |
459 | cx_write(ch->cmds_start + 0, 8); |
460 | else |
461 | cx_write(ch->cmds_start + 0, risc); |
462 | |
463 | cx_write(ch->cmds_start + 4, 0); /* 64 bits 63-32 */ |
464 | cx_write(ch->cmds_start + 8, cdt); |
465 | cx_write(ch->cmds_start + 12, (lines * 16) >> 3); |
466 | cx_write(ch->cmds_start + 16, ch->ctrl_start); |
467 | |
468 | if (ch->jumponly) |
469 | cx_write(ch->cmds_start + 20, 0x80000000 | (64 >> 2)); |
470 | else |
471 | cx_write(ch->cmds_start + 20, 64 >> 2); |
472 | |
473 | for (i = 24; i < 80; i += 4) |
474 | cx_write(ch->cmds_start + i, 0); |
475 | |
476 | /* fill registers */ |
477 | cx_write(ch->ptr1_reg, ch->fifo_start); |
478 | cx_write(ch->ptr2_reg, cdt); |
479 | cx_write(ch->cnt2_reg, (lines * 16) >> 3); |
480 | cx_write(ch->cnt1_reg, (bpl >> 3) - 1); |
481 | |
482 | return 0; |
483 | } |
484 | |
485 | int cx25821_sram_channel_setup_audio(struct cx25821_dev *dev, |
486 | const struct sram_channel *ch, |
487 | unsigned int bpl, u32 risc) |
488 | { |
489 | unsigned int i, lines; |
490 | u32 cdt; |
491 | |
492 | if (ch->cmds_start == 0) { |
493 | cx_write(ch->ptr1_reg, 0); |
494 | cx_write(ch->ptr2_reg, 0); |
495 | cx_write(ch->cnt2_reg, 0); |
496 | cx_write(ch->cnt1_reg, 0); |
497 | return 0; |
498 | } |
499 | |
500 | bpl = (bpl + 7) & ~7; /* alignment */ |
501 | cdt = ch->cdt; |
502 | lines = ch->fifo_size / bpl; |
503 | |
504 | if (lines > 3) |
505 | lines = 3; /* for AUDIO */ |
506 | |
507 | BUG_ON(lines < 2); |
508 | |
509 | cx_write(8 + 0, RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); |
510 | cx_write(8 + 4, 8); |
511 | cx_write(8 + 8, 0); |
512 | |
513 | /* write CDT */ |
514 | for (i = 0; i < lines; i++) { |
515 | cx_write(cdt + 16 * i, ch->fifo_start + bpl * i); |
516 | cx_write(cdt + 16 * i + 4, 0); |
517 | cx_write(cdt + 16 * i + 8, 0); |
518 | cx_write(cdt + 16 * i + 12, 0); |
519 | } |
520 | |
521 | /* write CMDS */ |
522 | if (ch->jumponly) |
523 | cx_write(ch->cmds_start + 0, 8); |
524 | else |
525 | cx_write(ch->cmds_start + 0, risc); |
526 | |
527 | cx_write(ch->cmds_start + 4, 0); /* 64 bits 63-32 */ |
528 | cx_write(ch->cmds_start + 8, cdt); |
529 | cx_write(ch->cmds_start + 12, (lines * 16) >> 3); |
530 | cx_write(ch->cmds_start + 16, ch->ctrl_start); |
531 | |
532 | /* IQ size */ |
533 | if (ch->jumponly) |
534 | cx_write(ch->cmds_start + 20, 0x80000000 | (64 >> 2)); |
535 | else |
536 | cx_write(ch->cmds_start + 20, 64 >> 2); |
537 | |
538 | /* zero out */ |
539 | for (i = 24; i < 80; i += 4) |
540 | cx_write(ch->cmds_start + i, 0); |
541 | |
542 | /* fill registers */ |
543 | cx_write(ch->ptr1_reg, ch->fifo_start); |
544 | cx_write(ch->ptr2_reg, cdt); |
545 | cx_write(ch->cnt2_reg, (lines * 16) >> 3); |
546 | cx_write(ch->cnt1_reg, (bpl >> 3) - 1); |
547 | |
548 | return 0; |
549 | } |
550 | EXPORT_SYMBOL(cx25821_sram_channel_setup_audio); |
551 | |
552 | void cx25821_sram_channel_dump(struct cx25821_dev *dev, const struct sram_channel *ch) |
553 | { |
554 | static char *name[] = { |
555 | "init risc lo" , |
556 | "init risc hi" , |
557 | "cdt base" , |
558 | "cdt size" , |
559 | "iq base" , |
560 | "iq size" , |
561 | "risc pc lo" , |
562 | "risc pc hi" , |
563 | "iq wr ptr" , |
564 | "iq rd ptr" , |
565 | "cdt current" , |
566 | "pci target lo" , |
567 | "pci target hi" , |
568 | "line / byte" , |
569 | }; |
570 | u32 risc; |
571 | unsigned int i, j, n; |
572 | |
573 | pr_warn("%s: %s - dma channel status dump\n" , dev->name, ch->name); |
574 | for (i = 0; i < ARRAY_SIZE(name); i++) |
575 | pr_warn("cmds + 0x%2x: %-15s: 0x%08x\n" , |
576 | i * 4, name[i], cx_read(ch->cmds_start + 4 * i)); |
577 | |
578 | j = i * 4; |
579 | for (i = 0; i < 4;) { |
580 | risc = cx_read(ch->cmds_start + 4 * (i + 14)); |
581 | pr_warn("cmds + 0x%2x: risc%d: " , j + i * 4, i); |
582 | i += cx25821_risc_decode(risc); |
583 | } |
584 | |
585 | for (i = 0; i < (64 >> 2); i += n) { |
586 | risc = cx_read(ch->ctrl_start + 4 * i); |
587 | /* No consideration for bits 63-32 */ |
588 | |
589 | pr_warn("ctrl + 0x%2x (0x%08x): iq %x: " , |
590 | i * 4, ch->ctrl_start + 4 * i, i); |
591 | n = cx25821_risc_decode(risc); |
592 | for (j = 1; j < n; j++) { |
593 | risc = cx_read(ch->ctrl_start + 4 * (i + j)); |
594 | pr_warn("ctrl + 0x%2x : iq %x: 0x%08x [ arg #%d ]\n" , |
595 | 4 * (i + j), i + j, risc, j); |
596 | } |
597 | } |
598 | |
599 | pr_warn(" : fifo: 0x%08x -> 0x%x\n" , |
600 | ch->fifo_start, ch->fifo_start + ch->fifo_size); |
601 | pr_warn(" : ctrl: 0x%08x -> 0x%x\n" , |
602 | ch->ctrl_start, ch->ctrl_start + 6 * 16); |
603 | pr_warn(" : ptr1_reg: 0x%08x\n" , |
604 | cx_read(ch->ptr1_reg)); |
605 | pr_warn(" : ptr2_reg: 0x%08x\n" , |
606 | cx_read(ch->ptr2_reg)); |
607 | pr_warn(" : cnt1_reg: 0x%08x\n" , |
608 | cx_read(ch->cnt1_reg)); |
609 | pr_warn(" : cnt2_reg: 0x%08x\n" , |
610 | cx_read(ch->cnt2_reg)); |
611 | } |
612 | |
613 | void cx25821_sram_channel_dump_audio(struct cx25821_dev *dev, |
614 | const struct sram_channel *ch) |
615 | { |
616 | static const char * const name[] = { |
617 | "init risc lo" , |
618 | "init risc hi" , |
619 | "cdt base" , |
620 | "cdt size" , |
621 | "iq base" , |
622 | "iq size" , |
623 | "risc pc lo" , |
624 | "risc pc hi" , |
625 | "iq wr ptr" , |
626 | "iq rd ptr" , |
627 | "cdt current" , |
628 | "pci target lo" , |
629 | "pci target hi" , |
630 | "line / byte" , |
631 | }; |
632 | |
633 | u32 risc, value, tmp; |
634 | unsigned int i, j, n; |
635 | |
636 | pr_info("\n%s: %s - dma Audio channel status dump\n" , |
637 | dev->name, ch->name); |
638 | |
639 | for (i = 0; i < ARRAY_SIZE(name); i++) |
640 | pr_info("%s: cmds + 0x%2x: %-15s: 0x%08x\n" , |
641 | dev->name, i * 4, name[i], |
642 | cx_read(ch->cmds_start + 4 * i)); |
643 | |
644 | j = i * 4; |
645 | for (i = 0; i < 4;) { |
646 | risc = cx_read(ch->cmds_start + 4 * (i + 14)); |
647 | pr_warn("cmds + 0x%2x: risc%d: " , j + i * 4, i); |
648 | i += cx25821_risc_decode(risc); |
649 | } |
650 | |
651 | for (i = 0; i < (64 >> 2); i += n) { |
652 | risc = cx_read(ch->ctrl_start + 4 * i); |
653 | /* No consideration for bits 63-32 */ |
654 | |
655 | pr_warn("ctrl + 0x%2x (0x%08x): iq %x: " , |
656 | i * 4, ch->ctrl_start + 4 * i, i); |
657 | n = cx25821_risc_decode(risc); |
658 | |
659 | for (j = 1; j < n; j++) { |
660 | risc = cx_read(ch->ctrl_start + 4 * (i + j)); |
661 | pr_warn("ctrl + 0x%2x : iq %x: 0x%08x [ arg #%d ]\n" , |
662 | 4 * (i + j), i + j, risc, j); |
663 | } |
664 | } |
665 | |
666 | pr_warn(" : fifo: 0x%08x -> 0x%x\n" , |
667 | ch->fifo_start, ch->fifo_start + ch->fifo_size); |
668 | pr_warn(" : ctrl: 0x%08x -> 0x%x\n" , |
669 | ch->ctrl_start, ch->ctrl_start + 6 * 16); |
670 | pr_warn(" : ptr1_reg: 0x%08x\n" , |
671 | cx_read(ch->ptr1_reg)); |
672 | pr_warn(" : ptr2_reg: 0x%08x\n" , |
673 | cx_read(ch->ptr2_reg)); |
674 | pr_warn(" : cnt1_reg: 0x%08x\n" , |
675 | cx_read(ch->cnt1_reg)); |
676 | pr_warn(" : cnt2_reg: 0x%08x\n" , |
677 | cx_read(ch->cnt2_reg)); |
678 | |
679 | for (i = 0; i < 4; i++) { |
680 | risc = cx_read(ch->cmds_start + 56 + (i * 4)); |
681 | pr_warn("instruction %d = 0x%x\n" , i, risc); |
682 | } |
683 | |
684 | /* read data from the first cdt buffer */ |
685 | risc = cx_read(AUD_A_CDT); |
686 | pr_warn("\nread cdt loc=0x%x\n" , risc); |
687 | for (i = 0; i < 8; i++) { |
688 | n = cx_read(risc + i * 4); |
689 | pr_cont("0x%x " , n); |
690 | } |
691 | pr_cont("\n\n" ); |
692 | |
693 | value = cx_read(CLK_RST); |
694 | CX25821_INFO(" CLK_RST = 0x%x\n\n" , value); |
695 | |
696 | value = cx_read(PLL_A_POST_STAT_BIST); |
697 | CX25821_INFO(" PLL_A_POST_STAT_BIST = 0x%x\n\n" , value); |
698 | value = cx_read(PLL_A_INT_FRAC); |
699 | CX25821_INFO(" PLL_A_INT_FRAC = 0x%x\n\n" , value); |
700 | |
701 | value = cx_read(PLL_B_POST_STAT_BIST); |
702 | CX25821_INFO(" PLL_B_POST_STAT_BIST = 0x%x\n\n" , value); |
703 | value = cx_read(PLL_B_INT_FRAC); |
704 | CX25821_INFO(" PLL_B_INT_FRAC = 0x%x\n\n" , value); |
705 | |
706 | value = cx_read(PLL_C_POST_STAT_BIST); |
707 | CX25821_INFO(" PLL_C_POST_STAT_BIST = 0x%x\n\n" , value); |
708 | value = cx_read(PLL_C_INT_FRAC); |
709 | CX25821_INFO(" PLL_C_INT_FRAC = 0x%x\n\n" , value); |
710 | |
711 | value = cx_read(PLL_D_POST_STAT_BIST); |
712 | CX25821_INFO(" PLL_D_POST_STAT_BIST = 0x%x\n\n" , value); |
713 | value = cx_read(PLL_D_INT_FRAC); |
714 | CX25821_INFO(" PLL_D_INT_FRAC = 0x%x\n\n" , value); |
715 | |
716 | value = cx25821_i2c_read(bus: &dev->i2c_bus[0], AFE_AB_DIAG_CTRL, value: &tmp); |
717 | CX25821_INFO(" AFE_AB_DIAG_CTRL (0x10900090) = 0x%x\n\n" , value); |
718 | } |
719 | EXPORT_SYMBOL(cx25821_sram_channel_dump_audio); |
720 | |
721 | static void cx25821_shutdown(struct cx25821_dev *dev) |
722 | { |
723 | int i; |
724 | |
725 | /* disable RISC controller */ |
726 | cx_write(DEV_CNTRL2, 0); |
727 | |
728 | /* Disable Video A/B activity */ |
729 | for (i = 0; i < VID_CHANNEL_NUM; i++) { |
730 | cx_write(dev->channels[i].sram_channels->dma_ctl, 0); |
731 | cx_write(dev->channels[i].sram_channels->int_msk, 0); |
732 | } |
733 | |
734 | for (i = VID_UPSTREAM_SRAM_CHANNEL_I; |
735 | i <= VID_UPSTREAM_SRAM_CHANNEL_J; i++) { |
736 | cx_write(dev->channels[i].sram_channels->dma_ctl, 0); |
737 | cx_write(dev->channels[i].sram_channels->int_msk, 0); |
738 | } |
739 | |
740 | /* Disable Audio activity */ |
741 | cx_write(AUD_INT_DMA_CTL, 0); |
742 | |
743 | /* Disable Serial port */ |
744 | cx_write(UART_CTL, 0); |
745 | |
746 | /* Disable Interrupts */ |
747 | cx_write(PCI_INT_MSK, 0); |
748 | cx_write(AUD_A_INT_MSK, 0); |
749 | } |
750 | |
751 | void cx25821_set_pixel_format(struct cx25821_dev *dev, int channel_select, |
752 | u32 format) |
753 | { |
754 | if (channel_select <= 7 && channel_select >= 0) { |
755 | cx_write(dev->channels[channel_select].sram_channels->pix_frmt, |
756 | format); |
757 | } |
758 | dev->channels[channel_select].pixel_formats = format; |
759 | } |
760 | |
761 | static void cx25821_set_vip_mode(struct cx25821_dev *dev, |
762 | const struct sram_channel *ch) |
763 | { |
764 | cx_write(ch->pix_frmt, PIXEL_FRMT_422); |
765 | cx_write(ch->vip_ctl, PIXEL_ENGINE_VIP1); |
766 | } |
767 | |
768 | static void cx25821_initialize(struct cx25821_dev *dev) |
769 | { |
770 | int i; |
771 | |
772 | dprintk(1, "%s()\n" , __func__); |
773 | |
774 | cx25821_shutdown(dev); |
775 | cx_write(PCI_INT_STAT, 0xffffffff); |
776 | |
777 | for (i = 0; i < VID_CHANNEL_NUM; i++) |
778 | cx_write(dev->channels[i].sram_channels->int_stat, 0xffffffff); |
779 | |
780 | cx_write(AUD_A_INT_STAT, 0xffffffff); |
781 | cx_write(AUD_B_INT_STAT, 0xffffffff); |
782 | cx_write(AUD_C_INT_STAT, 0xffffffff); |
783 | cx_write(AUD_D_INT_STAT, 0xffffffff); |
784 | cx_write(AUD_E_INT_STAT, 0xffffffff); |
785 | |
786 | cx_write(CLK_DELAY, cx_read(CLK_DELAY) & 0x80000000); |
787 | cx_write(PAD_CTRL, 0x12); /* for I2C */ |
788 | cx25821_registers_init(dev); /* init Pecos registers */ |
789 | msleep(msecs: 100); |
790 | |
791 | for (i = 0; i < VID_CHANNEL_NUM; i++) { |
792 | cx25821_set_vip_mode(dev, ch: dev->channels[i].sram_channels); |
793 | cx25821_sram_channel_setup(dev, ch: dev->channels[i].sram_channels, |
794 | bpl: 1440, risc: 0); |
795 | dev->channels[i].pixel_formats = PIXEL_FRMT_422; |
796 | dev->channels[i].use_cif_resolution = 0; |
797 | } |
798 | |
799 | /* Probably only affect Downstream */ |
800 | for (i = VID_UPSTREAM_SRAM_CHANNEL_I; |
801 | i <= VID_UPSTREAM_SRAM_CHANNEL_J; i++) { |
802 | dev->channels[i].pixel_formats = PIXEL_FRMT_422; |
803 | cx25821_set_vip_mode(dev, ch: dev->channels[i].sram_channels); |
804 | } |
805 | |
806 | cx25821_sram_channel_setup_audio(dev, |
807 | dev->channels[SRAM_CH08].sram_channels, 128, 0); |
808 | |
809 | cx25821_gpio_init(dev); |
810 | } |
811 | |
812 | static int cx25821_get_resources(struct cx25821_dev *dev) |
813 | { |
814 | if (request_mem_region(pci_resource_start(dev->pci, 0), |
815 | pci_resource_len(dev->pci, 0), dev->name)) |
816 | return 0; |
817 | |
818 | pr_err("%s: can't get MMIO memory @ 0x%llx\n" , |
819 | dev->name, (unsigned long long)pci_resource_start(dev->pci, 0)); |
820 | |
821 | return -EBUSY; |
822 | } |
823 | |
824 | static void cx25821_dev_checkrevision(struct cx25821_dev *dev) |
825 | { |
826 | dev->hwrevision = cx_read(RDR_CFG2) & 0xff; |
827 | |
828 | pr_info("Hardware revision = 0x%02x\n" , dev->hwrevision); |
829 | } |
830 | |
831 | static void cx25821_iounmap(struct cx25821_dev *dev) |
832 | { |
833 | if (dev == NULL) |
834 | return; |
835 | |
836 | /* Releasing IO memory */ |
837 | if (dev->lmmio != NULL) { |
838 | iounmap(addr: dev->lmmio); |
839 | dev->lmmio = NULL; |
840 | } |
841 | } |
842 | |
843 | static int cx25821_dev_setup(struct cx25821_dev *dev) |
844 | { |
845 | static unsigned int cx25821_devcount; |
846 | int i; |
847 | |
848 | mutex_init(&dev->lock); |
849 | |
850 | dev->nr = ++cx25821_devcount; |
851 | sprintf(buf: dev->name, fmt: "cx25821[%d]" , dev->nr); |
852 | |
853 | if (dev->nr >= ARRAY_SIZE(card)) { |
854 | CX25821_INFO("dev->nr >= %zd" , ARRAY_SIZE(card)); |
855 | return -ENODEV; |
856 | } |
857 | if (dev->pci->device != 0x8210) { |
858 | pr_info("%s(): Exiting. Incorrect Hardware device = 0x%02x\n" , |
859 | __func__, dev->pci->device); |
860 | return -ENODEV; |
861 | } |
862 | pr_info("Athena Hardware device = 0x%02x\n" , dev->pci->device); |
863 | |
864 | /* Apply a sensible clock frequency for the PCIe bridge */ |
865 | dev->clk_freq = 28000000; |
866 | for (i = 0; i < MAX_VID_CHANNEL_NUM; i++) { |
867 | dev->channels[i].dev = dev; |
868 | dev->channels[i].id = i; |
869 | dev->channels[i].sram_channels = &cx25821_sram_channels[i]; |
870 | } |
871 | |
872 | /* board config */ |
873 | dev->board = 1; /* card[dev->nr]; */ |
874 | dev->_max_num_decoders = MAX_DECODERS; |
875 | |
876 | dev->pci_bus = dev->pci->bus->number; |
877 | dev->pci_slot = PCI_SLOT(dev->pci->devfn); |
878 | dev->pci_irqmask = 0x001f00; |
879 | |
880 | /* External Master 1 Bus */ |
881 | dev->i2c_bus[0].nr = 0; |
882 | dev->i2c_bus[0].dev = dev; |
883 | dev->i2c_bus[0].reg_stat = I2C1_STAT; |
884 | dev->i2c_bus[0].reg_ctrl = I2C1_CTRL; |
885 | dev->i2c_bus[0].reg_addr = I2C1_ADDR; |
886 | dev->i2c_bus[0].reg_rdata = I2C1_RDATA; |
887 | dev->i2c_bus[0].reg_wdata = I2C1_WDATA; |
888 | dev->i2c_bus[0].i2c_period = (0x07 << 24); /* 1.95MHz */ |
889 | |
890 | if (cx25821_get_resources(dev) < 0) { |
891 | pr_err("%s: No more PCIe resources for subsystem: %04x:%04x\n" , |
892 | dev->name, dev->pci->subsystem_vendor, |
893 | dev->pci->subsystem_device); |
894 | |
895 | cx25821_devcount--; |
896 | return -EBUSY; |
897 | } |
898 | |
899 | /* PCIe stuff */ |
900 | dev->base_io_addr = pci_resource_start(dev->pci, 0); |
901 | |
902 | if (!dev->base_io_addr) { |
903 | CX25821_ERR("No PCI Memory resources, exiting!\n" ); |
904 | return -ENODEV; |
905 | } |
906 | |
907 | dev->lmmio = ioremap(offset: dev->base_io_addr, pci_resource_len(dev->pci, 0)); |
908 | |
909 | if (!dev->lmmio) { |
910 | CX25821_ERR("ioremap failed, maybe increasing __VMALLOC_RESERVE in page.h\n" ); |
911 | cx25821_iounmap(dev); |
912 | return -ENOMEM; |
913 | } |
914 | |
915 | dev->bmmio = (u8 __iomem *) dev->lmmio; |
916 | |
917 | pr_info("%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n" , |
918 | dev->name, dev->pci->subsystem_vendor, |
919 | dev->pci->subsystem_device, cx25821_boards[dev->board].name, |
920 | dev->board, card[dev->nr] == dev->board ? |
921 | "insmod option" : "autodetected" ); |
922 | |
923 | /* init hardware */ |
924 | cx25821_initialize(dev); |
925 | |
926 | cx25821_i2c_register(bus: &dev->i2c_bus[0]); |
927 | /* cx25821_i2c_register(&dev->i2c_bus[1]); |
928 | * cx25821_i2c_register(&dev->i2c_bus[2]); */ |
929 | |
930 | if (medusa_video_init(dev) < 0) |
931 | CX25821_ERR("%s(): Failed to initialize medusa!\n" , __func__); |
932 | |
933 | cx25821_video_register(dev); |
934 | |
935 | cx25821_dev_checkrevision(dev); |
936 | return 0; |
937 | } |
938 | |
939 | void cx25821_dev_unregister(struct cx25821_dev *dev) |
940 | { |
941 | int i; |
942 | |
943 | if (!dev->base_io_addr) |
944 | return; |
945 | |
946 | release_mem_region(dev->base_io_addr, pci_resource_len(dev->pci, 0)); |
947 | |
948 | for (i = 0; i < MAX_VID_CAP_CHANNEL_NUM - 1; i++) { |
949 | if (i == SRAM_CH08) /* audio channel */ |
950 | continue; |
951 | /* |
952 | * TODO: enable when video output is properly |
953 | * supported. |
954 | if (i == SRAM_CH09 || i == SRAM_CH10) |
955 | cx25821_free_mem_upstream(&dev->channels[i]); |
956 | */ |
957 | cx25821_video_unregister(dev, chan_num: i); |
958 | } |
959 | |
960 | cx25821_i2c_unregister(bus: &dev->i2c_bus[0]); |
961 | cx25821_iounmap(dev); |
962 | } |
963 | EXPORT_SYMBOL(cx25821_dev_unregister); |
964 | |
965 | int cx25821_riscmem_alloc(struct pci_dev *pci, |
966 | struct cx25821_riscmem *risc, |
967 | unsigned int size) |
968 | { |
969 | __le32 *cpu; |
970 | dma_addr_t dma = 0; |
971 | |
972 | if (risc->cpu && risc->size < size) { |
973 | dma_free_coherent(dev: &pci->dev, size: risc->size, cpu_addr: risc->cpu, dma_handle: risc->dma); |
974 | risc->cpu = NULL; |
975 | } |
976 | if (NULL == risc->cpu) { |
977 | cpu = dma_alloc_coherent(dev: &pci->dev, size, dma_handle: &dma, GFP_KERNEL); |
978 | if (NULL == cpu) |
979 | return -ENOMEM; |
980 | risc->cpu = cpu; |
981 | risc->dma = dma; |
982 | risc->size = size; |
983 | } |
984 | return 0; |
985 | } |
986 | EXPORT_SYMBOL(cx25821_riscmem_alloc); |
987 | |
988 | static __le32 *cx25821_risc_field(__le32 * rp, struct scatterlist *sglist, |
989 | unsigned int offset, u32 sync_line, |
990 | unsigned int bpl, unsigned int padding, |
991 | unsigned int lines, bool jump) |
992 | { |
993 | struct scatterlist *sg; |
994 | unsigned int line, todo; |
995 | |
996 | if (jump) { |
997 | *(rp++) = cpu_to_le32(RISC_JUMP); |
998 | *(rp++) = cpu_to_le32(0); |
999 | *(rp++) = cpu_to_le32(0); /* bits 63-32 */ |
1000 | } |
1001 | |
1002 | /* sync instruction */ |
1003 | if (sync_line != NO_SYNC_LINE) |
1004 | *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); |
1005 | |
1006 | /* scan lines */ |
1007 | sg = sglist; |
1008 | for (line = 0; line < lines; line++) { |
1009 | while (offset && offset >= sg_dma_len(sg)) { |
1010 | offset -= sg_dma_len(sg); |
1011 | sg = sg_next(sg); |
1012 | } |
1013 | if (bpl <= sg_dma_len(sg) - offset) { |
1014 | /* fits into current chunk */ |
1015 | *(rp++) = cpu_to_le32(RISC_WRITE | RISC_SOL | RISC_EOL | |
1016 | bpl); |
1017 | *(rp++) = cpu_to_le32(sg_dma_address(sg) + offset); |
1018 | *(rp++) = cpu_to_le32(0); /* bits 63-32 */ |
1019 | offset += bpl; |
1020 | } else { |
1021 | /* scanline needs to be split */ |
1022 | todo = bpl; |
1023 | *(rp++) = cpu_to_le32(RISC_WRITE | RISC_SOL | |
1024 | (sg_dma_len(sg) - offset)); |
1025 | *(rp++) = cpu_to_le32(sg_dma_address(sg) + offset); |
1026 | *(rp++) = cpu_to_le32(0); /* bits 63-32 */ |
1027 | todo -= (sg_dma_len(sg) - offset); |
1028 | offset = 0; |
1029 | sg = sg_next(sg); |
1030 | while (todo > sg_dma_len(sg)) { |
1031 | *(rp++) = cpu_to_le32(RISC_WRITE | |
1032 | sg_dma_len(sg)); |
1033 | *(rp++) = cpu_to_le32(sg_dma_address(sg)); |
1034 | *(rp++) = cpu_to_le32(0); /* bits 63-32 */ |
1035 | todo -= sg_dma_len(sg); |
1036 | sg = sg_next(sg); |
1037 | } |
1038 | *(rp++) = cpu_to_le32(RISC_WRITE | RISC_EOL | todo); |
1039 | *(rp++) = cpu_to_le32(sg_dma_address(sg)); |
1040 | *(rp++) = cpu_to_le32(0); /* bits 63-32 */ |
1041 | offset += todo; |
1042 | } |
1043 | |
1044 | offset += padding; |
1045 | } |
1046 | |
1047 | return rp; |
1048 | } |
1049 | |
1050 | int cx25821_risc_buffer(struct pci_dev *pci, struct cx25821_riscmem *risc, |
1051 | struct scatterlist *sglist, unsigned int top_offset, |
1052 | unsigned int bottom_offset, unsigned int bpl, |
1053 | unsigned int padding, unsigned int lines) |
1054 | { |
1055 | u32 instructions; |
1056 | u32 fields; |
1057 | __le32 *rp; |
1058 | int rc; |
1059 | |
1060 | fields = 0; |
1061 | if (UNSET != top_offset) |
1062 | fields++; |
1063 | if (UNSET != bottom_offset) |
1064 | fields++; |
1065 | |
1066 | /* estimate risc mem: worst case is one write per page border + |
1067 | one write per scan line + syncs + jump (all 3 dwords). Padding |
1068 | can cause next bpl to start close to a page border. First DMA |
1069 | region may be smaller than PAGE_SIZE */ |
1070 | /* write and jump need and extra dword */ |
1071 | instructions = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + |
1072 | lines); |
1073 | instructions += 5; |
1074 | rc = cx25821_riscmem_alloc(pci, risc, instructions * 12); |
1075 | |
1076 | if (rc < 0) |
1077 | return rc; |
1078 | |
1079 | /* write risc instructions */ |
1080 | rp = risc->cpu; |
1081 | |
1082 | if (UNSET != top_offset) { |
1083 | rp = cx25821_risc_field(rp, sglist, offset: top_offset, sync_line: 0, bpl, padding, |
1084 | lines, jump: true); |
1085 | } |
1086 | |
1087 | if (UNSET != bottom_offset) { |
1088 | rp = cx25821_risc_field(rp, sglist, offset: bottom_offset, sync_line: 0x200, bpl, |
1089 | padding, lines, UNSET == top_offset); |
1090 | } |
1091 | |
1092 | /* save pointer to jmp instruction address */ |
1093 | risc->jmp = rp; |
1094 | BUG_ON((risc->jmp - risc->cpu + 3) * sizeof(*risc->cpu) > risc->size); |
1095 | |
1096 | return 0; |
1097 | } |
1098 | |
1099 | static __le32 *cx25821_risc_field_audio(__le32 * rp, struct scatterlist *sglist, |
1100 | unsigned int offset, u32 sync_line, |
1101 | unsigned int bpl, unsigned int padding, |
1102 | unsigned int lines, unsigned int lpi) |
1103 | { |
1104 | struct scatterlist *sg; |
1105 | unsigned int line, todo, sol; |
1106 | |
1107 | /* sync instruction */ |
1108 | if (sync_line != NO_SYNC_LINE) |
1109 | *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); |
1110 | |
1111 | /* scan lines */ |
1112 | sg = sglist; |
1113 | for (line = 0; line < lines; line++) { |
1114 | while (offset && offset >= sg_dma_len(sg)) { |
1115 | offset -= sg_dma_len(sg); |
1116 | sg = sg_next(sg); |
1117 | } |
1118 | |
1119 | if (lpi && line > 0 && !(line % lpi)) |
1120 | sol = RISC_SOL | RISC_IRQ1 | RISC_CNT_INC; |
1121 | else |
1122 | sol = RISC_SOL; |
1123 | |
1124 | if (bpl <= sg_dma_len(sg) - offset) { |
1125 | /* fits into current chunk */ |
1126 | *(rp++) = cpu_to_le32(RISC_WRITE | sol | RISC_EOL | |
1127 | bpl); |
1128 | *(rp++) = cpu_to_le32(sg_dma_address(sg) + offset); |
1129 | *(rp++) = cpu_to_le32(0); /* bits 63-32 */ |
1130 | offset += bpl; |
1131 | } else { |
1132 | /* scanline needs to be split */ |
1133 | todo = bpl; |
1134 | *(rp++) = cpu_to_le32(RISC_WRITE | sol | |
1135 | (sg_dma_len(sg) - offset)); |
1136 | *(rp++) = cpu_to_le32(sg_dma_address(sg) + offset); |
1137 | *(rp++) = cpu_to_le32(0); /* bits 63-32 */ |
1138 | todo -= (sg_dma_len(sg) - offset); |
1139 | offset = 0; |
1140 | sg = sg_next(sg); |
1141 | while (todo > sg_dma_len(sg)) { |
1142 | *(rp++) = cpu_to_le32(RISC_WRITE | |
1143 | sg_dma_len(sg)); |
1144 | *(rp++) = cpu_to_le32(sg_dma_address(sg)); |
1145 | *(rp++) = cpu_to_le32(0); /* bits 63-32 */ |
1146 | todo -= sg_dma_len(sg); |
1147 | sg = sg_next(sg); |
1148 | } |
1149 | *(rp++) = cpu_to_le32(RISC_WRITE | RISC_EOL | todo); |
1150 | *(rp++) = cpu_to_le32(sg_dma_address(sg)); |
1151 | *(rp++) = cpu_to_le32(0); /* bits 63-32 */ |
1152 | offset += todo; |
1153 | } |
1154 | offset += padding; |
1155 | } |
1156 | |
1157 | return rp; |
1158 | } |
1159 | |
1160 | int cx25821_risc_databuffer_audio(struct pci_dev *pci, |
1161 | struct cx25821_riscmem *risc, |
1162 | struct scatterlist *sglist, |
1163 | unsigned int bpl, |
1164 | unsigned int lines, unsigned int lpi) |
1165 | { |
1166 | u32 instructions; |
1167 | __le32 *rp; |
1168 | int rc; |
1169 | |
1170 | /* estimate risc mem: worst case is one write per page border + |
1171 | one write per scan line + syncs + jump (all 2 dwords). Here |
1172 | there is no padding and no sync. First DMA region may be smaller |
1173 | than PAGE_SIZE */ |
1174 | /* Jump and write need an extra dword */ |
1175 | instructions = 1 + (bpl * lines) / PAGE_SIZE + lines; |
1176 | instructions += 1; |
1177 | |
1178 | rc = cx25821_riscmem_alloc(pci, risc, instructions * 12); |
1179 | if (rc < 0) |
1180 | return rc; |
1181 | |
1182 | /* write risc instructions */ |
1183 | rp = risc->cpu; |
1184 | rp = cx25821_risc_field_audio(rp, sglist, offset: 0, NO_SYNC_LINE, bpl, padding: 0, |
1185 | lines, lpi); |
1186 | |
1187 | /* save pointer to jmp instruction address */ |
1188 | risc->jmp = rp; |
1189 | BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); |
1190 | return 0; |
1191 | } |
1192 | EXPORT_SYMBOL(cx25821_risc_databuffer_audio); |
1193 | |
1194 | void cx25821_free_buffer(struct cx25821_dev *dev, struct cx25821_buffer *buf) |
1195 | { |
1196 | if (WARN_ON(buf->risc.size == 0)) |
1197 | return; |
1198 | dma_free_coherent(dev: &dev->pci->dev, size: buf->risc.size, cpu_addr: buf->risc.cpu, |
1199 | dma_handle: buf->risc.dma); |
1200 | memset(&buf->risc, 0, sizeof(buf->risc)); |
1201 | } |
1202 | |
1203 | static irqreturn_t cx25821_irq(int irq, void *dev_id) |
1204 | { |
1205 | struct cx25821_dev *dev = dev_id; |
1206 | u32 pci_status; |
1207 | u32 vid_status; |
1208 | int i, handled = 0; |
1209 | u32 mask[8] = { 1, 2, 4, 8, 16, 32, 64, 128 }; |
1210 | |
1211 | pci_status = cx_read(PCI_INT_STAT); |
1212 | |
1213 | if (pci_status == 0) |
1214 | goto out; |
1215 | |
1216 | for (i = 0; i < VID_CHANNEL_NUM; i++) { |
1217 | if (pci_status & mask[i]) { |
1218 | vid_status = cx_read(dev->channels[i]. |
1219 | sram_channels->int_stat); |
1220 | |
1221 | if (vid_status) |
1222 | handled += cx25821_video_irq(dev, chan_num: i, |
1223 | status: vid_status); |
1224 | |
1225 | cx_write(PCI_INT_STAT, mask[i]); |
1226 | } |
1227 | } |
1228 | |
1229 | out: |
1230 | return IRQ_RETVAL(handled); |
1231 | } |
1232 | |
1233 | void cx25821_print_irqbits(char *name, char *tag, char **strings, |
1234 | int len, u32 bits, u32 mask) |
1235 | { |
1236 | unsigned int i; |
1237 | |
1238 | printk(KERN_DEBUG pr_fmt("%s: %s [0x%x]" ), name, tag, bits); |
1239 | |
1240 | for (i = 0; i < len; i++) { |
1241 | if (!(bits & (1 << i))) |
1242 | continue; |
1243 | if (strings[i]) |
1244 | pr_cont(" %s" , strings[i]); |
1245 | else |
1246 | pr_cont(" %d" , i); |
1247 | if (!(mask & (1 << i))) |
1248 | continue; |
1249 | pr_cont("*" ); |
1250 | } |
1251 | pr_cont("\n" ); |
1252 | } |
1253 | EXPORT_SYMBOL(cx25821_print_irqbits); |
1254 | |
1255 | struct cx25821_dev *cx25821_dev_get(struct pci_dev *pci) |
1256 | { |
1257 | struct cx25821_dev *dev = pci_get_drvdata(pdev: pci); |
1258 | return dev; |
1259 | } |
1260 | EXPORT_SYMBOL(cx25821_dev_get); |
1261 | |
1262 | static int cx25821_initdev(struct pci_dev *pci_dev, |
1263 | const struct pci_device_id *pci_id) |
1264 | { |
1265 | struct cx25821_dev *dev; |
1266 | int err = 0; |
1267 | |
1268 | dev = kzalloc(size: sizeof(*dev), GFP_KERNEL); |
1269 | if (NULL == dev) |
1270 | return -ENOMEM; |
1271 | |
1272 | err = v4l2_device_register(dev: &pci_dev->dev, v4l2_dev: &dev->v4l2_dev); |
1273 | if (err < 0) |
1274 | goto fail_free; |
1275 | |
1276 | /* pci init */ |
1277 | dev->pci = pci_dev; |
1278 | if (pci_enable_device(dev: pci_dev)) { |
1279 | err = -EIO; |
1280 | |
1281 | pr_info("pci enable failed!\n" ); |
1282 | |
1283 | goto fail_unregister_device; |
1284 | } |
1285 | |
1286 | err = cx25821_dev_setup(dev); |
1287 | if (err) |
1288 | goto fail_unregister_pci; |
1289 | |
1290 | /* print pci info */ |
1291 | pci_read_config_byte(dev: pci_dev, PCI_CLASS_REVISION, val: &dev->pci_rev); |
1292 | pci_read_config_byte(dev: pci_dev, PCI_LATENCY_TIMER, val: &dev->pci_lat); |
1293 | pr_info("%s/0: found at %s, rev: %d, irq: %d, latency: %d, mmio: 0x%llx\n" , |
1294 | dev->name, pci_name(pci_dev), dev->pci_rev, pci_dev->irq, |
1295 | dev->pci_lat, (unsigned long long)dev->base_io_addr); |
1296 | |
1297 | pci_set_master(dev: pci_dev); |
1298 | err = dma_set_mask(dev: &pci_dev->dev, mask: 0xffffffff); |
1299 | if (err) { |
1300 | pr_err("%s/0: Oops: no 32bit PCI DMA ???\n" , dev->name); |
1301 | err = -EIO; |
1302 | goto fail_irq; |
1303 | } |
1304 | |
1305 | err = request_irq(irq: pci_dev->irq, handler: cx25821_irq, |
1306 | IRQF_SHARED, name: dev->name, dev); |
1307 | |
1308 | if (err < 0) { |
1309 | pr_err("%s: can't get IRQ %d\n" , dev->name, pci_dev->irq); |
1310 | goto fail_irq; |
1311 | } |
1312 | |
1313 | return 0; |
1314 | |
1315 | fail_irq: |
1316 | pr_info("cx25821_initdev() can't get IRQ !\n" ); |
1317 | cx25821_dev_unregister(dev); |
1318 | |
1319 | fail_unregister_pci: |
1320 | pci_disable_device(dev: pci_dev); |
1321 | fail_unregister_device: |
1322 | v4l2_device_unregister(v4l2_dev: &dev->v4l2_dev); |
1323 | |
1324 | fail_free: |
1325 | kfree(objp: dev); |
1326 | return err; |
1327 | } |
1328 | |
1329 | static void cx25821_finidev(struct pci_dev *pci_dev) |
1330 | { |
1331 | struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev: pci_dev); |
1332 | struct cx25821_dev *dev = get_cx25821(v4l2_dev); |
1333 | |
1334 | cx25821_shutdown(dev); |
1335 | |
1336 | /* unregister stuff */ |
1337 | if (pci_dev->irq) |
1338 | free_irq(pci_dev->irq, dev); |
1339 | pci_disable_device(dev: pci_dev); |
1340 | |
1341 | cx25821_dev_unregister(dev); |
1342 | v4l2_device_unregister(v4l2_dev); |
1343 | kfree(objp: dev); |
1344 | } |
1345 | |
1346 | static const struct pci_device_id cx25821_pci_tbl[] = { |
1347 | { |
1348 | /* CX25821 Athena */ |
1349 | .vendor = 0x14f1, |
1350 | .device = 0x8210, |
1351 | .subvendor = 0x14f1, |
1352 | .subdevice = 0x0920, |
1353 | }, { |
1354 | /* CX25821 No Brand */ |
1355 | .vendor = 0x14f1, |
1356 | .device = 0x8210, |
1357 | .subvendor = 0x0000, |
1358 | .subdevice = 0x0000, |
1359 | }, { |
1360 | /* --- end of list --- */ |
1361 | } |
1362 | }; |
1363 | |
1364 | MODULE_DEVICE_TABLE(pci, cx25821_pci_tbl); |
1365 | |
1366 | static struct pci_driver cx25821_pci_driver = { |
1367 | .name = "cx25821" , |
1368 | .id_table = cx25821_pci_tbl, |
1369 | .probe = cx25821_initdev, |
1370 | .remove = cx25821_finidev, |
1371 | }; |
1372 | |
1373 | static int __init cx25821_init(void) |
1374 | { |
1375 | pr_info("driver loaded\n" ); |
1376 | return pci_register_driver(&cx25821_pci_driver); |
1377 | } |
1378 | |
1379 | static void __exit cx25821_fini(void) |
1380 | { |
1381 | pci_unregister_driver(dev: &cx25821_pci_driver); |
1382 | } |
1383 | |
1384 | module_init(cx25821_init); |
1385 | module_exit(cx25821_fini); |
1386 | |