1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Support for a cx23417 mpeg encoder via cx23885 host port.
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * (c) 2004 Jelle Foks <jelle@foks.us>
7*4882a593Smuzhiyun * (c) 2004 Gerd Knorr <kraxel@bytesex.org>
8*4882a593Smuzhiyun * (c) 2008 Steven Toth <stoth@linuxtv.org>
9*4882a593Smuzhiyun * - CX23885/7/8 support
10*4882a593Smuzhiyun *
11*4882a593Smuzhiyun * Includes parts from the ivtv driver <http://sourceforge.net/projects/ivtv/>
12*4882a593Smuzhiyun */
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun #include "cx23885.h"
15*4882a593Smuzhiyun #include "cx23885-ioctl.h"
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun #include <linux/module.h>
18*4882a593Smuzhiyun #include <linux/moduleparam.h>
19*4882a593Smuzhiyun #include <linux/init.h>
20*4882a593Smuzhiyun #include <linux/fs.h>
21*4882a593Smuzhiyun #include <linux/delay.h>
22*4882a593Smuzhiyun #include <linux/device.h>
23*4882a593Smuzhiyun #include <linux/firmware.h>
24*4882a593Smuzhiyun #include <linux/slab.h>
25*4882a593Smuzhiyun #include <media/v4l2-common.h>
26*4882a593Smuzhiyun #include <media/v4l2-ioctl.h>
27*4882a593Smuzhiyun #include <media/drv-intf/cx2341x.h>
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun #define CX23885_FIRM_IMAGE_SIZE 376836
30*4882a593Smuzhiyun #define CX23885_FIRM_IMAGE_NAME "v4l-cx23885-enc.fw"
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun static unsigned int mpegbufs = 32;
33*4882a593Smuzhiyun module_param(mpegbufs, int, 0644);
34*4882a593Smuzhiyun MODULE_PARM_DESC(mpegbufs, "number of mpeg buffers, range 2-32");
35*4882a593Smuzhiyun static unsigned int mpeglines = 32;
36*4882a593Smuzhiyun module_param(mpeglines, int, 0644);
37*4882a593Smuzhiyun MODULE_PARM_DESC(mpeglines, "number of lines in an MPEG buffer, range 2-32");
38*4882a593Smuzhiyun static unsigned int mpeglinesize = 512;
39*4882a593Smuzhiyun module_param(mpeglinesize, int, 0644);
40*4882a593Smuzhiyun MODULE_PARM_DESC(mpeglinesize,
41*4882a593Smuzhiyun "number of bytes in each line of an MPEG buffer, range 512-1024");
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun static unsigned int v4l_debug;
44*4882a593Smuzhiyun module_param(v4l_debug, int, 0644);
45*4882a593Smuzhiyun MODULE_PARM_DESC(v4l_debug, "enable V4L debug messages");
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun #define dprintk(level, fmt, arg...)\
48*4882a593Smuzhiyun do { if (v4l_debug >= level) \
49*4882a593Smuzhiyun printk(KERN_DEBUG pr_fmt("%s: 417:" fmt), \
50*4882a593Smuzhiyun __func__, ##arg); \
51*4882a593Smuzhiyun } while (0)
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun static struct cx23885_tvnorm cx23885_tvnorms[] = {
54*4882a593Smuzhiyun {
55*4882a593Smuzhiyun .name = "NTSC-M",
56*4882a593Smuzhiyun .id = V4L2_STD_NTSC_M,
57*4882a593Smuzhiyun }, {
58*4882a593Smuzhiyun .name = "NTSC-JP",
59*4882a593Smuzhiyun .id = V4L2_STD_NTSC_M_JP,
60*4882a593Smuzhiyun }, {
61*4882a593Smuzhiyun .name = "PAL-BG",
62*4882a593Smuzhiyun .id = V4L2_STD_PAL_BG,
63*4882a593Smuzhiyun }, {
64*4882a593Smuzhiyun .name = "PAL-DK",
65*4882a593Smuzhiyun .id = V4L2_STD_PAL_DK,
66*4882a593Smuzhiyun }, {
67*4882a593Smuzhiyun .name = "PAL-I",
68*4882a593Smuzhiyun .id = V4L2_STD_PAL_I,
69*4882a593Smuzhiyun }, {
70*4882a593Smuzhiyun .name = "PAL-M",
71*4882a593Smuzhiyun .id = V4L2_STD_PAL_M,
72*4882a593Smuzhiyun }, {
73*4882a593Smuzhiyun .name = "PAL-N",
74*4882a593Smuzhiyun .id = V4L2_STD_PAL_N,
75*4882a593Smuzhiyun }, {
76*4882a593Smuzhiyun .name = "PAL-Nc",
77*4882a593Smuzhiyun .id = V4L2_STD_PAL_Nc,
78*4882a593Smuzhiyun }, {
79*4882a593Smuzhiyun .name = "PAL-60",
80*4882a593Smuzhiyun .id = V4L2_STD_PAL_60,
81*4882a593Smuzhiyun }, {
82*4882a593Smuzhiyun .name = "SECAM-L",
83*4882a593Smuzhiyun .id = V4L2_STD_SECAM_L,
84*4882a593Smuzhiyun }, {
85*4882a593Smuzhiyun .name = "SECAM-DK",
86*4882a593Smuzhiyun .id = V4L2_STD_SECAM_DK,
87*4882a593Smuzhiyun }
88*4882a593Smuzhiyun };
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun /* ------------------------------------------------------------------ */
91*4882a593Smuzhiyun enum cx23885_capture_type {
92*4882a593Smuzhiyun CX23885_MPEG_CAPTURE,
93*4882a593Smuzhiyun CX23885_RAW_CAPTURE,
94*4882a593Smuzhiyun CX23885_RAW_PASSTHRU_CAPTURE
95*4882a593Smuzhiyun };
96*4882a593Smuzhiyun enum cx23885_capture_bits {
97*4882a593Smuzhiyun CX23885_RAW_BITS_NONE = 0x00,
98*4882a593Smuzhiyun CX23885_RAW_BITS_YUV_CAPTURE = 0x01,
99*4882a593Smuzhiyun CX23885_RAW_BITS_PCM_CAPTURE = 0x02,
100*4882a593Smuzhiyun CX23885_RAW_BITS_VBI_CAPTURE = 0x04,
101*4882a593Smuzhiyun CX23885_RAW_BITS_PASSTHRU_CAPTURE = 0x08,
102*4882a593Smuzhiyun CX23885_RAW_BITS_TO_HOST_CAPTURE = 0x10
103*4882a593Smuzhiyun };
104*4882a593Smuzhiyun enum cx23885_capture_end {
105*4882a593Smuzhiyun CX23885_END_AT_GOP, /* stop at the end of gop, generate irq */
106*4882a593Smuzhiyun CX23885_END_NOW, /* stop immediately, no irq */
107*4882a593Smuzhiyun };
108*4882a593Smuzhiyun enum cx23885_framerate {
109*4882a593Smuzhiyun CX23885_FRAMERATE_NTSC_30, /* NTSC: 30fps */
110*4882a593Smuzhiyun CX23885_FRAMERATE_PAL_25 /* PAL: 25fps */
111*4882a593Smuzhiyun };
112*4882a593Smuzhiyun enum cx23885_stream_port {
113*4882a593Smuzhiyun CX23885_OUTPUT_PORT_MEMORY,
114*4882a593Smuzhiyun CX23885_OUTPUT_PORT_STREAMING,
115*4882a593Smuzhiyun CX23885_OUTPUT_PORT_SERIAL
116*4882a593Smuzhiyun };
117*4882a593Smuzhiyun enum cx23885_data_xfer_status {
118*4882a593Smuzhiyun CX23885_MORE_BUFFERS_FOLLOW,
119*4882a593Smuzhiyun CX23885_LAST_BUFFER,
120*4882a593Smuzhiyun };
121*4882a593Smuzhiyun enum cx23885_picture_mask {
122*4882a593Smuzhiyun CX23885_PICTURE_MASK_NONE,
123*4882a593Smuzhiyun CX23885_PICTURE_MASK_I_FRAMES,
124*4882a593Smuzhiyun CX23885_PICTURE_MASK_I_P_FRAMES = 0x3,
125*4882a593Smuzhiyun CX23885_PICTURE_MASK_ALL_FRAMES = 0x7,
126*4882a593Smuzhiyun };
127*4882a593Smuzhiyun enum cx23885_vbi_mode_bits {
128*4882a593Smuzhiyun CX23885_VBI_BITS_SLICED,
129*4882a593Smuzhiyun CX23885_VBI_BITS_RAW,
130*4882a593Smuzhiyun };
131*4882a593Smuzhiyun enum cx23885_vbi_insertion_bits {
132*4882a593Smuzhiyun CX23885_VBI_BITS_INSERT_IN_XTENSION_USR_DATA,
133*4882a593Smuzhiyun CX23885_VBI_BITS_INSERT_IN_PRIVATE_PACKETS = 0x1 << 1,
134*4882a593Smuzhiyun CX23885_VBI_BITS_SEPARATE_STREAM = 0x2 << 1,
135*4882a593Smuzhiyun CX23885_VBI_BITS_SEPARATE_STREAM_USR_DATA = 0x4 << 1,
136*4882a593Smuzhiyun CX23885_VBI_BITS_SEPARATE_STREAM_PRV_DATA = 0x5 << 1,
137*4882a593Smuzhiyun };
138*4882a593Smuzhiyun enum cx23885_dma_unit {
139*4882a593Smuzhiyun CX23885_DMA_BYTES,
140*4882a593Smuzhiyun CX23885_DMA_FRAMES,
141*4882a593Smuzhiyun };
142*4882a593Smuzhiyun enum cx23885_dma_transfer_status_bits {
143*4882a593Smuzhiyun CX23885_DMA_TRANSFER_BITS_DONE = 0x01,
144*4882a593Smuzhiyun CX23885_DMA_TRANSFER_BITS_ERROR = 0x04,
145*4882a593Smuzhiyun CX23885_DMA_TRANSFER_BITS_LL_ERROR = 0x10,
146*4882a593Smuzhiyun };
147*4882a593Smuzhiyun enum cx23885_pause {
148*4882a593Smuzhiyun CX23885_PAUSE_ENCODING,
149*4882a593Smuzhiyun CX23885_RESUME_ENCODING,
150*4882a593Smuzhiyun };
151*4882a593Smuzhiyun enum cx23885_copyright {
152*4882a593Smuzhiyun CX23885_COPYRIGHT_OFF,
153*4882a593Smuzhiyun CX23885_COPYRIGHT_ON,
154*4882a593Smuzhiyun };
155*4882a593Smuzhiyun enum cx23885_notification_type {
156*4882a593Smuzhiyun CX23885_NOTIFICATION_REFRESH,
157*4882a593Smuzhiyun };
158*4882a593Smuzhiyun enum cx23885_notification_status {
159*4882a593Smuzhiyun CX23885_NOTIFICATION_OFF,
160*4882a593Smuzhiyun CX23885_NOTIFICATION_ON,
161*4882a593Smuzhiyun };
162*4882a593Smuzhiyun enum cx23885_notification_mailbox {
163*4882a593Smuzhiyun CX23885_NOTIFICATION_NO_MAILBOX = -1,
164*4882a593Smuzhiyun };
165*4882a593Smuzhiyun enum cx23885_field1_lines {
166*4882a593Smuzhiyun CX23885_FIELD1_SAA7114 = 0x00EF, /* 239 */
167*4882a593Smuzhiyun CX23885_FIELD1_SAA7115 = 0x00F0, /* 240 */
168*4882a593Smuzhiyun CX23885_FIELD1_MICRONAS = 0x0105, /* 261 */
169*4882a593Smuzhiyun };
170*4882a593Smuzhiyun enum cx23885_field2_lines {
171*4882a593Smuzhiyun CX23885_FIELD2_SAA7114 = 0x00EF, /* 239 */
172*4882a593Smuzhiyun CX23885_FIELD2_SAA7115 = 0x00F0, /* 240 */
173*4882a593Smuzhiyun CX23885_FIELD2_MICRONAS = 0x0106, /* 262 */
174*4882a593Smuzhiyun };
175*4882a593Smuzhiyun enum cx23885_custom_data_type {
176*4882a593Smuzhiyun CX23885_CUSTOM_EXTENSION_USR_DATA,
177*4882a593Smuzhiyun CX23885_CUSTOM_PRIVATE_PACKET,
178*4882a593Smuzhiyun };
179*4882a593Smuzhiyun enum cx23885_mute {
180*4882a593Smuzhiyun CX23885_UNMUTE,
181*4882a593Smuzhiyun CX23885_MUTE,
182*4882a593Smuzhiyun };
183*4882a593Smuzhiyun enum cx23885_mute_video_mask {
184*4882a593Smuzhiyun CX23885_MUTE_VIDEO_V_MASK = 0x0000FF00,
185*4882a593Smuzhiyun CX23885_MUTE_VIDEO_U_MASK = 0x00FF0000,
186*4882a593Smuzhiyun CX23885_MUTE_VIDEO_Y_MASK = 0xFF000000,
187*4882a593Smuzhiyun };
188*4882a593Smuzhiyun enum cx23885_mute_video_shift {
189*4882a593Smuzhiyun CX23885_MUTE_VIDEO_V_SHIFT = 8,
190*4882a593Smuzhiyun CX23885_MUTE_VIDEO_U_SHIFT = 16,
191*4882a593Smuzhiyun CX23885_MUTE_VIDEO_Y_SHIFT = 24,
192*4882a593Smuzhiyun };
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun /* defines below are from ivtv-driver.h */
195*4882a593Smuzhiyun #define IVTV_CMD_HW_BLOCKS_RST 0xFFFFFFFF
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun /* Firmware API commands */
198*4882a593Smuzhiyun #define IVTV_API_STD_TIMEOUT 500
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun /* Registers */
201*4882a593Smuzhiyun /* IVTV_REG_OFFSET */
202*4882a593Smuzhiyun #define IVTV_REG_ENC_SDRAM_REFRESH (0x07F8)
203*4882a593Smuzhiyun #define IVTV_REG_ENC_SDRAM_PRECHARGE (0x07FC)
204*4882a593Smuzhiyun #define IVTV_REG_SPU (0x9050)
205*4882a593Smuzhiyun #define IVTV_REG_HW_BLOCKS (0x9054)
206*4882a593Smuzhiyun #define IVTV_REG_VPU (0x9058)
207*4882a593Smuzhiyun #define IVTV_REG_APU (0xA064)
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun /**** Bit definitions for MC417_RWD and MC417_OEN registers ***
210*4882a593Smuzhiyun bits 31-16
211*4882a593Smuzhiyun +-----------+
212*4882a593Smuzhiyun | Reserved |
213*4882a593Smuzhiyun +-----------+
214*4882a593Smuzhiyun bit 15 bit 14 bit 13 bit 12 bit 11 bit 10 bit 9 bit 8
215*4882a593Smuzhiyun +-------+-------+-------+-------+-------+-------+-------+-------+
216*4882a593Smuzhiyun | MIWR# | MIRD# | MICS# |MIRDY# |MIADDR3|MIADDR2|MIADDR1|MIADDR0|
217*4882a593Smuzhiyun +-------+-------+-------+-------+-------+-------+-------+-------+
218*4882a593Smuzhiyun bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0
219*4882a593Smuzhiyun +-------+-------+-------+-------+-------+-------+-------+-------+
220*4882a593Smuzhiyun |MIDATA7|MIDATA6|MIDATA5|MIDATA4|MIDATA3|MIDATA2|MIDATA1|MIDATA0|
221*4882a593Smuzhiyun +-------+-------+-------+-------+-------+-------+-------+-------+
222*4882a593Smuzhiyun ***/
223*4882a593Smuzhiyun #define MC417_MIWR 0x8000
224*4882a593Smuzhiyun #define MC417_MIRD 0x4000
225*4882a593Smuzhiyun #define MC417_MICS 0x2000
226*4882a593Smuzhiyun #define MC417_MIRDY 0x1000
227*4882a593Smuzhiyun #define MC417_MIADDR 0x0F00
228*4882a593Smuzhiyun #define MC417_MIDATA 0x00FF
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun /* MIADDR* nibble definitions */
231*4882a593Smuzhiyun #define MCI_MEMORY_DATA_BYTE0 0x000
232*4882a593Smuzhiyun #define MCI_MEMORY_DATA_BYTE1 0x100
233*4882a593Smuzhiyun #define MCI_MEMORY_DATA_BYTE2 0x200
234*4882a593Smuzhiyun #define MCI_MEMORY_DATA_BYTE3 0x300
235*4882a593Smuzhiyun #define MCI_MEMORY_ADDRESS_BYTE2 0x400
236*4882a593Smuzhiyun #define MCI_MEMORY_ADDRESS_BYTE1 0x500
237*4882a593Smuzhiyun #define MCI_MEMORY_ADDRESS_BYTE0 0x600
238*4882a593Smuzhiyun #define MCI_REGISTER_DATA_BYTE0 0x800
239*4882a593Smuzhiyun #define MCI_REGISTER_DATA_BYTE1 0x900
240*4882a593Smuzhiyun #define MCI_REGISTER_DATA_BYTE2 0xA00
241*4882a593Smuzhiyun #define MCI_REGISTER_DATA_BYTE3 0xB00
242*4882a593Smuzhiyun #define MCI_REGISTER_ADDRESS_BYTE0 0xC00
243*4882a593Smuzhiyun #define MCI_REGISTER_ADDRESS_BYTE1 0xD00
244*4882a593Smuzhiyun #define MCI_REGISTER_MODE 0xE00
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun /* Read and write modes */
247*4882a593Smuzhiyun #define MCI_MODE_REGISTER_READ 0
248*4882a593Smuzhiyun #define MCI_MODE_REGISTER_WRITE 1
249*4882a593Smuzhiyun #define MCI_MODE_MEMORY_READ 0
250*4882a593Smuzhiyun #define MCI_MODE_MEMORY_WRITE 0x40
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun /*** Bit definitions for MC417_CTL register ****
253*4882a593Smuzhiyun bits 31-6 bits 5-4 bit 3 bits 2-1 Bit 0
254*4882a593Smuzhiyun +--------+-------------+--------+--------------+------------+
255*4882a593Smuzhiyun |Reserved|MC417_SPD_CTL|Reserved|MC417_GPIO_SEL|UART_GPIO_EN|
256*4882a593Smuzhiyun +--------+-------------+--------+--------------+------------+
257*4882a593Smuzhiyun ***/
258*4882a593Smuzhiyun #define MC417_SPD_CTL(x) (((x) << 4) & 0x00000030)
259*4882a593Smuzhiyun #define MC417_GPIO_SEL(x) (((x) << 1) & 0x00000006)
260*4882a593Smuzhiyun #define MC417_UART_GPIO_EN 0x00000001
261*4882a593Smuzhiyun
262*4882a593Smuzhiyun /* Values for speed control */
263*4882a593Smuzhiyun #define MC417_SPD_CTL_SLOW 0x1
264*4882a593Smuzhiyun #define MC417_SPD_CTL_MEDIUM 0x0
265*4882a593Smuzhiyun #define MC417_SPD_CTL_FAST 0x3 /* b'1x, but we use b'11 */
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun /* Values for GPIO select */
268*4882a593Smuzhiyun #define MC417_GPIO_SEL_GPIO3 0x3
269*4882a593Smuzhiyun #define MC417_GPIO_SEL_GPIO2 0x2
270*4882a593Smuzhiyun #define MC417_GPIO_SEL_GPIO1 0x1
271*4882a593Smuzhiyun #define MC417_GPIO_SEL_GPIO0 0x0
272*4882a593Smuzhiyun
cx23885_mc417_init(struct cx23885_dev * dev)273*4882a593Smuzhiyun void cx23885_mc417_init(struct cx23885_dev *dev)
274*4882a593Smuzhiyun {
275*4882a593Smuzhiyun u32 regval;
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun dprintk(2, "%s()\n", __func__);
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun /* Configure MC417_CTL register to defaults. */
280*4882a593Smuzhiyun regval = MC417_SPD_CTL(MC417_SPD_CTL_FAST) |
281*4882a593Smuzhiyun MC417_GPIO_SEL(MC417_GPIO_SEL_GPIO3) |
282*4882a593Smuzhiyun MC417_UART_GPIO_EN;
283*4882a593Smuzhiyun cx_write(MC417_CTL, regval);
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun /* Configure MC417_OEN to defaults. */
286*4882a593Smuzhiyun regval = MC417_MIRDY;
287*4882a593Smuzhiyun cx_write(MC417_OEN, regval);
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun /* Configure MC417_RWD to defaults. */
290*4882a593Smuzhiyun regval = MC417_MIWR | MC417_MIRD | MC417_MICS;
291*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
292*4882a593Smuzhiyun }
293*4882a593Smuzhiyun
mc417_wait_ready(struct cx23885_dev * dev)294*4882a593Smuzhiyun static int mc417_wait_ready(struct cx23885_dev *dev)
295*4882a593Smuzhiyun {
296*4882a593Smuzhiyun u32 mi_ready;
297*4882a593Smuzhiyun unsigned long timeout = jiffies + msecs_to_jiffies(1);
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun for (;;) {
300*4882a593Smuzhiyun mi_ready = cx_read(MC417_RWD) & MC417_MIRDY;
301*4882a593Smuzhiyun if (mi_ready != 0)
302*4882a593Smuzhiyun return 0;
303*4882a593Smuzhiyun if (time_after(jiffies, timeout))
304*4882a593Smuzhiyun return -1;
305*4882a593Smuzhiyun udelay(1);
306*4882a593Smuzhiyun }
307*4882a593Smuzhiyun }
308*4882a593Smuzhiyun
mc417_register_write(struct cx23885_dev * dev,u16 address,u32 value)309*4882a593Smuzhiyun int mc417_register_write(struct cx23885_dev *dev, u16 address, u32 value)
310*4882a593Smuzhiyun {
311*4882a593Smuzhiyun u32 regval;
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun /* Enable MC417 GPIO outputs except for MC417_MIRDY,
314*4882a593Smuzhiyun * which is an input.
315*4882a593Smuzhiyun */
316*4882a593Smuzhiyun cx_write(MC417_OEN, MC417_MIRDY);
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun /* Write data byte 0 */
319*4882a593Smuzhiyun regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE0 |
320*4882a593Smuzhiyun (value & 0x000000FF);
321*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
322*4882a593Smuzhiyun
323*4882a593Smuzhiyun /* Transition CS/WR to effect write transaction across bus. */
324*4882a593Smuzhiyun regval |= MC417_MICS | MC417_MIWR;
325*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun /* Write data byte 1 */
328*4882a593Smuzhiyun regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE1 |
329*4882a593Smuzhiyun ((value >> 8) & 0x000000FF);
330*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
331*4882a593Smuzhiyun regval |= MC417_MICS | MC417_MIWR;
332*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun /* Write data byte 2 */
335*4882a593Smuzhiyun regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE2 |
336*4882a593Smuzhiyun ((value >> 16) & 0x000000FF);
337*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
338*4882a593Smuzhiyun regval |= MC417_MICS | MC417_MIWR;
339*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun /* Write data byte 3 */
342*4882a593Smuzhiyun regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE3 |
343*4882a593Smuzhiyun ((value >> 24) & 0x000000FF);
344*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
345*4882a593Smuzhiyun regval |= MC417_MICS | MC417_MIWR;
346*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
347*4882a593Smuzhiyun
348*4882a593Smuzhiyun /* Write address byte 0 */
349*4882a593Smuzhiyun regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE0 |
350*4882a593Smuzhiyun (address & 0xFF);
351*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
352*4882a593Smuzhiyun regval |= MC417_MICS | MC417_MIWR;
353*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
354*4882a593Smuzhiyun
355*4882a593Smuzhiyun /* Write address byte 1 */
356*4882a593Smuzhiyun regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE1 |
357*4882a593Smuzhiyun ((address >> 8) & 0xFF);
358*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
359*4882a593Smuzhiyun regval |= MC417_MICS | MC417_MIWR;
360*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun /* Indicate that this is a write. */
363*4882a593Smuzhiyun regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_MODE |
364*4882a593Smuzhiyun MCI_MODE_REGISTER_WRITE;
365*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
366*4882a593Smuzhiyun regval |= MC417_MICS | MC417_MIWR;
367*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
368*4882a593Smuzhiyun
369*4882a593Smuzhiyun /* Wait for the trans to complete (MC417_MIRDY asserted). */
370*4882a593Smuzhiyun return mc417_wait_ready(dev);
371*4882a593Smuzhiyun }
372*4882a593Smuzhiyun
mc417_register_read(struct cx23885_dev * dev,u16 address,u32 * value)373*4882a593Smuzhiyun int mc417_register_read(struct cx23885_dev *dev, u16 address, u32 *value)
374*4882a593Smuzhiyun {
375*4882a593Smuzhiyun int retval;
376*4882a593Smuzhiyun u32 regval;
377*4882a593Smuzhiyun u32 tempval;
378*4882a593Smuzhiyun u32 dataval;
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun /* Enable MC417 GPIO outputs except for MC417_MIRDY,
381*4882a593Smuzhiyun * which is an input.
382*4882a593Smuzhiyun */
383*4882a593Smuzhiyun cx_write(MC417_OEN, MC417_MIRDY);
384*4882a593Smuzhiyun
385*4882a593Smuzhiyun /* Write address byte 0 */
386*4882a593Smuzhiyun regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE0 |
387*4882a593Smuzhiyun ((address & 0x00FF));
388*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
389*4882a593Smuzhiyun regval |= MC417_MICS | MC417_MIWR;
390*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun /* Write address byte 1 */
393*4882a593Smuzhiyun regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE1 |
394*4882a593Smuzhiyun ((address >> 8) & 0xFF);
395*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
396*4882a593Smuzhiyun regval |= MC417_MICS | MC417_MIWR;
397*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
398*4882a593Smuzhiyun
399*4882a593Smuzhiyun /* Indicate that this is a register read. */
400*4882a593Smuzhiyun regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_MODE |
401*4882a593Smuzhiyun MCI_MODE_REGISTER_READ;
402*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
403*4882a593Smuzhiyun regval |= MC417_MICS | MC417_MIWR;
404*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
405*4882a593Smuzhiyun
406*4882a593Smuzhiyun /* Wait for the trans to complete (MC417_MIRDY asserted). */
407*4882a593Smuzhiyun retval = mc417_wait_ready(dev);
408*4882a593Smuzhiyun
409*4882a593Smuzhiyun /* switch the DAT0-7 GPIO[10:3] to input mode */
410*4882a593Smuzhiyun cx_write(MC417_OEN, MC417_MIRDY | MC417_MIDATA);
411*4882a593Smuzhiyun
412*4882a593Smuzhiyun /* Read data byte 0 */
413*4882a593Smuzhiyun regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE0;
414*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
415*4882a593Smuzhiyun
416*4882a593Smuzhiyun /* Transition RD to effect read transaction across bus.
417*4882a593Smuzhiyun * Transition 0x5000 -> 0x9000 correct (RD/RDY -> WR/RDY)?
418*4882a593Smuzhiyun * Should it be 0x9000 -> 0xF000 (also why is RDY being set, its
419*4882a593Smuzhiyun * input only...)
420*4882a593Smuzhiyun */
421*4882a593Smuzhiyun regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE0;
422*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
423*4882a593Smuzhiyun
424*4882a593Smuzhiyun /* Collect byte */
425*4882a593Smuzhiyun tempval = cx_read(MC417_RWD);
426*4882a593Smuzhiyun dataval = tempval & 0x000000FF;
427*4882a593Smuzhiyun
428*4882a593Smuzhiyun /* Bring CS and RD high. */
429*4882a593Smuzhiyun regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
430*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
431*4882a593Smuzhiyun
432*4882a593Smuzhiyun /* Read data byte 1 */
433*4882a593Smuzhiyun regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE1;
434*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
435*4882a593Smuzhiyun regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE1;
436*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
437*4882a593Smuzhiyun tempval = cx_read(MC417_RWD);
438*4882a593Smuzhiyun dataval |= ((tempval & 0x000000FF) << 8);
439*4882a593Smuzhiyun regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
440*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
441*4882a593Smuzhiyun
442*4882a593Smuzhiyun /* Read data byte 2 */
443*4882a593Smuzhiyun regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE2;
444*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
445*4882a593Smuzhiyun regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE2;
446*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
447*4882a593Smuzhiyun tempval = cx_read(MC417_RWD);
448*4882a593Smuzhiyun dataval |= ((tempval & 0x000000FF) << 16);
449*4882a593Smuzhiyun regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
450*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun /* Read data byte 3 */
453*4882a593Smuzhiyun regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE3;
454*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
455*4882a593Smuzhiyun regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE3;
456*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
457*4882a593Smuzhiyun tempval = cx_read(MC417_RWD);
458*4882a593Smuzhiyun dataval |= ((tempval & 0x000000FF) << 24);
459*4882a593Smuzhiyun regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
460*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
461*4882a593Smuzhiyun
462*4882a593Smuzhiyun *value = dataval;
463*4882a593Smuzhiyun
464*4882a593Smuzhiyun return retval;
465*4882a593Smuzhiyun }
466*4882a593Smuzhiyun
mc417_memory_write(struct cx23885_dev * dev,u32 address,u32 value)467*4882a593Smuzhiyun int mc417_memory_write(struct cx23885_dev *dev, u32 address, u32 value)
468*4882a593Smuzhiyun {
469*4882a593Smuzhiyun u32 regval;
470*4882a593Smuzhiyun
471*4882a593Smuzhiyun /* Enable MC417 GPIO outputs except for MC417_MIRDY,
472*4882a593Smuzhiyun * which is an input.
473*4882a593Smuzhiyun */
474*4882a593Smuzhiyun cx_write(MC417_OEN, MC417_MIRDY);
475*4882a593Smuzhiyun
476*4882a593Smuzhiyun /* Write data byte 0 */
477*4882a593Smuzhiyun regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE0 |
478*4882a593Smuzhiyun (value & 0x000000FF);
479*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
480*4882a593Smuzhiyun
481*4882a593Smuzhiyun /* Transition CS/WR to effect write transaction across bus. */
482*4882a593Smuzhiyun regval |= MC417_MICS | MC417_MIWR;
483*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
484*4882a593Smuzhiyun
485*4882a593Smuzhiyun /* Write data byte 1 */
486*4882a593Smuzhiyun regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE1 |
487*4882a593Smuzhiyun ((value >> 8) & 0x000000FF);
488*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
489*4882a593Smuzhiyun regval |= MC417_MICS | MC417_MIWR;
490*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
491*4882a593Smuzhiyun
492*4882a593Smuzhiyun /* Write data byte 2 */
493*4882a593Smuzhiyun regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE2 |
494*4882a593Smuzhiyun ((value >> 16) & 0x000000FF);
495*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
496*4882a593Smuzhiyun regval |= MC417_MICS | MC417_MIWR;
497*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
498*4882a593Smuzhiyun
499*4882a593Smuzhiyun /* Write data byte 3 */
500*4882a593Smuzhiyun regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE3 |
501*4882a593Smuzhiyun ((value >> 24) & 0x000000FF);
502*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
503*4882a593Smuzhiyun regval |= MC417_MICS | MC417_MIWR;
504*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
505*4882a593Smuzhiyun
506*4882a593Smuzhiyun /* Write address byte 2 */
507*4882a593Smuzhiyun regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE2 |
508*4882a593Smuzhiyun MCI_MODE_MEMORY_WRITE | ((address >> 16) & 0x3F);
509*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
510*4882a593Smuzhiyun regval |= MC417_MICS | MC417_MIWR;
511*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
512*4882a593Smuzhiyun
513*4882a593Smuzhiyun /* Write address byte 1 */
514*4882a593Smuzhiyun regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE1 |
515*4882a593Smuzhiyun ((address >> 8) & 0xFF);
516*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
517*4882a593Smuzhiyun regval |= MC417_MICS | MC417_MIWR;
518*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
519*4882a593Smuzhiyun
520*4882a593Smuzhiyun /* Write address byte 0 */
521*4882a593Smuzhiyun regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE0 |
522*4882a593Smuzhiyun (address & 0xFF);
523*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
524*4882a593Smuzhiyun regval |= MC417_MICS | MC417_MIWR;
525*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
526*4882a593Smuzhiyun
527*4882a593Smuzhiyun /* Wait for the trans to complete (MC417_MIRDY asserted). */
528*4882a593Smuzhiyun return mc417_wait_ready(dev);
529*4882a593Smuzhiyun }
530*4882a593Smuzhiyun
mc417_memory_read(struct cx23885_dev * dev,u32 address,u32 * value)531*4882a593Smuzhiyun int mc417_memory_read(struct cx23885_dev *dev, u32 address, u32 *value)
532*4882a593Smuzhiyun {
533*4882a593Smuzhiyun int retval;
534*4882a593Smuzhiyun u32 regval;
535*4882a593Smuzhiyun u32 tempval;
536*4882a593Smuzhiyun u32 dataval;
537*4882a593Smuzhiyun
538*4882a593Smuzhiyun /* Enable MC417 GPIO outputs except for MC417_MIRDY,
539*4882a593Smuzhiyun * which is an input.
540*4882a593Smuzhiyun */
541*4882a593Smuzhiyun cx_write(MC417_OEN, MC417_MIRDY);
542*4882a593Smuzhiyun
543*4882a593Smuzhiyun /* Write address byte 2 */
544*4882a593Smuzhiyun regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE2 |
545*4882a593Smuzhiyun MCI_MODE_MEMORY_READ | ((address >> 16) & 0x3F);
546*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
547*4882a593Smuzhiyun regval |= MC417_MICS | MC417_MIWR;
548*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
549*4882a593Smuzhiyun
550*4882a593Smuzhiyun /* Write address byte 1 */
551*4882a593Smuzhiyun regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE1 |
552*4882a593Smuzhiyun ((address >> 8) & 0xFF);
553*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
554*4882a593Smuzhiyun regval |= MC417_MICS | MC417_MIWR;
555*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
556*4882a593Smuzhiyun
557*4882a593Smuzhiyun /* Write address byte 0 */
558*4882a593Smuzhiyun regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE0 |
559*4882a593Smuzhiyun (address & 0xFF);
560*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
561*4882a593Smuzhiyun regval |= MC417_MICS | MC417_MIWR;
562*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
563*4882a593Smuzhiyun
564*4882a593Smuzhiyun /* Wait for the trans to complete (MC417_MIRDY asserted). */
565*4882a593Smuzhiyun retval = mc417_wait_ready(dev);
566*4882a593Smuzhiyun
567*4882a593Smuzhiyun /* switch the DAT0-7 GPIO[10:3] to input mode */
568*4882a593Smuzhiyun cx_write(MC417_OEN, MC417_MIRDY | MC417_MIDATA);
569*4882a593Smuzhiyun
570*4882a593Smuzhiyun /* Read data byte 3 */
571*4882a593Smuzhiyun regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE3;
572*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
573*4882a593Smuzhiyun
574*4882a593Smuzhiyun /* Transition RD to effect read transaction across bus. */
575*4882a593Smuzhiyun regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE3;
576*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
577*4882a593Smuzhiyun
578*4882a593Smuzhiyun /* Collect byte */
579*4882a593Smuzhiyun tempval = cx_read(MC417_RWD);
580*4882a593Smuzhiyun dataval = ((tempval & 0x000000FF) << 24);
581*4882a593Smuzhiyun
582*4882a593Smuzhiyun /* Bring CS and RD high. */
583*4882a593Smuzhiyun regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
584*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
585*4882a593Smuzhiyun
586*4882a593Smuzhiyun /* Read data byte 2 */
587*4882a593Smuzhiyun regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE2;
588*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
589*4882a593Smuzhiyun regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE2;
590*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
591*4882a593Smuzhiyun tempval = cx_read(MC417_RWD);
592*4882a593Smuzhiyun dataval |= ((tempval & 0x000000FF) << 16);
593*4882a593Smuzhiyun regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
594*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
595*4882a593Smuzhiyun
596*4882a593Smuzhiyun /* Read data byte 1 */
597*4882a593Smuzhiyun regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE1;
598*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
599*4882a593Smuzhiyun regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE1;
600*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
601*4882a593Smuzhiyun tempval = cx_read(MC417_RWD);
602*4882a593Smuzhiyun dataval |= ((tempval & 0x000000FF) << 8);
603*4882a593Smuzhiyun regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
604*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
605*4882a593Smuzhiyun
606*4882a593Smuzhiyun /* Read data byte 0 */
607*4882a593Smuzhiyun regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE0;
608*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
609*4882a593Smuzhiyun regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE0;
610*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
611*4882a593Smuzhiyun tempval = cx_read(MC417_RWD);
612*4882a593Smuzhiyun dataval |= (tempval & 0x000000FF);
613*4882a593Smuzhiyun regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
614*4882a593Smuzhiyun cx_write(MC417_RWD, regval);
615*4882a593Smuzhiyun
616*4882a593Smuzhiyun *value = dataval;
617*4882a593Smuzhiyun
618*4882a593Smuzhiyun return retval;
619*4882a593Smuzhiyun }
620*4882a593Smuzhiyun
mc417_gpio_set(struct cx23885_dev * dev,u32 mask)621*4882a593Smuzhiyun void mc417_gpio_set(struct cx23885_dev *dev, u32 mask)
622*4882a593Smuzhiyun {
623*4882a593Smuzhiyun u32 val;
624*4882a593Smuzhiyun
625*4882a593Smuzhiyun /* Set the gpio value */
626*4882a593Smuzhiyun mc417_register_read(dev, 0x900C, &val);
627*4882a593Smuzhiyun val |= (mask & 0x000ffff);
628*4882a593Smuzhiyun mc417_register_write(dev, 0x900C, val);
629*4882a593Smuzhiyun }
630*4882a593Smuzhiyun
mc417_gpio_clear(struct cx23885_dev * dev,u32 mask)631*4882a593Smuzhiyun void mc417_gpio_clear(struct cx23885_dev *dev, u32 mask)
632*4882a593Smuzhiyun {
633*4882a593Smuzhiyun u32 val;
634*4882a593Smuzhiyun
635*4882a593Smuzhiyun /* Clear the gpio value */
636*4882a593Smuzhiyun mc417_register_read(dev, 0x900C, &val);
637*4882a593Smuzhiyun val &= ~(mask & 0x0000ffff);
638*4882a593Smuzhiyun mc417_register_write(dev, 0x900C, val);
639*4882a593Smuzhiyun }
640*4882a593Smuzhiyun
mc417_gpio_enable(struct cx23885_dev * dev,u32 mask,int asoutput)641*4882a593Smuzhiyun void mc417_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput)
642*4882a593Smuzhiyun {
643*4882a593Smuzhiyun u32 val;
644*4882a593Smuzhiyun
645*4882a593Smuzhiyun /* Enable GPIO direction bits */
646*4882a593Smuzhiyun mc417_register_read(dev, 0x9020, &val);
647*4882a593Smuzhiyun if (asoutput)
648*4882a593Smuzhiyun val |= (mask & 0x0000ffff);
649*4882a593Smuzhiyun else
650*4882a593Smuzhiyun val &= ~(mask & 0x0000ffff);
651*4882a593Smuzhiyun
652*4882a593Smuzhiyun mc417_register_write(dev, 0x9020, val);
653*4882a593Smuzhiyun }
654*4882a593Smuzhiyun /* ------------------------------------------------------------------ */
655*4882a593Smuzhiyun
656*4882a593Smuzhiyun /* MPEG encoder API */
cmd_to_str(int cmd)657*4882a593Smuzhiyun static char *cmd_to_str(int cmd)
658*4882a593Smuzhiyun {
659*4882a593Smuzhiyun switch (cmd) {
660*4882a593Smuzhiyun case CX2341X_ENC_PING_FW:
661*4882a593Smuzhiyun return "PING_FW";
662*4882a593Smuzhiyun case CX2341X_ENC_START_CAPTURE:
663*4882a593Smuzhiyun return "START_CAPTURE";
664*4882a593Smuzhiyun case CX2341X_ENC_STOP_CAPTURE:
665*4882a593Smuzhiyun return "STOP_CAPTURE";
666*4882a593Smuzhiyun case CX2341X_ENC_SET_AUDIO_ID:
667*4882a593Smuzhiyun return "SET_AUDIO_ID";
668*4882a593Smuzhiyun case CX2341X_ENC_SET_VIDEO_ID:
669*4882a593Smuzhiyun return "SET_VIDEO_ID";
670*4882a593Smuzhiyun case CX2341X_ENC_SET_PCR_ID:
671*4882a593Smuzhiyun return "SET_PCR_ID";
672*4882a593Smuzhiyun case CX2341X_ENC_SET_FRAME_RATE:
673*4882a593Smuzhiyun return "SET_FRAME_RATE";
674*4882a593Smuzhiyun case CX2341X_ENC_SET_FRAME_SIZE:
675*4882a593Smuzhiyun return "SET_FRAME_SIZE";
676*4882a593Smuzhiyun case CX2341X_ENC_SET_BIT_RATE:
677*4882a593Smuzhiyun return "SET_BIT_RATE";
678*4882a593Smuzhiyun case CX2341X_ENC_SET_GOP_PROPERTIES:
679*4882a593Smuzhiyun return "SET_GOP_PROPERTIES";
680*4882a593Smuzhiyun case CX2341X_ENC_SET_ASPECT_RATIO:
681*4882a593Smuzhiyun return "SET_ASPECT_RATIO";
682*4882a593Smuzhiyun case CX2341X_ENC_SET_DNR_FILTER_MODE:
683*4882a593Smuzhiyun return "SET_DNR_FILTER_MODE";
684*4882a593Smuzhiyun case CX2341X_ENC_SET_DNR_FILTER_PROPS:
685*4882a593Smuzhiyun return "SET_DNR_FILTER_PROPS";
686*4882a593Smuzhiyun case CX2341X_ENC_SET_CORING_LEVELS:
687*4882a593Smuzhiyun return "SET_CORING_LEVELS";
688*4882a593Smuzhiyun case CX2341X_ENC_SET_SPATIAL_FILTER_TYPE:
689*4882a593Smuzhiyun return "SET_SPATIAL_FILTER_TYPE";
690*4882a593Smuzhiyun case CX2341X_ENC_SET_VBI_LINE:
691*4882a593Smuzhiyun return "SET_VBI_LINE";
692*4882a593Smuzhiyun case CX2341X_ENC_SET_STREAM_TYPE:
693*4882a593Smuzhiyun return "SET_STREAM_TYPE";
694*4882a593Smuzhiyun case CX2341X_ENC_SET_OUTPUT_PORT:
695*4882a593Smuzhiyun return "SET_OUTPUT_PORT";
696*4882a593Smuzhiyun case CX2341X_ENC_SET_AUDIO_PROPERTIES:
697*4882a593Smuzhiyun return "SET_AUDIO_PROPERTIES";
698*4882a593Smuzhiyun case CX2341X_ENC_HALT_FW:
699*4882a593Smuzhiyun return "HALT_FW";
700*4882a593Smuzhiyun case CX2341X_ENC_GET_VERSION:
701*4882a593Smuzhiyun return "GET_VERSION";
702*4882a593Smuzhiyun case CX2341X_ENC_SET_GOP_CLOSURE:
703*4882a593Smuzhiyun return "SET_GOP_CLOSURE";
704*4882a593Smuzhiyun case CX2341X_ENC_GET_SEQ_END:
705*4882a593Smuzhiyun return "GET_SEQ_END";
706*4882a593Smuzhiyun case CX2341X_ENC_SET_PGM_INDEX_INFO:
707*4882a593Smuzhiyun return "SET_PGM_INDEX_INFO";
708*4882a593Smuzhiyun case CX2341X_ENC_SET_VBI_CONFIG:
709*4882a593Smuzhiyun return "SET_VBI_CONFIG";
710*4882a593Smuzhiyun case CX2341X_ENC_SET_DMA_BLOCK_SIZE:
711*4882a593Smuzhiyun return "SET_DMA_BLOCK_SIZE";
712*4882a593Smuzhiyun case CX2341X_ENC_GET_PREV_DMA_INFO_MB_10:
713*4882a593Smuzhiyun return "GET_PREV_DMA_INFO_MB_10";
714*4882a593Smuzhiyun case CX2341X_ENC_GET_PREV_DMA_INFO_MB_9:
715*4882a593Smuzhiyun return "GET_PREV_DMA_INFO_MB_9";
716*4882a593Smuzhiyun case CX2341X_ENC_SCHED_DMA_TO_HOST:
717*4882a593Smuzhiyun return "SCHED_DMA_TO_HOST";
718*4882a593Smuzhiyun case CX2341X_ENC_INITIALIZE_INPUT:
719*4882a593Smuzhiyun return "INITIALIZE_INPUT";
720*4882a593Smuzhiyun case CX2341X_ENC_SET_FRAME_DROP_RATE:
721*4882a593Smuzhiyun return "SET_FRAME_DROP_RATE";
722*4882a593Smuzhiyun case CX2341X_ENC_PAUSE_ENCODER:
723*4882a593Smuzhiyun return "PAUSE_ENCODER";
724*4882a593Smuzhiyun case CX2341X_ENC_REFRESH_INPUT:
725*4882a593Smuzhiyun return "REFRESH_INPUT";
726*4882a593Smuzhiyun case CX2341X_ENC_SET_COPYRIGHT:
727*4882a593Smuzhiyun return "SET_COPYRIGHT";
728*4882a593Smuzhiyun case CX2341X_ENC_SET_EVENT_NOTIFICATION:
729*4882a593Smuzhiyun return "SET_EVENT_NOTIFICATION";
730*4882a593Smuzhiyun case CX2341X_ENC_SET_NUM_VSYNC_LINES:
731*4882a593Smuzhiyun return "SET_NUM_VSYNC_LINES";
732*4882a593Smuzhiyun case CX2341X_ENC_SET_PLACEHOLDER:
733*4882a593Smuzhiyun return "SET_PLACEHOLDER";
734*4882a593Smuzhiyun case CX2341X_ENC_MUTE_VIDEO:
735*4882a593Smuzhiyun return "MUTE_VIDEO";
736*4882a593Smuzhiyun case CX2341X_ENC_MUTE_AUDIO:
737*4882a593Smuzhiyun return "MUTE_AUDIO";
738*4882a593Smuzhiyun case CX2341X_ENC_MISC:
739*4882a593Smuzhiyun return "MISC";
740*4882a593Smuzhiyun default:
741*4882a593Smuzhiyun return "UNKNOWN";
742*4882a593Smuzhiyun }
743*4882a593Smuzhiyun }
744*4882a593Smuzhiyun
cx23885_mbox_func(void * priv,u32 command,int in,int out,u32 data[CX2341X_MBOX_MAX_DATA])745*4882a593Smuzhiyun static int cx23885_mbox_func(void *priv,
746*4882a593Smuzhiyun u32 command,
747*4882a593Smuzhiyun int in,
748*4882a593Smuzhiyun int out,
749*4882a593Smuzhiyun u32 data[CX2341X_MBOX_MAX_DATA])
750*4882a593Smuzhiyun {
751*4882a593Smuzhiyun struct cx23885_dev *dev = priv;
752*4882a593Smuzhiyun unsigned long timeout;
753*4882a593Smuzhiyun u32 value, flag, retval = 0;
754*4882a593Smuzhiyun int i;
755*4882a593Smuzhiyun
756*4882a593Smuzhiyun dprintk(3, "%s: command(0x%X) = %s\n", __func__, command,
757*4882a593Smuzhiyun cmd_to_str(command));
758*4882a593Smuzhiyun
759*4882a593Smuzhiyun /* this may not be 100% safe if we can't read any memory location
760*4882a593Smuzhiyun without side effects */
761*4882a593Smuzhiyun mc417_memory_read(dev, dev->cx23417_mailbox - 4, &value);
762*4882a593Smuzhiyun if (value != 0x12345678) {
763*4882a593Smuzhiyun pr_err("Firmware and/or mailbox pointer not initialized or corrupted, signature = 0x%x, cmd = %s\n",
764*4882a593Smuzhiyun value, cmd_to_str(command));
765*4882a593Smuzhiyun return -1;
766*4882a593Smuzhiyun }
767*4882a593Smuzhiyun
768*4882a593Smuzhiyun /* This read looks at 32 bits, but flag is only 8 bits.
769*4882a593Smuzhiyun * Seems we also bail if CMD or TIMEOUT bytes are set???
770*4882a593Smuzhiyun */
771*4882a593Smuzhiyun mc417_memory_read(dev, dev->cx23417_mailbox, &flag);
772*4882a593Smuzhiyun if (flag) {
773*4882a593Smuzhiyun pr_err("ERROR: Mailbox appears to be in use (%x), cmd = %s\n",
774*4882a593Smuzhiyun flag, cmd_to_str(command));
775*4882a593Smuzhiyun return -1;
776*4882a593Smuzhiyun }
777*4882a593Smuzhiyun
778*4882a593Smuzhiyun flag |= 1; /* tell 'em we're working on it */
779*4882a593Smuzhiyun mc417_memory_write(dev, dev->cx23417_mailbox, flag);
780*4882a593Smuzhiyun
781*4882a593Smuzhiyun /* write command + args + fill remaining with zeros */
782*4882a593Smuzhiyun /* command code */
783*4882a593Smuzhiyun mc417_memory_write(dev, dev->cx23417_mailbox + 1, command);
784*4882a593Smuzhiyun mc417_memory_write(dev, dev->cx23417_mailbox + 3,
785*4882a593Smuzhiyun IVTV_API_STD_TIMEOUT); /* timeout */
786*4882a593Smuzhiyun for (i = 0; i < in; i++) {
787*4882a593Smuzhiyun mc417_memory_write(dev, dev->cx23417_mailbox + 4 + i, data[i]);
788*4882a593Smuzhiyun dprintk(3, "API Input %d = %d\n", i, data[i]);
789*4882a593Smuzhiyun }
790*4882a593Smuzhiyun for (; i < CX2341X_MBOX_MAX_DATA; i++)
791*4882a593Smuzhiyun mc417_memory_write(dev, dev->cx23417_mailbox + 4 + i, 0);
792*4882a593Smuzhiyun
793*4882a593Smuzhiyun flag |= 3; /* tell 'em we're done writing */
794*4882a593Smuzhiyun mc417_memory_write(dev, dev->cx23417_mailbox, flag);
795*4882a593Smuzhiyun
796*4882a593Smuzhiyun /* wait for firmware to handle the API command */
797*4882a593Smuzhiyun timeout = jiffies + msecs_to_jiffies(10);
798*4882a593Smuzhiyun for (;;) {
799*4882a593Smuzhiyun mc417_memory_read(dev, dev->cx23417_mailbox, &flag);
800*4882a593Smuzhiyun if (0 != (flag & 4))
801*4882a593Smuzhiyun break;
802*4882a593Smuzhiyun if (time_after(jiffies, timeout)) {
803*4882a593Smuzhiyun pr_err("ERROR: API Mailbox timeout\n");
804*4882a593Smuzhiyun return -1;
805*4882a593Smuzhiyun }
806*4882a593Smuzhiyun udelay(10);
807*4882a593Smuzhiyun }
808*4882a593Smuzhiyun
809*4882a593Smuzhiyun /* read output values */
810*4882a593Smuzhiyun for (i = 0; i < out; i++) {
811*4882a593Smuzhiyun mc417_memory_read(dev, dev->cx23417_mailbox + 4 + i, data + i);
812*4882a593Smuzhiyun dprintk(3, "API Output %d = %d\n", i, data[i]);
813*4882a593Smuzhiyun }
814*4882a593Smuzhiyun
815*4882a593Smuzhiyun mc417_memory_read(dev, dev->cx23417_mailbox + 2, &retval);
816*4882a593Smuzhiyun dprintk(3, "API result = %d\n", retval);
817*4882a593Smuzhiyun
818*4882a593Smuzhiyun flag = 0;
819*4882a593Smuzhiyun mc417_memory_write(dev, dev->cx23417_mailbox, flag);
820*4882a593Smuzhiyun
821*4882a593Smuzhiyun return retval;
822*4882a593Smuzhiyun }
823*4882a593Smuzhiyun
824*4882a593Smuzhiyun /* We don't need to call the API often, so using just one
825*4882a593Smuzhiyun * mailbox will probably suffice
826*4882a593Smuzhiyun */
cx23885_api_cmd(struct cx23885_dev * dev,u32 command,u32 inputcnt,u32 outputcnt,...)827*4882a593Smuzhiyun static int cx23885_api_cmd(struct cx23885_dev *dev,
828*4882a593Smuzhiyun u32 command,
829*4882a593Smuzhiyun u32 inputcnt,
830*4882a593Smuzhiyun u32 outputcnt,
831*4882a593Smuzhiyun ...)
832*4882a593Smuzhiyun {
833*4882a593Smuzhiyun u32 data[CX2341X_MBOX_MAX_DATA];
834*4882a593Smuzhiyun va_list vargs;
835*4882a593Smuzhiyun int i, err;
836*4882a593Smuzhiyun
837*4882a593Smuzhiyun dprintk(3, "%s() cmds = 0x%08x\n", __func__, command);
838*4882a593Smuzhiyun
839*4882a593Smuzhiyun va_start(vargs, outputcnt);
840*4882a593Smuzhiyun for (i = 0; i < inputcnt; i++)
841*4882a593Smuzhiyun data[i] = va_arg(vargs, int);
842*4882a593Smuzhiyun
843*4882a593Smuzhiyun err = cx23885_mbox_func(dev, command, inputcnt, outputcnt, data);
844*4882a593Smuzhiyun for (i = 0; i < outputcnt; i++) {
845*4882a593Smuzhiyun int *vptr = va_arg(vargs, int *);
846*4882a593Smuzhiyun *vptr = data[i];
847*4882a593Smuzhiyun }
848*4882a593Smuzhiyun va_end(vargs);
849*4882a593Smuzhiyun
850*4882a593Smuzhiyun return err;
851*4882a593Smuzhiyun }
852*4882a593Smuzhiyun
cx23885_api_func(void * priv,u32 cmd,int in,int out,u32 data[CX2341X_MBOX_MAX_DATA])853*4882a593Smuzhiyun static int cx23885_api_func(void *priv, u32 cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA])
854*4882a593Smuzhiyun {
855*4882a593Smuzhiyun return cx23885_mbox_func(priv, cmd, in, out, data);
856*4882a593Smuzhiyun }
857*4882a593Smuzhiyun
cx23885_find_mailbox(struct cx23885_dev * dev)858*4882a593Smuzhiyun static int cx23885_find_mailbox(struct cx23885_dev *dev)
859*4882a593Smuzhiyun {
860*4882a593Smuzhiyun u32 signature[4] = {
861*4882a593Smuzhiyun 0x12345678, 0x34567812, 0x56781234, 0x78123456
862*4882a593Smuzhiyun };
863*4882a593Smuzhiyun int signaturecnt = 0;
864*4882a593Smuzhiyun u32 value;
865*4882a593Smuzhiyun int i;
866*4882a593Smuzhiyun
867*4882a593Smuzhiyun dprintk(2, "%s()\n", __func__);
868*4882a593Smuzhiyun
869*4882a593Smuzhiyun for (i = 0; i < CX23885_FIRM_IMAGE_SIZE; i++) {
870*4882a593Smuzhiyun mc417_memory_read(dev, i, &value);
871*4882a593Smuzhiyun if (value == signature[signaturecnt])
872*4882a593Smuzhiyun signaturecnt++;
873*4882a593Smuzhiyun else
874*4882a593Smuzhiyun signaturecnt = 0;
875*4882a593Smuzhiyun if (4 == signaturecnt) {
876*4882a593Smuzhiyun dprintk(1, "Mailbox signature found at 0x%x\n", i+1);
877*4882a593Smuzhiyun return i+1;
878*4882a593Smuzhiyun }
879*4882a593Smuzhiyun }
880*4882a593Smuzhiyun pr_err("Mailbox signature values not found!\n");
881*4882a593Smuzhiyun return -1;
882*4882a593Smuzhiyun }
883*4882a593Smuzhiyun
cx23885_load_firmware(struct cx23885_dev * dev)884*4882a593Smuzhiyun static int cx23885_load_firmware(struct cx23885_dev *dev)
885*4882a593Smuzhiyun {
886*4882a593Smuzhiyun static const unsigned char magic[8] = {
887*4882a593Smuzhiyun 0xa7, 0x0d, 0x00, 0x00, 0x66, 0xbb, 0x55, 0xaa
888*4882a593Smuzhiyun };
889*4882a593Smuzhiyun const struct firmware *firmware;
890*4882a593Smuzhiyun int i, retval = 0;
891*4882a593Smuzhiyun u32 value = 0;
892*4882a593Smuzhiyun u32 gpio_output = 0;
893*4882a593Smuzhiyun u32 gpio_value;
894*4882a593Smuzhiyun u32 checksum = 0;
895*4882a593Smuzhiyun u32 *dataptr;
896*4882a593Smuzhiyun
897*4882a593Smuzhiyun dprintk(2, "%s()\n", __func__);
898*4882a593Smuzhiyun
899*4882a593Smuzhiyun /* Save GPIO settings before reset of APU */
900*4882a593Smuzhiyun retval |= mc417_memory_read(dev, 0x9020, &gpio_output);
901*4882a593Smuzhiyun retval |= mc417_memory_read(dev, 0x900C, &gpio_value);
902*4882a593Smuzhiyun
903*4882a593Smuzhiyun retval = mc417_register_write(dev,
904*4882a593Smuzhiyun IVTV_REG_VPU, 0xFFFFFFED);
905*4882a593Smuzhiyun retval |= mc417_register_write(dev,
906*4882a593Smuzhiyun IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST);
907*4882a593Smuzhiyun retval |= mc417_register_write(dev,
908*4882a593Smuzhiyun IVTV_REG_ENC_SDRAM_REFRESH, 0x80000800);
909*4882a593Smuzhiyun retval |= mc417_register_write(dev,
910*4882a593Smuzhiyun IVTV_REG_ENC_SDRAM_PRECHARGE, 0x1A);
911*4882a593Smuzhiyun retval |= mc417_register_write(dev,
912*4882a593Smuzhiyun IVTV_REG_APU, 0);
913*4882a593Smuzhiyun
914*4882a593Smuzhiyun if (retval != 0) {
915*4882a593Smuzhiyun pr_err("%s: Error with mc417_register_write\n",
916*4882a593Smuzhiyun __func__);
917*4882a593Smuzhiyun return -1;
918*4882a593Smuzhiyun }
919*4882a593Smuzhiyun
920*4882a593Smuzhiyun retval = request_firmware(&firmware, CX23885_FIRM_IMAGE_NAME,
921*4882a593Smuzhiyun &dev->pci->dev);
922*4882a593Smuzhiyun
923*4882a593Smuzhiyun if (retval != 0) {
924*4882a593Smuzhiyun pr_err("ERROR: Hotplug firmware request failed (%s).\n",
925*4882a593Smuzhiyun CX23885_FIRM_IMAGE_NAME);
926*4882a593Smuzhiyun pr_err("Please fix your hotplug setup, the board will not work without firmware loaded!\n");
927*4882a593Smuzhiyun return -1;
928*4882a593Smuzhiyun }
929*4882a593Smuzhiyun
930*4882a593Smuzhiyun if (firmware->size != CX23885_FIRM_IMAGE_SIZE) {
931*4882a593Smuzhiyun pr_err("ERROR: Firmware size mismatch (have %zu, expected %d)\n",
932*4882a593Smuzhiyun firmware->size, CX23885_FIRM_IMAGE_SIZE);
933*4882a593Smuzhiyun release_firmware(firmware);
934*4882a593Smuzhiyun return -1;
935*4882a593Smuzhiyun }
936*4882a593Smuzhiyun
937*4882a593Smuzhiyun if (0 != memcmp(firmware->data, magic, 8)) {
938*4882a593Smuzhiyun pr_err("ERROR: Firmware magic mismatch, wrong file?\n");
939*4882a593Smuzhiyun release_firmware(firmware);
940*4882a593Smuzhiyun return -1;
941*4882a593Smuzhiyun }
942*4882a593Smuzhiyun
943*4882a593Smuzhiyun /* transfer to the chip */
944*4882a593Smuzhiyun dprintk(2, "Loading firmware ...\n");
945*4882a593Smuzhiyun dataptr = (u32 *)firmware->data;
946*4882a593Smuzhiyun for (i = 0; i < (firmware->size >> 2); i++) {
947*4882a593Smuzhiyun value = *dataptr;
948*4882a593Smuzhiyun checksum += ~value;
949*4882a593Smuzhiyun if (mc417_memory_write(dev, i, value) != 0) {
950*4882a593Smuzhiyun pr_err("ERROR: Loading firmware failed!\n");
951*4882a593Smuzhiyun release_firmware(firmware);
952*4882a593Smuzhiyun return -1;
953*4882a593Smuzhiyun }
954*4882a593Smuzhiyun dataptr++;
955*4882a593Smuzhiyun }
956*4882a593Smuzhiyun
957*4882a593Smuzhiyun /* read back to verify with the checksum */
958*4882a593Smuzhiyun dprintk(1, "Verifying firmware ...\n");
959*4882a593Smuzhiyun for (i--; i >= 0; i--) {
960*4882a593Smuzhiyun if (mc417_memory_read(dev, i, &value) != 0) {
961*4882a593Smuzhiyun pr_err("ERROR: Reading firmware failed!\n");
962*4882a593Smuzhiyun release_firmware(firmware);
963*4882a593Smuzhiyun return -1;
964*4882a593Smuzhiyun }
965*4882a593Smuzhiyun checksum -= ~value;
966*4882a593Smuzhiyun }
967*4882a593Smuzhiyun if (checksum) {
968*4882a593Smuzhiyun pr_err("ERROR: Firmware load failed (checksum mismatch).\n");
969*4882a593Smuzhiyun release_firmware(firmware);
970*4882a593Smuzhiyun return -1;
971*4882a593Smuzhiyun }
972*4882a593Smuzhiyun release_firmware(firmware);
973*4882a593Smuzhiyun dprintk(1, "Firmware upload successful.\n");
974*4882a593Smuzhiyun
975*4882a593Smuzhiyun retval |= mc417_register_write(dev, IVTV_REG_HW_BLOCKS,
976*4882a593Smuzhiyun IVTV_CMD_HW_BLOCKS_RST);
977*4882a593Smuzhiyun
978*4882a593Smuzhiyun /* F/W power up disturbs the GPIOs, restore state */
979*4882a593Smuzhiyun retval |= mc417_register_write(dev, 0x9020, gpio_output);
980*4882a593Smuzhiyun retval |= mc417_register_write(dev, 0x900C, gpio_value);
981*4882a593Smuzhiyun
982*4882a593Smuzhiyun retval |= mc417_register_read(dev, IVTV_REG_VPU, &value);
983*4882a593Smuzhiyun retval |= mc417_register_write(dev, IVTV_REG_VPU, value & 0xFFFFFFE8);
984*4882a593Smuzhiyun
985*4882a593Smuzhiyun /* Hardcoded GPIO's here */
986*4882a593Smuzhiyun retval |= mc417_register_write(dev, 0x9020, 0x4000);
987*4882a593Smuzhiyun retval |= mc417_register_write(dev, 0x900C, 0x4000);
988*4882a593Smuzhiyun
989*4882a593Smuzhiyun mc417_register_read(dev, 0x9020, &gpio_output);
990*4882a593Smuzhiyun mc417_register_read(dev, 0x900C, &gpio_value);
991*4882a593Smuzhiyun
992*4882a593Smuzhiyun if (retval < 0)
993*4882a593Smuzhiyun pr_err("%s: Error with mc417_register_write\n",
994*4882a593Smuzhiyun __func__);
995*4882a593Smuzhiyun return 0;
996*4882a593Smuzhiyun }
997*4882a593Smuzhiyun
cx23885_417_check_encoder(struct cx23885_dev * dev)998*4882a593Smuzhiyun void cx23885_417_check_encoder(struct cx23885_dev *dev)
999*4882a593Smuzhiyun {
1000*4882a593Smuzhiyun u32 status, seq;
1001*4882a593Smuzhiyun
1002*4882a593Smuzhiyun status = seq = 0;
1003*4882a593Smuzhiyun cx23885_api_cmd(dev, CX2341X_ENC_GET_SEQ_END, 0, 2, &status, &seq);
1004*4882a593Smuzhiyun dprintk(1, "%s() status = %d, seq = %d\n", __func__, status, seq);
1005*4882a593Smuzhiyun }
1006*4882a593Smuzhiyun
cx23885_codec_settings(struct cx23885_dev * dev)1007*4882a593Smuzhiyun static void cx23885_codec_settings(struct cx23885_dev *dev)
1008*4882a593Smuzhiyun {
1009*4882a593Smuzhiyun dprintk(1, "%s()\n", __func__);
1010*4882a593Smuzhiyun
1011*4882a593Smuzhiyun /* Dynamically change the height based on video standard */
1012*4882a593Smuzhiyun if (dev->encodernorm.id & V4L2_STD_525_60)
1013*4882a593Smuzhiyun dev->ts1.height = 480;
1014*4882a593Smuzhiyun else
1015*4882a593Smuzhiyun dev->ts1.height = 576;
1016*4882a593Smuzhiyun
1017*4882a593Smuzhiyun /* assign frame size */
1018*4882a593Smuzhiyun cx23885_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0,
1019*4882a593Smuzhiyun dev->ts1.height, dev->ts1.width);
1020*4882a593Smuzhiyun
1021*4882a593Smuzhiyun dev->cxhdl.width = dev->ts1.width;
1022*4882a593Smuzhiyun dev->cxhdl.height = dev->ts1.height;
1023*4882a593Smuzhiyun dev->cxhdl.is_50hz =
1024*4882a593Smuzhiyun (dev->encodernorm.id & V4L2_STD_625_50) != 0;
1025*4882a593Smuzhiyun
1026*4882a593Smuzhiyun cx2341x_handler_setup(&dev->cxhdl);
1027*4882a593Smuzhiyun
1028*4882a593Smuzhiyun cx23885_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 3, 1);
1029*4882a593Smuzhiyun cx23885_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 4, 1);
1030*4882a593Smuzhiyun }
1031*4882a593Smuzhiyun
cx23885_initialize_codec(struct cx23885_dev * dev,int startencoder)1032*4882a593Smuzhiyun static int cx23885_initialize_codec(struct cx23885_dev *dev, int startencoder)
1033*4882a593Smuzhiyun {
1034*4882a593Smuzhiyun int version;
1035*4882a593Smuzhiyun int retval;
1036*4882a593Smuzhiyun u32 i, data[7];
1037*4882a593Smuzhiyun
1038*4882a593Smuzhiyun dprintk(1, "%s()\n", __func__);
1039*4882a593Smuzhiyun
1040*4882a593Smuzhiyun retval = cx23885_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */
1041*4882a593Smuzhiyun if (retval < 0) {
1042*4882a593Smuzhiyun dprintk(2, "%s() PING OK\n", __func__);
1043*4882a593Smuzhiyun retval = cx23885_load_firmware(dev);
1044*4882a593Smuzhiyun if (retval < 0) {
1045*4882a593Smuzhiyun pr_err("%s() f/w load failed\n", __func__);
1046*4882a593Smuzhiyun return retval;
1047*4882a593Smuzhiyun }
1048*4882a593Smuzhiyun retval = cx23885_find_mailbox(dev);
1049*4882a593Smuzhiyun if (retval < 0) {
1050*4882a593Smuzhiyun pr_err("%s() mailbox < 0, error\n",
1051*4882a593Smuzhiyun __func__);
1052*4882a593Smuzhiyun return -1;
1053*4882a593Smuzhiyun }
1054*4882a593Smuzhiyun dev->cx23417_mailbox = retval;
1055*4882a593Smuzhiyun retval = cx23885_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0);
1056*4882a593Smuzhiyun if (retval < 0) {
1057*4882a593Smuzhiyun pr_err("ERROR: cx23417 firmware ping failed!\n");
1058*4882a593Smuzhiyun return -1;
1059*4882a593Smuzhiyun }
1060*4882a593Smuzhiyun retval = cx23885_api_cmd(dev, CX2341X_ENC_GET_VERSION, 0, 1,
1061*4882a593Smuzhiyun &version);
1062*4882a593Smuzhiyun if (retval < 0) {
1063*4882a593Smuzhiyun pr_err("ERROR: cx23417 firmware get encoder :version failed!\n");
1064*4882a593Smuzhiyun return -1;
1065*4882a593Smuzhiyun }
1066*4882a593Smuzhiyun dprintk(1, "cx23417 firmware version is 0x%08x\n", version);
1067*4882a593Smuzhiyun msleep(200);
1068*4882a593Smuzhiyun }
1069*4882a593Smuzhiyun
1070*4882a593Smuzhiyun cx23885_codec_settings(dev);
1071*4882a593Smuzhiyun msleep(60);
1072*4882a593Smuzhiyun
1073*4882a593Smuzhiyun cx23885_api_cmd(dev, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, 0,
1074*4882a593Smuzhiyun CX23885_FIELD1_SAA7115, CX23885_FIELD2_SAA7115);
1075*4882a593Smuzhiyun cx23885_api_cmd(dev, CX2341X_ENC_SET_PLACEHOLDER, 12, 0,
1076*4882a593Smuzhiyun CX23885_CUSTOM_EXTENSION_USR_DATA, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1077*4882a593Smuzhiyun 0, 0);
1078*4882a593Smuzhiyun
1079*4882a593Smuzhiyun /* Setup to capture VBI */
1080*4882a593Smuzhiyun data[0] = 0x0001BD00;
1081*4882a593Smuzhiyun data[1] = 1; /* frames per interrupt */
1082*4882a593Smuzhiyun data[2] = 4; /* total bufs */
1083*4882a593Smuzhiyun data[3] = 0x91559155; /* start codes */
1084*4882a593Smuzhiyun data[4] = 0x206080C0; /* stop codes */
1085*4882a593Smuzhiyun data[5] = 6; /* lines */
1086*4882a593Smuzhiyun data[6] = 64; /* BPL */
1087*4882a593Smuzhiyun
1088*4882a593Smuzhiyun cx23885_api_cmd(dev, CX2341X_ENC_SET_VBI_CONFIG, 7, 0, data[0], data[1],
1089*4882a593Smuzhiyun data[2], data[3], data[4], data[5], data[6]);
1090*4882a593Smuzhiyun
1091*4882a593Smuzhiyun for (i = 2; i <= 24; i++) {
1092*4882a593Smuzhiyun int valid;
1093*4882a593Smuzhiyun
1094*4882a593Smuzhiyun valid = ((i >= 19) && (i <= 21));
1095*4882a593Smuzhiyun cx23885_api_cmd(dev, CX2341X_ENC_SET_VBI_LINE, 5, 0, i,
1096*4882a593Smuzhiyun valid, 0 , 0, 0);
1097*4882a593Smuzhiyun cx23885_api_cmd(dev, CX2341X_ENC_SET_VBI_LINE, 5, 0,
1098*4882a593Smuzhiyun i | 0x80000000, valid, 0, 0, 0);
1099*4882a593Smuzhiyun }
1100*4882a593Smuzhiyun
1101*4882a593Smuzhiyun cx23885_api_cmd(dev, CX2341X_ENC_MUTE_AUDIO, 1, 0, CX23885_UNMUTE);
1102*4882a593Smuzhiyun msleep(60);
1103*4882a593Smuzhiyun
1104*4882a593Smuzhiyun /* initialize the video input */
1105*4882a593Smuzhiyun cx23885_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0);
1106*4882a593Smuzhiyun msleep(60);
1107*4882a593Smuzhiyun
1108*4882a593Smuzhiyun /* Enable VIP style pixel invalidation so we work with scaled mode */
1109*4882a593Smuzhiyun mc417_memory_write(dev, 2120, 0x00000080);
1110*4882a593Smuzhiyun
1111*4882a593Smuzhiyun /* start capturing to the host interface */
1112*4882a593Smuzhiyun if (startencoder) {
1113*4882a593Smuzhiyun cx23885_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0,
1114*4882a593Smuzhiyun CX23885_MPEG_CAPTURE, CX23885_RAW_BITS_NONE);
1115*4882a593Smuzhiyun msleep(10);
1116*4882a593Smuzhiyun }
1117*4882a593Smuzhiyun
1118*4882a593Smuzhiyun return 0;
1119*4882a593Smuzhiyun }
1120*4882a593Smuzhiyun
1121*4882a593Smuzhiyun /* ------------------------------------------------------------------ */
1122*4882a593Smuzhiyun
queue_setup(struct vb2_queue * q,unsigned int * num_buffers,unsigned int * num_planes,unsigned int sizes[],struct device * alloc_devs[])1123*4882a593Smuzhiyun static int queue_setup(struct vb2_queue *q,
1124*4882a593Smuzhiyun unsigned int *num_buffers, unsigned int *num_planes,
1125*4882a593Smuzhiyun unsigned int sizes[], struct device *alloc_devs[])
1126*4882a593Smuzhiyun {
1127*4882a593Smuzhiyun struct cx23885_dev *dev = q->drv_priv;
1128*4882a593Smuzhiyun
1129*4882a593Smuzhiyun dev->ts1.ts_packet_size = mpeglinesize;
1130*4882a593Smuzhiyun dev->ts1.ts_packet_count = mpeglines;
1131*4882a593Smuzhiyun *num_planes = 1;
1132*4882a593Smuzhiyun sizes[0] = mpeglinesize * mpeglines;
1133*4882a593Smuzhiyun *num_buffers = mpegbufs;
1134*4882a593Smuzhiyun return 0;
1135*4882a593Smuzhiyun }
1136*4882a593Smuzhiyun
buffer_prepare(struct vb2_buffer * vb)1137*4882a593Smuzhiyun static int buffer_prepare(struct vb2_buffer *vb)
1138*4882a593Smuzhiyun {
1139*4882a593Smuzhiyun struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1140*4882a593Smuzhiyun struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
1141*4882a593Smuzhiyun struct cx23885_buffer *buf =
1142*4882a593Smuzhiyun container_of(vbuf, struct cx23885_buffer, vb);
1143*4882a593Smuzhiyun
1144*4882a593Smuzhiyun return cx23885_buf_prepare(buf, &dev->ts1);
1145*4882a593Smuzhiyun }
1146*4882a593Smuzhiyun
buffer_finish(struct vb2_buffer * vb)1147*4882a593Smuzhiyun static void buffer_finish(struct vb2_buffer *vb)
1148*4882a593Smuzhiyun {
1149*4882a593Smuzhiyun struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1150*4882a593Smuzhiyun struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
1151*4882a593Smuzhiyun struct cx23885_buffer *buf = container_of(vbuf,
1152*4882a593Smuzhiyun struct cx23885_buffer, vb);
1153*4882a593Smuzhiyun
1154*4882a593Smuzhiyun cx23885_free_buffer(dev, buf);
1155*4882a593Smuzhiyun }
1156*4882a593Smuzhiyun
buffer_queue(struct vb2_buffer * vb)1157*4882a593Smuzhiyun static void buffer_queue(struct vb2_buffer *vb)
1158*4882a593Smuzhiyun {
1159*4882a593Smuzhiyun struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1160*4882a593Smuzhiyun struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
1161*4882a593Smuzhiyun struct cx23885_buffer *buf = container_of(vbuf,
1162*4882a593Smuzhiyun struct cx23885_buffer, vb);
1163*4882a593Smuzhiyun
1164*4882a593Smuzhiyun cx23885_buf_queue(&dev->ts1, buf);
1165*4882a593Smuzhiyun }
1166*4882a593Smuzhiyun
cx23885_start_streaming(struct vb2_queue * q,unsigned int count)1167*4882a593Smuzhiyun static int cx23885_start_streaming(struct vb2_queue *q, unsigned int count)
1168*4882a593Smuzhiyun {
1169*4882a593Smuzhiyun struct cx23885_dev *dev = q->drv_priv;
1170*4882a593Smuzhiyun struct cx23885_dmaqueue *dmaq = &dev->ts1.mpegq;
1171*4882a593Smuzhiyun unsigned long flags;
1172*4882a593Smuzhiyun int ret;
1173*4882a593Smuzhiyun
1174*4882a593Smuzhiyun ret = cx23885_initialize_codec(dev, 1);
1175*4882a593Smuzhiyun if (ret == 0) {
1176*4882a593Smuzhiyun struct cx23885_buffer *buf = list_entry(dmaq->active.next,
1177*4882a593Smuzhiyun struct cx23885_buffer, queue);
1178*4882a593Smuzhiyun
1179*4882a593Smuzhiyun cx23885_start_dma(&dev->ts1, dmaq, buf);
1180*4882a593Smuzhiyun return 0;
1181*4882a593Smuzhiyun }
1182*4882a593Smuzhiyun spin_lock_irqsave(&dev->slock, flags);
1183*4882a593Smuzhiyun while (!list_empty(&dmaq->active)) {
1184*4882a593Smuzhiyun struct cx23885_buffer *buf = list_entry(dmaq->active.next,
1185*4882a593Smuzhiyun struct cx23885_buffer, queue);
1186*4882a593Smuzhiyun
1187*4882a593Smuzhiyun list_del(&buf->queue);
1188*4882a593Smuzhiyun vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED);
1189*4882a593Smuzhiyun }
1190*4882a593Smuzhiyun spin_unlock_irqrestore(&dev->slock, flags);
1191*4882a593Smuzhiyun return ret;
1192*4882a593Smuzhiyun }
1193*4882a593Smuzhiyun
cx23885_stop_streaming(struct vb2_queue * q)1194*4882a593Smuzhiyun static void cx23885_stop_streaming(struct vb2_queue *q)
1195*4882a593Smuzhiyun {
1196*4882a593Smuzhiyun struct cx23885_dev *dev = q->drv_priv;
1197*4882a593Smuzhiyun
1198*4882a593Smuzhiyun /* stop mpeg capture */
1199*4882a593Smuzhiyun cx23885_api_cmd(dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
1200*4882a593Smuzhiyun CX23885_END_NOW, CX23885_MPEG_CAPTURE,
1201*4882a593Smuzhiyun CX23885_RAW_BITS_NONE);
1202*4882a593Smuzhiyun
1203*4882a593Smuzhiyun msleep(500);
1204*4882a593Smuzhiyun cx23885_417_check_encoder(dev);
1205*4882a593Smuzhiyun cx23885_cancel_buffers(&dev->ts1);
1206*4882a593Smuzhiyun }
1207*4882a593Smuzhiyun
1208*4882a593Smuzhiyun static const struct vb2_ops cx23885_qops = {
1209*4882a593Smuzhiyun .queue_setup = queue_setup,
1210*4882a593Smuzhiyun .buf_prepare = buffer_prepare,
1211*4882a593Smuzhiyun .buf_finish = buffer_finish,
1212*4882a593Smuzhiyun .buf_queue = buffer_queue,
1213*4882a593Smuzhiyun .wait_prepare = vb2_ops_wait_prepare,
1214*4882a593Smuzhiyun .wait_finish = vb2_ops_wait_finish,
1215*4882a593Smuzhiyun .start_streaming = cx23885_start_streaming,
1216*4882a593Smuzhiyun .stop_streaming = cx23885_stop_streaming,
1217*4882a593Smuzhiyun };
1218*4882a593Smuzhiyun
1219*4882a593Smuzhiyun /* ------------------------------------------------------------------ */
1220*4882a593Smuzhiyun
vidioc_g_std(struct file * file,void * priv,v4l2_std_id * id)1221*4882a593Smuzhiyun static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
1222*4882a593Smuzhiyun {
1223*4882a593Smuzhiyun struct cx23885_dev *dev = video_drvdata(file);
1224*4882a593Smuzhiyun
1225*4882a593Smuzhiyun *id = dev->tvnorm;
1226*4882a593Smuzhiyun return 0;
1227*4882a593Smuzhiyun }
1228*4882a593Smuzhiyun
vidioc_s_std(struct file * file,void * priv,v4l2_std_id id)1229*4882a593Smuzhiyun static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id)
1230*4882a593Smuzhiyun {
1231*4882a593Smuzhiyun struct cx23885_dev *dev = video_drvdata(file);
1232*4882a593Smuzhiyun unsigned int i;
1233*4882a593Smuzhiyun int ret;
1234*4882a593Smuzhiyun
1235*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(cx23885_tvnorms); i++)
1236*4882a593Smuzhiyun if (id & cx23885_tvnorms[i].id)
1237*4882a593Smuzhiyun break;
1238*4882a593Smuzhiyun if (i == ARRAY_SIZE(cx23885_tvnorms))
1239*4882a593Smuzhiyun return -EINVAL;
1240*4882a593Smuzhiyun
1241*4882a593Smuzhiyun ret = cx23885_set_tvnorm(dev, id);
1242*4882a593Smuzhiyun if (!ret)
1243*4882a593Smuzhiyun dev->encodernorm = cx23885_tvnorms[i];
1244*4882a593Smuzhiyun return ret;
1245*4882a593Smuzhiyun }
1246*4882a593Smuzhiyun
vidioc_enum_input(struct file * file,void * priv,struct v4l2_input * i)1247*4882a593Smuzhiyun static int vidioc_enum_input(struct file *file, void *priv,
1248*4882a593Smuzhiyun struct v4l2_input *i)
1249*4882a593Smuzhiyun {
1250*4882a593Smuzhiyun struct cx23885_dev *dev = video_drvdata(file);
1251*4882a593Smuzhiyun dprintk(1, "%s()\n", __func__);
1252*4882a593Smuzhiyun return cx23885_enum_input(dev, i);
1253*4882a593Smuzhiyun }
1254*4882a593Smuzhiyun
vidioc_g_input(struct file * file,void * priv,unsigned int * i)1255*4882a593Smuzhiyun static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
1256*4882a593Smuzhiyun {
1257*4882a593Smuzhiyun return cx23885_get_input(file, priv, i);
1258*4882a593Smuzhiyun }
1259*4882a593Smuzhiyun
vidioc_s_input(struct file * file,void * priv,unsigned int i)1260*4882a593Smuzhiyun static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
1261*4882a593Smuzhiyun {
1262*4882a593Smuzhiyun return cx23885_set_input(file, priv, i);
1263*4882a593Smuzhiyun }
1264*4882a593Smuzhiyun
vidioc_g_tuner(struct file * file,void * priv,struct v4l2_tuner * t)1265*4882a593Smuzhiyun static int vidioc_g_tuner(struct file *file, void *priv,
1266*4882a593Smuzhiyun struct v4l2_tuner *t)
1267*4882a593Smuzhiyun {
1268*4882a593Smuzhiyun struct cx23885_dev *dev = video_drvdata(file);
1269*4882a593Smuzhiyun
1270*4882a593Smuzhiyun if (dev->tuner_type == TUNER_ABSENT)
1271*4882a593Smuzhiyun return -EINVAL;
1272*4882a593Smuzhiyun if (0 != t->index)
1273*4882a593Smuzhiyun return -EINVAL;
1274*4882a593Smuzhiyun strscpy(t->name, "Television", sizeof(t->name));
1275*4882a593Smuzhiyun call_all(dev, tuner, g_tuner, t);
1276*4882a593Smuzhiyun
1277*4882a593Smuzhiyun dprintk(1, "VIDIOC_G_TUNER: tuner type %d\n", t->type);
1278*4882a593Smuzhiyun
1279*4882a593Smuzhiyun return 0;
1280*4882a593Smuzhiyun }
1281*4882a593Smuzhiyun
vidioc_s_tuner(struct file * file,void * priv,const struct v4l2_tuner * t)1282*4882a593Smuzhiyun static int vidioc_s_tuner(struct file *file, void *priv,
1283*4882a593Smuzhiyun const struct v4l2_tuner *t)
1284*4882a593Smuzhiyun {
1285*4882a593Smuzhiyun struct cx23885_dev *dev = video_drvdata(file);
1286*4882a593Smuzhiyun
1287*4882a593Smuzhiyun if (dev->tuner_type == TUNER_ABSENT)
1288*4882a593Smuzhiyun return -EINVAL;
1289*4882a593Smuzhiyun
1290*4882a593Smuzhiyun /* Update the A/V core */
1291*4882a593Smuzhiyun call_all(dev, tuner, s_tuner, t);
1292*4882a593Smuzhiyun
1293*4882a593Smuzhiyun return 0;
1294*4882a593Smuzhiyun }
1295*4882a593Smuzhiyun
vidioc_g_frequency(struct file * file,void * priv,struct v4l2_frequency * f)1296*4882a593Smuzhiyun static int vidioc_g_frequency(struct file *file, void *priv,
1297*4882a593Smuzhiyun struct v4l2_frequency *f)
1298*4882a593Smuzhiyun {
1299*4882a593Smuzhiyun struct cx23885_dev *dev = video_drvdata(file);
1300*4882a593Smuzhiyun
1301*4882a593Smuzhiyun if (dev->tuner_type == TUNER_ABSENT)
1302*4882a593Smuzhiyun return -EINVAL;
1303*4882a593Smuzhiyun f->type = V4L2_TUNER_ANALOG_TV;
1304*4882a593Smuzhiyun f->frequency = dev->freq;
1305*4882a593Smuzhiyun
1306*4882a593Smuzhiyun call_all(dev, tuner, g_frequency, f);
1307*4882a593Smuzhiyun
1308*4882a593Smuzhiyun return 0;
1309*4882a593Smuzhiyun }
1310*4882a593Smuzhiyun
vidioc_s_frequency(struct file * file,void * priv,const struct v4l2_frequency * f)1311*4882a593Smuzhiyun static int vidioc_s_frequency(struct file *file, void *priv,
1312*4882a593Smuzhiyun const struct v4l2_frequency *f)
1313*4882a593Smuzhiyun {
1314*4882a593Smuzhiyun return cx23885_set_frequency(file, priv, f);
1315*4882a593Smuzhiyun }
1316*4882a593Smuzhiyun
vidioc_querycap(struct file * file,void * priv,struct v4l2_capability * cap)1317*4882a593Smuzhiyun static int vidioc_querycap(struct file *file, void *priv,
1318*4882a593Smuzhiyun struct v4l2_capability *cap)
1319*4882a593Smuzhiyun {
1320*4882a593Smuzhiyun struct cx23885_dev *dev = video_drvdata(file);
1321*4882a593Smuzhiyun struct cx23885_tsport *tsport = &dev->ts1;
1322*4882a593Smuzhiyun
1323*4882a593Smuzhiyun strscpy(cap->driver, dev->name, sizeof(cap->driver));
1324*4882a593Smuzhiyun strscpy(cap->card, cx23885_boards[tsport->dev->board].name,
1325*4882a593Smuzhiyun sizeof(cap->card));
1326*4882a593Smuzhiyun sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci));
1327*4882a593Smuzhiyun cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
1328*4882a593Smuzhiyun V4L2_CAP_STREAMING | V4L2_CAP_VBI_CAPTURE |
1329*4882a593Smuzhiyun V4L2_CAP_AUDIO | V4L2_CAP_DEVICE_CAPS;
1330*4882a593Smuzhiyun if (dev->tuner_type != TUNER_ABSENT)
1331*4882a593Smuzhiyun cap->capabilities |= V4L2_CAP_TUNER;
1332*4882a593Smuzhiyun
1333*4882a593Smuzhiyun return 0;
1334*4882a593Smuzhiyun }
1335*4882a593Smuzhiyun
vidioc_enum_fmt_vid_cap(struct file * file,void * priv,struct v4l2_fmtdesc * f)1336*4882a593Smuzhiyun static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
1337*4882a593Smuzhiyun struct v4l2_fmtdesc *f)
1338*4882a593Smuzhiyun {
1339*4882a593Smuzhiyun if (f->index != 0)
1340*4882a593Smuzhiyun return -EINVAL;
1341*4882a593Smuzhiyun
1342*4882a593Smuzhiyun f->pixelformat = V4L2_PIX_FMT_MPEG;
1343*4882a593Smuzhiyun
1344*4882a593Smuzhiyun return 0;
1345*4882a593Smuzhiyun }
1346*4882a593Smuzhiyun
vidioc_g_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)1347*4882a593Smuzhiyun static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
1348*4882a593Smuzhiyun struct v4l2_format *f)
1349*4882a593Smuzhiyun {
1350*4882a593Smuzhiyun struct cx23885_dev *dev = video_drvdata(file);
1351*4882a593Smuzhiyun
1352*4882a593Smuzhiyun f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
1353*4882a593Smuzhiyun f->fmt.pix.bytesperline = 0;
1354*4882a593Smuzhiyun f->fmt.pix.sizeimage =
1355*4882a593Smuzhiyun dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
1356*4882a593Smuzhiyun f->fmt.pix.colorspace = 0;
1357*4882a593Smuzhiyun f->fmt.pix.width = dev->ts1.width;
1358*4882a593Smuzhiyun f->fmt.pix.height = dev->ts1.height;
1359*4882a593Smuzhiyun f->fmt.pix.field = V4L2_FIELD_INTERLACED;
1360*4882a593Smuzhiyun dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d\n",
1361*4882a593Smuzhiyun dev->ts1.width, dev->ts1.height);
1362*4882a593Smuzhiyun return 0;
1363*4882a593Smuzhiyun }
1364*4882a593Smuzhiyun
vidioc_try_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)1365*4882a593Smuzhiyun static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
1366*4882a593Smuzhiyun struct v4l2_format *f)
1367*4882a593Smuzhiyun {
1368*4882a593Smuzhiyun struct cx23885_dev *dev = video_drvdata(file);
1369*4882a593Smuzhiyun
1370*4882a593Smuzhiyun f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
1371*4882a593Smuzhiyun f->fmt.pix.bytesperline = 0;
1372*4882a593Smuzhiyun f->fmt.pix.sizeimage =
1373*4882a593Smuzhiyun dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
1374*4882a593Smuzhiyun f->fmt.pix.colorspace = 0;
1375*4882a593Smuzhiyun f->fmt.pix.field = V4L2_FIELD_INTERLACED;
1376*4882a593Smuzhiyun dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d\n",
1377*4882a593Smuzhiyun dev->ts1.width, dev->ts1.height);
1378*4882a593Smuzhiyun return 0;
1379*4882a593Smuzhiyun }
1380*4882a593Smuzhiyun
vidioc_s_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)1381*4882a593Smuzhiyun static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
1382*4882a593Smuzhiyun struct v4l2_format *f)
1383*4882a593Smuzhiyun {
1384*4882a593Smuzhiyun struct cx23885_dev *dev = video_drvdata(file);
1385*4882a593Smuzhiyun
1386*4882a593Smuzhiyun f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
1387*4882a593Smuzhiyun f->fmt.pix.bytesperline = 0;
1388*4882a593Smuzhiyun f->fmt.pix.sizeimage =
1389*4882a593Smuzhiyun dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
1390*4882a593Smuzhiyun f->fmt.pix.colorspace = 0;
1391*4882a593Smuzhiyun f->fmt.pix.field = V4L2_FIELD_INTERLACED;
1392*4882a593Smuzhiyun dprintk(1, "VIDIOC_S_FMT: w: %d, h: %d, f: %d\n",
1393*4882a593Smuzhiyun f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field);
1394*4882a593Smuzhiyun return 0;
1395*4882a593Smuzhiyun }
1396*4882a593Smuzhiyun
vidioc_log_status(struct file * file,void * priv)1397*4882a593Smuzhiyun static int vidioc_log_status(struct file *file, void *priv)
1398*4882a593Smuzhiyun {
1399*4882a593Smuzhiyun struct cx23885_dev *dev = video_drvdata(file);
1400*4882a593Smuzhiyun char name[32 + 2];
1401*4882a593Smuzhiyun
1402*4882a593Smuzhiyun snprintf(name, sizeof(name), "%s/2", dev->name);
1403*4882a593Smuzhiyun call_all(dev, core, log_status);
1404*4882a593Smuzhiyun v4l2_ctrl_handler_log_status(&dev->cxhdl.hdl, name);
1405*4882a593Smuzhiyun return 0;
1406*4882a593Smuzhiyun }
1407*4882a593Smuzhiyun
1408*4882a593Smuzhiyun static const struct v4l2_file_operations mpeg_fops = {
1409*4882a593Smuzhiyun .owner = THIS_MODULE,
1410*4882a593Smuzhiyun .open = v4l2_fh_open,
1411*4882a593Smuzhiyun .release = vb2_fop_release,
1412*4882a593Smuzhiyun .read = vb2_fop_read,
1413*4882a593Smuzhiyun .poll = vb2_fop_poll,
1414*4882a593Smuzhiyun .unlocked_ioctl = video_ioctl2,
1415*4882a593Smuzhiyun .mmap = vb2_fop_mmap,
1416*4882a593Smuzhiyun };
1417*4882a593Smuzhiyun
1418*4882a593Smuzhiyun static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
1419*4882a593Smuzhiyun .vidioc_g_std = vidioc_g_std,
1420*4882a593Smuzhiyun .vidioc_s_std = vidioc_s_std,
1421*4882a593Smuzhiyun .vidioc_enum_input = vidioc_enum_input,
1422*4882a593Smuzhiyun .vidioc_g_input = vidioc_g_input,
1423*4882a593Smuzhiyun .vidioc_s_input = vidioc_s_input,
1424*4882a593Smuzhiyun .vidioc_g_tuner = vidioc_g_tuner,
1425*4882a593Smuzhiyun .vidioc_s_tuner = vidioc_s_tuner,
1426*4882a593Smuzhiyun .vidioc_g_frequency = vidioc_g_frequency,
1427*4882a593Smuzhiyun .vidioc_s_frequency = vidioc_s_frequency,
1428*4882a593Smuzhiyun .vidioc_querycap = vidioc_querycap,
1429*4882a593Smuzhiyun .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
1430*4882a593Smuzhiyun .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
1431*4882a593Smuzhiyun .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
1432*4882a593Smuzhiyun .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
1433*4882a593Smuzhiyun .vidioc_reqbufs = vb2_ioctl_reqbufs,
1434*4882a593Smuzhiyun .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
1435*4882a593Smuzhiyun .vidioc_querybuf = vb2_ioctl_querybuf,
1436*4882a593Smuzhiyun .vidioc_qbuf = vb2_ioctl_qbuf,
1437*4882a593Smuzhiyun .vidioc_dqbuf = vb2_ioctl_dqbuf,
1438*4882a593Smuzhiyun .vidioc_streamon = vb2_ioctl_streamon,
1439*4882a593Smuzhiyun .vidioc_streamoff = vb2_ioctl_streamoff,
1440*4882a593Smuzhiyun .vidioc_log_status = vidioc_log_status,
1441*4882a593Smuzhiyun #ifdef CONFIG_VIDEO_ADV_DEBUG
1442*4882a593Smuzhiyun .vidioc_g_chip_info = cx23885_g_chip_info,
1443*4882a593Smuzhiyun .vidioc_g_register = cx23885_g_register,
1444*4882a593Smuzhiyun .vidioc_s_register = cx23885_s_register,
1445*4882a593Smuzhiyun #endif
1446*4882a593Smuzhiyun };
1447*4882a593Smuzhiyun
1448*4882a593Smuzhiyun static struct video_device cx23885_mpeg_template = {
1449*4882a593Smuzhiyun .name = "cx23885",
1450*4882a593Smuzhiyun .fops = &mpeg_fops,
1451*4882a593Smuzhiyun .ioctl_ops = &mpeg_ioctl_ops,
1452*4882a593Smuzhiyun .tvnorms = CX23885_NORMS,
1453*4882a593Smuzhiyun };
1454*4882a593Smuzhiyun
cx23885_417_unregister(struct cx23885_dev * dev)1455*4882a593Smuzhiyun void cx23885_417_unregister(struct cx23885_dev *dev)
1456*4882a593Smuzhiyun {
1457*4882a593Smuzhiyun dprintk(1, "%s()\n", __func__);
1458*4882a593Smuzhiyun
1459*4882a593Smuzhiyun if (dev->v4l_device) {
1460*4882a593Smuzhiyun if (video_is_registered(dev->v4l_device))
1461*4882a593Smuzhiyun video_unregister_device(dev->v4l_device);
1462*4882a593Smuzhiyun else
1463*4882a593Smuzhiyun video_device_release(dev->v4l_device);
1464*4882a593Smuzhiyun v4l2_ctrl_handler_free(&dev->cxhdl.hdl);
1465*4882a593Smuzhiyun dev->v4l_device = NULL;
1466*4882a593Smuzhiyun }
1467*4882a593Smuzhiyun }
1468*4882a593Smuzhiyun
cx23885_video_dev_alloc(struct cx23885_tsport * tsport,struct pci_dev * pci,struct video_device * template,char * type)1469*4882a593Smuzhiyun static struct video_device *cx23885_video_dev_alloc(
1470*4882a593Smuzhiyun struct cx23885_tsport *tsport,
1471*4882a593Smuzhiyun struct pci_dev *pci,
1472*4882a593Smuzhiyun struct video_device *template,
1473*4882a593Smuzhiyun char *type)
1474*4882a593Smuzhiyun {
1475*4882a593Smuzhiyun struct video_device *vfd;
1476*4882a593Smuzhiyun struct cx23885_dev *dev = tsport->dev;
1477*4882a593Smuzhiyun
1478*4882a593Smuzhiyun dprintk(1, "%s()\n", __func__);
1479*4882a593Smuzhiyun
1480*4882a593Smuzhiyun vfd = video_device_alloc();
1481*4882a593Smuzhiyun if (NULL == vfd)
1482*4882a593Smuzhiyun return NULL;
1483*4882a593Smuzhiyun *vfd = *template;
1484*4882a593Smuzhiyun snprintf(vfd->name, sizeof(vfd->name), "%s (%s)",
1485*4882a593Smuzhiyun cx23885_boards[tsport->dev->board].name, type);
1486*4882a593Smuzhiyun vfd->v4l2_dev = &dev->v4l2_dev;
1487*4882a593Smuzhiyun vfd->release = video_device_release;
1488*4882a593Smuzhiyun return vfd;
1489*4882a593Smuzhiyun }
1490*4882a593Smuzhiyun
cx23885_417_register(struct cx23885_dev * dev)1491*4882a593Smuzhiyun int cx23885_417_register(struct cx23885_dev *dev)
1492*4882a593Smuzhiyun {
1493*4882a593Smuzhiyun /* FIXME: Port1 hardcoded here */
1494*4882a593Smuzhiyun int err = -ENODEV;
1495*4882a593Smuzhiyun struct cx23885_tsport *tsport = &dev->ts1;
1496*4882a593Smuzhiyun struct vb2_queue *q;
1497*4882a593Smuzhiyun
1498*4882a593Smuzhiyun dprintk(1, "%s()\n", __func__);
1499*4882a593Smuzhiyun
1500*4882a593Smuzhiyun if (cx23885_boards[dev->board].portb != CX23885_MPEG_ENCODER)
1501*4882a593Smuzhiyun return err;
1502*4882a593Smuzhiyun
1503*4882a593Smuzhiyun /* Set default TV standard */
1504*4882a593Smuzhiyun dev->encodernorm = cx23885_tvnorms[0];
1505*4882a593Smuzhiyun
1506*4882a593Smuzhiyun if (dev->encodernorm.id & V4L2_STD_525_60)
1507*4882a593Smuzhiyun tsport->height = 480;
1508*4882a593Smuzhiyun else
1509*4882a593Smuzhiyun tsport->height = 576;
1510*4882a593Smuzhiyun
1511*4882a593Smuzhiyun tsport->width = 720;
1512*4882a593Smuzhiyun dev->cxhdl.port = CX2341X_PORT_SERIAL;
1513*4882a593Smuzhiyun err = cx2341x_handler_init(&dev->cxhdl, 50);
1514*4882a593Smuzhiyun if (err)
1515*4882a593Smuzhiyun return err;
1516*4882a593Smuzhiyun dev->cxhdl.priv = dev;
1517*4882a593Smuzhiyun dev->cxhdl.func = cx23885_api_func;
1518*4882a593Smuzhiyun cx2341x_handler_set_50hz(&dev->cxhdl, tsport->height == 576);
1519*4882a593Smuzhiyun v4l2_ctrl_add_handler(&dev->ctrl_handler, &dev->cxhdl.hdl, NULL, false);
1520*4882a593Smuzhiyun
1521*4882a593Smuzhiyun /* Allocate and initialize V4L video device */
1522*4882a593Smuzhiyun dev->v4l_device = cx23885_video_dev_alloc(tsport,
1523*4882a593Smuzhiyun dev->pci, &cx23885_mpeg_template, "mpeg");
1524*4882a593Smuzhiyun q = &dev->vb2_mpegq;
1525*4882a593Smuzhiyun q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1526*4882a593Smuzhiyun q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
1527*4882a593Smuzhiyun q->gfp_flags = GFP_DMA32;
1528*4882a593Smuzhiyun q->min_buffers_needed = 2;
1529*4882a593Smuzhiyun q->drv_priv = dev;
1530*4882a593Smuzhiyun q->buf_struct_size = sizeof(struct cx23885_buffer);
1531*4882a593Smuzhiyun q->ops = &cx23885_qops;
1532*4882a593Smuzhiyun q->mem_ops = &vb2_dma_sg_memops;
1533*4882a593Smuzhiyun q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
1534*4882a593Smuzhiyun q->lock = &dev->lock;
1535*4882a593Smuzhiyun q->dev = &dev->pci->dev;
1536*4882a593Smuzhiyun
1537*4882a593Smuzhiyun err = vb2_queue_init(q);
1538*4882a593Smuzhiyun if (err < 0)
1539*4882a593Smuzhiyun return err;
1540*4882a593Smuzhiyun video_set_drvdata(dev->v4l_device, dev);
1541*4882a593Smuzhiyun dev->v4l_device->lock = &dev->lock;
1542*4882a593Smuzhiyun dev->v4l_device->queue = q;
1543*4882a593Smuzhiyun dev->v4l_device->device_caps = V4L2_CAP_VIDEO_CAPTURE |
1544*4882a593Smuzhiyun V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
1545*4882a593Smuzhiyun if (dev->tuner_type != TUNER_ABSENT)
1546*4882a593Smuzhiyun dev->v4l_device->device_caps |= V4L2_CAP_TUNER;
1547*4882a593Smuzhiyun err = video_register_device(dev->v4l_device,
1548*4882a593Smuzhiyun VFL_TYPE_VIDEO, -1);
1549*4882a593Smuzhiyun if (err < 0) {
1550*4882a593Smuzhiyun pr_info("%s: can't register mpeg device\n", dev->name);
1551*4882a593Smuzhiyun return err;
1552*4882a593Smuzhiyun }
1553*4882a593Smuzhiyun
1554*4882a593Smuzhiyun pr_info("%s: registered device %s [mpeg]\n",
1555*4882a593Smuzhiyun dev->name, video_device_node_name(dev->v4l_device));
1556*4882a593Smuzhiyun
1557*4882a593Smuzhiyun /* ST: Configure the encoder parameters, but don't begin
1558*4882a593Smuzhiyun * encoding, this resolves an issue where the first time the
1559*4882a593Smuzhiyun * encoder is started video can be choppy.
1560*4882a593Smuzhiyun */
1561*4882a593Smuzhiyun cx23885_initialize_codec(dev, 0);
1562*4882a593Smuzhiyun
1563*4882a593Smuzhiyun return 0;
1564*4882a593Smuzhiyun }
1565*4882a593Smuzhiyun
1566*4882a593Smuzhiyun MODULE_FIRMWARE(CX23885_FIRM_IMAGE_NAME);
1567