📄 cx23885-417.c
字号:
/* * * Support for a cx23417 mpeg encoder via cx23885 host port. * * (c) 2004 Jelle Foks <jelle@foks.8m.com> * (c) 2004 Gerd Knorr <kraxel@bytesex.org> * (c) 2008 Steven Toth <stoth@linuxtv.org> * - CX23885/7/8 support * * Includes parts from the ivtv driver( http://ivtv.sourceforge.net/), * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/init.h>#include <linux/fs.h>#include <linux/delay.h>#include <linux/device.h>#include <linux/firmware.h>#include <media/v4l2-common.h>#include <media/v4l2-ioctl.h>#include <media/cx2341x.h>#include "cx23885.h"#define CX23885_FIRM_IMAGE_SIZE 376836#define CX23885_FIRM_IMAGE_NAME "v4l-cx23885-enc.fw"static unsigned int mpegbufs = 32;module_param(mpegbufs, int, 0644);MODULE_PARM_DESC(mpegbufs, "number of mpeg buffers, range 2-32");static unsigned int mpeglines = 32;module_param(mpeglines, int, 0644);MODULE_PARM_DESC(mpeglines, "number of lines in an MPEG buffer, range 2-32");static unsigned int mpeglinesize = 512;module_param(mpeglinesize, int, 0644);MODULE_PARM_DESC(mpeglinesize, "number of bytes in each line of an MPEG buffer, range 512-1024");static unsigned int v4l_debug;module_param(v4l_debug, int, 0644);MODULE_PARM_DESC(v4l_debug, "enable V4L debug messages");#define dprintk(level, fmt, arg...)\ do { if (v4l_debug >= level) \ printk(KERN_DEBUG "%s: " fmt, dev->name , ## arg);\ } while (0)static struct cx23885_tvnorm cx23885_tvnorms[] = { { .name = "NTSC-M", .id = V4L2_STD_NTSC_M, }, { .name = "NTSC-JP", .id = V4L2_STD_NTSC_M_JP, }, { .name = "PAL-BG", .id = V4L2_STD_PAL_BG, }, { .name = "PAL-DK", .id = V4L2_STD_PAL_DK, }, { .name = "PAL-I", .id = V4L2_STD_PAL_I, }, { .name = "PAL-M", .id = V4L2_STD_PAL_M, }, { .name = "PAL-N", .id = V4L2_STD_PAL_N, }, { .name = "PAL-Nc", .id = V4L2_STD_PAL_Nc, }, { .name = "PAL-60", .id = V4L2_STD_PAL_60, }, { .name = "SECAM-L", .id = V4L2_STD_SECAM_L, }, { .name = "SECAM-DK", .id = V4L2_STD_SECAM_DK, }};/* ------------------------------------------------------------------ */enum cx23885_capture_type { CX23885_MPEG_CAPTURE, CX23885_RAW_CAPTURE, CX23885_RAW_PASSTHRU_CAPTURE};enum cx23885_capture_bits { CX23885_RAW_BITS_NONE = 0x00, CX23885_RAW_BITS_YUV_CAPTURE = 0x01, CX23885_RAW_BITS_PCM_CAPTURE = 0x02, CX23885_RAW_BITS_VBI_CAPTURE = 0x04, CX23885_RAW_BITS_PASSTHRU_CAPTURE = 0x08, CX23885_RAW_BITS_TO_HOST_CAPTURE = 0x10};enum cx23885_capture_end { CX23885_END_AT_GOP, /* stop at the end of gop, generate irq */ CX23885_END_NOW, /* stop immediately, no irq */};enum cx23885_framerate { CX23885_FRAMERATE_NTSC_30, /* NTSC: 30fps */ CX23885_FRAMERATE_PAL_25 /* PAL: 25fps */};enum cx23885_stream_port { CX23885_OUTPUT_PORT_MEMORY, CX23885_OUTPUT_PORT_STREAMING, CX23885_OUTPUT_PORT_SERIAL};enum cx23885_data_xfer_status { CX23885_MORE_BUFFERS_FOLLOW, CX23885_LAST_BUFFER,};enum cx23885_picture_mask { CX23885_PICTURE_MASK_NONE, CX23885_PICTURE_MASK_I_FRAMES, CX23885_PICTURE_MASK_I_P_FRAMES = 0x3, CX23885_PICTURE_MASK_ALL_FRAMES = 0x7,};enum cx23885_vbi_mode_bits { CX23885_VBI_BITS_SLICED, CX23885_VBI_BITS_RAW,};enum cx23885_vbi_insertion_bits { CX23885_VBI_BITS_INSERT_IN_XTENSION_USR_DATA, CX23885_VBI_BITS_INSERT_IN_PRIVATE_PACKETS = 0x1 << 1, CX23885_VBI_BITS_SEPARATE_STREAM = 0x2 << 1, CX23885_VBI_BITS_SEPARATE_STREAM_USR_DATA = 0x4 << 1, CX23885_VBI_BITS_SEPARATE_STREAM_PRV_DATA = 0x5 << 1,};enum cx23885_dma_unit { CX23885_DMA_BYTES, CX23885_DMA_FRAMES,};enum cx23885_dma_transfer_status_bits { CX23885_DMA_TRANSFER_BITS_DONE = 0x01, CX23885_DMA_TRANSFER_BITS_ERROR = 0x04, CX23885_DMA_TRANSFER_BITS_LL_ERROR = 0x10,};enum cx23885_pause { CX23885_PAUSE_ENCODING, CX23885_RESUME_ENCODING,};enum cx23885_copyright { CX23885_COPYRIGHT_OFF, CX23885_COPYRIGHT_ON,};enum cx23885_notification_type { CX23885_NOTIFICATION_REFRESH,};enum cx23885_notification_status { CX23885_NOTIFICATION_OFF, CX23885_NOTIFICATION_ON,};enum cx23885_notification_mailbox { CX23885_NOTIFICATION_NO_MAILBOX = -1,};enum cx23885_field1_lines { CX23885_FIELD1_SAA7114 = 0x00EF, /* 239 */ CX23885_FIELD1_SAA7115 = 0x00F0, /* 240 */ CX23885_FIELD1_MICRONAS = 0x0105, /* 261 */};enum cx23885_field2_lines { CX23885_FIELD2_SAA7114 = 0x00EF, /* 239 */ CX23885_FIELD2_SAA7115 = 0x00F0, /* 240 */ CX23885_FIELD2_MICRONAS = 0x0106, /* 262 */};enum cx23885_custom_data_type { CX23885_CUSTOM_EXTENSION_USR_DATA, CX23885_CUSTOM_PRIVATE_PACKET,};enum cx23885_mute { CX23885_UNMUTE, CX23885_MUTE,};enum cx23885_mute_video_mask { CX23885_MUTE_VIDEO_V_MASK = 0x0000FF00, CX23885_MUTE_VIDEO_U_MASK = 0x00FF0000, CX23885_MUTE_VIDEO_Y_MASK = 0xFF000000,};enum cx23885_mute_video_shift { CX23885_MUTE_VIDEO_V_SHIFT = 8, CX23885_MUTE_VIDEO_U_SHIFT = 16, CX23885_MUTE_VIDEO_Y_SHIFT = 24,};/* defines below are from ivtv-driver.h */#define IVTV_CMD_HW_BLOCKS_RST 0xFFFFFFFF/* Firmware API commands */#define IVTV_API_STD_TIMEOUT 500/* Registers *//* IVTV_REG_OFFSET */#define IVTV_REG_ENC_SDRAM_REFRESH (0x07F8)#define IVTV_REG_ENC_SDRAM_PRECHARGE (0x07FC)#define IVTV_REG_SPU (0x9050)#define IVTV_REG_HW_BLOCKS (0x9054)#define IVTV_REG_VPU (0x9058)#define IVTV_REG_APU (0xA064)/**** Bit definitions for MC417_RWD and MC417_OEN registers *** bits 31-16+-----------+| Reserved |+-----------+ bit 15 bit 14 bit 13 bit 12 bit 11 bit 10 bit 9 bit 8+-------+-------+-------+-------+-------+-------+-------+-------+| MIWR# | MIRD# | MICS# |MIRDY# |MIADDR3|MIADDR2|MIADDR1|MIADDR0|+-------+-------+-------+-------+-------+-------+-------+-------+ bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0+-------+-------+-------+-------+-------+-------+-------+-------+|MIDATA7|MIDATA6|MIDATA5|MIDATA4|MIDATA3|MIDATA2|MIDATA1|MIDATA0|+-------+-------+-------+-------+-------+-------+-------+-------+***/#define MC417_MIWR 0x8000#define MC417_MIRD 0x4000#define MC417_MICS 0x2000#define MC417_MIRDY 0x1000#define MC417_MIADDR 0x0F00#define MC417_MIDATA 0x00FF/* MIADDR* nibble definitions */#define MCI_MEMORY_DATA_BYTE0 0x000#define MCI_MEMORY_DATA_BYTE1 0x100#define MCI_MEMORY_DATA_BYTE2 0x200#define MCI_MEMORY_DATA_BYTE3 0x300#define MCI_MEMORY_ADDRESS_BYTE2 0x400#define MCI_MEMORY_ADDRESS_BYTE1 0x500#define MCI_MEMORY_ADDRESS_BYTE0 0x600#define MCI_REGISTER_DATA_BYTE0 0x800#define MCI_REGISTER_DATA_BYTE1 0x900#define MCI_REGISTER_DATA_BYTE2 0xA00#define MCI_REGISTER_DATA_BYTE3 0xB00#define MCI_REGISTER_ADDRESS_BYTE0 0xC00#define MCI_REGISTER_ADDRESS_BYTE1 0xD00#define MCI_REGISTER_MODE 0xE00/* Read and write modes */#define MCI_MODE_REGISTER_READ 0#define MCI_MODE_REGISTER_WRITE 1#define MCI_MODE_MEMORY_READ 0#define MCI_MODE_MEMORY_WRITE 0x40/*** Bit definitions for MC417_CTL register **** bits 31-6 bits 5-4 bit 3 bits 2-1 Bit 0+--------+-------------+--------+--------------+------------+|Reserved|MC417_SPD_CTL|Reserved|MC417_GPIO_SEL|UART_GPIO_EN|+--------+-------------+--------+--------------+------------+***/#define MC417_SPD_CTL(x) (((x) << 4) & 0x00000030)#define MC417_GPIO_SEL(x) (((x) << 1) & 0x00000006)#define MC417_UART_GPIO_EN 0x00000001/* Values for speed control */#define MC417_SPD_CTL_SLOW 0x1#define MC417_SPD_CTL_MEDIUM 0x0#define MC417_SPD_CTL_FAST 0x3 /* b'1x, but we use b'11 *//* Values for GPIO select */#define MC417_GPIO_SEL_GPIO3 0x3#define MC417_GPIO_SEL_GPIO2 0x2#define MC417_GPIO_SEL_GPIO1 0x1#define MC417_GPIO_SEL_GPIO0 0x0void cx23885_mc417_init(struct cx23885_dev *dev){ u32 regval; dprintk(2, "%s()\n", __func__); /* Configure MC417_CTL register to defaults. */ regval = MC417_SPD_CTL(MC417_SPD_CTL_FAST) | MC417_GPIO_SEL(MC417_GPIO_SEL_GPIO3) | MC417_UART_GPIO_EN; cx_write(MC417_CTL, regval); /* Configure MC417_OEN to defaults. */ regval = MC417_MIRDY; cx_write(MC417_OEN, regval); /* Configure MC417_RWD to defaults. */ regval = MC417_MIWR | MC417_MIRD | MC417_MICS; cx_write(MC417_RWD, regval);}static int mc417_wait_ready(struct cx23885_dev *dev){ u32 mi_ready; unsigned long timeout = jiffies + msecs_to_jiffies(1); for (;;) { mi_ready = cx_read(MC417_RWD) & MC417_MIRDY; if (mi_ready != 0) return 0; if (time_after(jiffies, timeout)) return -1; udelay(1); }}static int mc417_register_write(struct cx23885_dev *dev, u16 address, u32 value){ u32 regval; /* Enable MC417 GPIO outputs except for MC417_MIRDY, * which is an input. */ cx_write(MC417_OEN, MC417_MIRDY); /* Write data byte 0 */ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE0 | (value & 0x000000FF); cx_write(MC417_RWD, regval); /* Transition CS/WR to effect write transaction across bus. */ regval |= MC417_MICS | MC417_MIWR; cx_write(MC417_RWD, regval); /* Write data byte 1 */ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE1 | ((value >> 8) & 0x000000FF); cx_write(MC417_RWD, regval); regval |= MC417_MICS | MC417_MIWR; cx_write(MC417_RWD, regval); /* Write data byte 2 */ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE2 | ((value >> 16) & 0x000000FF); cx_write(MC417_RWD, regval); regval |= MC417_MICS | MC417_MIWR; cx_write(MC417_RWD, regval); /* Write data byte 3 */ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE3 | ((value >> 24) & 0x000000FF); cx_write(MC417_RWD, regval); regval |= MC417_MICS | MC417_MIWR; cx_write(MC417_RWD, regval); /* Write address byte 0 */ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE0 | (address & 0xFF); cx_write(MC417_RWD, regval); regval |= MC417_MICS | MC417_MIWR; cx_write(MC417_RWD, regval); /* Write address byte 1 */ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE1 | ((address >> 8) & 0xFF); cx_write(MC417_RWD, regval); regval |= MC417_MICS | MC417_MIWR; cx_write(MC417_RWD, regval); /* Indicate that this is a write. */ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_MODE | MCI_MODE_REGISTER_WRITE; cx_write(MC417_RWD, regval); regval |= MC417_MICS | MC417_MIWR; cx_write(MC417_RWD, regval); /* Wait for the trans to complete (MC417_MIRDY asserted). */ return mc417_wait_ready(dev);}static int mc417_register_read(struct cx23885_dev *dev, u16 address, u32 *value){ int retval; u32 regval; u32 tempval; u32 dataval; /* Enable MC417 GPIO outputs except for MC417_MIRDY, * which is an input. */ cx_write(MC417_OEN, MC417_MIRDY); /* Write address byte 0 */ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE0 | ((address & 0x00FF)); cx_write(MC417_RWD, regval); regval |= MC417_MICS | MC417_MIWR; cx_write(MC417_RWD, regval); /* Write address byte 1 */ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE1 | ((address >> 8) & 0xFF); cx_write(MC417_RWD, regval); regval |= MC417_MICS | MC417_MIWR; cx_write(MC417_RWD, regval); /* Indicate that this is a register read. */ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_MODE | MCI_MODE_REGISTER_READ; cx_write(MC417_RWD, regval); regval |= MC417_MICS | MC417_MIWR; cx_write(MC417_RWD, regval); /* Wait for the trans to complete (MC417_MIRDY asserted). */ retval = mc417_wait_ready(dev); /* switch the DAT0-7 GPIO[10:3] to input mode */ cx_write(MC417_OEN, MC417_MIRDY | MC417_MIDATA); /* Read data byte 0 */ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE0; cx_write(MC417_RWD, regval); /* Transition RD to effect read transaction across bus. * Transtion 0x5000 -> 0x9000 correct (RD/RDY -> WR/RDY)? * Should it be 0x9000 -> 0xF000 (also why is RDY being set, its * input only...) */ regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE0; cx_write(MC417_RWD, regval); /* Collect byte */ tempval = cx_read(MC417_RWD); dataval = tempval & 0x000000FF; /* Bring CS and RD high. */ regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY; cx_write(MC417_RWD, regval); /* Read data byte 1 */ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE1; cx_write(MC417_RWD, regval); regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE1; cx_write(MC417_RWD, regval); tempval = cx_read(MC417_RWD); dataval |= ((tempval & 0x000000FF) << 8); regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY; cx_write(MC417_RWD, regval); /* Read data byte 2 */ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE2; cx_write(MC417_RWD, regval); regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE2; cx_write(MC417_RWD, regval); tempval = cx_read(MC417_RWD); dataval |= ((tempval & 0x000000FF) << 16);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -