1 修改vpif驱动程序
由于ov5642是由vpif进行管理,而原先的vpif驱动程序不支持sensorraw格式,所以需要修改vpif驱动程序以兼容sensor raw格式,这时首先需要参考原先在CCS中调试好的vpif寄存器配置。对于sensor视频输入,vpif的寄存器配置比较简单,如下所示。
channel0->regs->FLD0_Y_STRTADR = ( ( Uint32 )RawData );
VPIF_CHCTRL0 = 0 // Capture Parameters | ( 1 << 31 ) // Data phase changes at falling edge of the input clock | ( 1 << 28 ) // Data width: 10-bit | ( 480 << 16 ) // Line interrupt: 480 lines | ( 1 << 14 ) // Invert incoming VSYNC | ( 1 << 12 ) // Input Frame | ( 1 << 10 ) // Progressive Format | ( 1 << 7 ) // Frame interrupt to CPU: top and bottom field | ( 1 << 2 ); // CCD/CMOS video capture mode
channel0->regs->IMG_LINE_OFFSET = 640 * 2 * 2;
VPIF_CHCTRL1 = 0 // Capture Parameters | ( 1 << 31 ) // Data phase changes at falling edge of the input clock | ( 1 << 10 ) // Progressive Format | ( 1 << 7 ) // Frame interrupt to CPU: top and bottom field | ( 1 << 2 ); // CCD/CMOS video capture mode
channel1->regs->IMG_LINE_OFFSET = 640 * 2 * 2; |
只要配置好vpif的寄存器,那么vpif就可以获取ov5642传来的视频数据,所以这是修改vpif驱动程序时的主要工作,剩下的部分主要就是添加一些定义,修改一些函数以扩展其兼容性。
修改vpif时有以下几部分比较重要:
(1) 配置vpif寄存器。
配置vpif寄存器的函数是vpif.c文件中的config_vpif_params(),需要在其中添加判断是否当前的视频输入格式为CCD/CMOS,如果是则需要按照以下代码配置vpif的channel 0和channel 1。其中,红色部分为添加的代码,下同。
/* Set the polarity of various pins */ vpif_wr_bit(reg, VPIF_CH_FID_POLARITY_BIT, vpifparams->iface.fid_pol); vpif_wr_bit(reg, VPIF_CH_V_VALID_POLARITY_BIT, vpifparams->iface.vd_pol); vpif_wr_bit(reg, VPIF_CH_H_VALID_POLARITY_BIT, vpifparams->iface.hd_pol); /* Data phase changes at falling edge of input clock */ vpif_wr_bit(reg, VPIF_CH_CLK_EDGE_CTRL_BIT, 0x1); /* top and bottom field interrupt */ vpif_wr_bit(reg, 7, 0x1); /* frame based storage */ vpif_wr_bit(reg, VPIF_CH_INPUT_FIELD_FRAME_BIT, 0x1); /* Set data width */ vpif_wr_bit(reg, VPIF_CH_DATA_WIDTH_BIT, 0x1); /* Set frame height in lines interrupt */ value = regr(reg); value &= ~(((unsigned int)(0xfff)) << VPIF_CH0_INTERVAL_LINE_INT_BIT); value |= ((480) << VPIF_CH0_INTERVAL_LINE_INT_BIT); regw(value, reg);
/* set channel 1 regs */ value = 0x0; reg = vpifregs[1].ch_ctrl; regw(value, reg); vpif_wr_bit(reg, VPIF_CH_CLK_EDGE_CTRL_BIT, 0x1);//VPIF_CH_CLK_EDGE_CTRL_BIT(31) vpif_wr_bit(reg, VPIF_CAPTURE_CH_NIP, 0x1);//VPIF_CAPTURE_CH_NIP (10) vpif_wr_bit(reg, 7, 0x1);//VPIF_CH_INT_CTRL_BIT (6) top and bottom vpif_wr_bit(reg, VPIF_CH_YC_MUX_BIT, 0x0);//VPIF_CH_YC_MUX_BIT (3) vpif_wr_bit(reg, VPIF_CH_DATA_MODE_BIT, 0x1);//VPIF_CH_DATA_MODE_BIT (2) vpif_wr_bit(reg, VPIF_CH_SDR_FMT_BIT, 0x0);//VPIF_CH_SDR_FMT_BIT (4) regw(640 *2 * 2, vpifregs[1].line_offset);// 10-bit VGA CMOS Camera input |
(2) 添加对CCD/CMOS的支持。
这主要通过定义一个结构体来实现:staticconst struct vpif_channel_config_params ch_params[]。该结构体用来记录vpif支持的视频输入格式以及一些重要参数。要添加对CCD/CMOS的支持,需要在其中添加以下定义。
static const struct vpif_channel_config_params ch_params[] = { { "PAL_BDGHIK", 720, 576, 25, 0, 1, 280, 1440, 1, 23, 311, 313, 336, 624, 625, 0, 1, 0, V4L2_STD_625_50, }, { "1080P-60", 1920, 1080, 60, 1, 0, 272, 1920, 1, 42, 1122, 0, 0, 0, 1125, 0, 0, 1, V4L2_STD_1080P_60, }, { "CAMERA-VGA", 640, 480, 15, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 480, 1, 0, 0, V4L2_STD_CAMERA_VGA, }, }; |
(3) 在V4L2框架中添加CCD/CMOS支持。
首先,需要在/include/linux/videodev2.c中添加宏定义以支持ov5642输入的视频格式。
#define V4L2_STD_SECAM_L ((v4l2_std_id)0x00400000) #define V4L2_STD_SECAM_LC ((v4l2_std_id)0x00800000)
/* ATSC/HDTV */ #define V4L2_STD_ATSC_8_VSB ((v4l2_std_id)0x01000000) #define V4L2_STD_ATSC_16_VSB ((v4l2_std_id)0x02000000)
/* camera */ #define V4L2_STD_CAMERA_VGA ((v4l2_std_id)0x10000000) //#define V4L2_STD_CAMERA_PAL ((v4l2_std_id)0x20000000) //#define V4L2_STD_CAMERA_720P ((v4l2_std_id)0x40000000) //#define V4L2_STD_CAMERA_1080P ((v4l2_std_id)0x80000000) |
然后,需要在/driver/media/video/v4l2-ioctl.c中添加相关定义。
{ V4L2_STD_SECAM_L, "SECAM-L" }, { V4L2_STD_SECAM_LC, "SECAM-Lc" }, { V4L2_STD_CAMERA_VGA, "CAMERA-VGA"}, { 0, "Unknown" } }; |
(4) 在CCD/CMOS模式时使能channel 1。
在使用sensor模式输入视频时,需要使用vpif的两个channel,所以,在使能channel0时需要使能channel 1。
if ((VPIF_CHANNEL1_VIDEO == ch->channel_id) || (common->started == 2) || (ch->video.stdid == V4L2_STD_CAMERA_VGA)) { channel1_intr_assert(); channel1_intr_enable(1); enable_channel1(1); } |
(5) 编写CCD/CMOS模式时的vpif buffer地址设置函数。
当vpif为sensor raw输入时,vpif存储视频帧的4个ddr2地址寄存器只需要配置一个就行了,而当输入为标清或者高清时都需要配置4个寄存器,所以这里需要修改。
首先,在/driver/media/video/davinci/vpif.h中添加对应的函数。
/* inline function to set buffer addresses in case of raw bayer mode */ static inline void ch0_set_videobuf_addr_raw(unsigned long top_strt_luma, unsigned long btm_strt_luma, unsigned long top_strt_chroma, unsigned long btm_strt_chroma) { regw(top_strt_luma, VPIF_CH0_TOP_STRT_ADD_LUMA); regw(0, VPIF_CH0_BTM_STRT_ADD_LUMA); regw(0, VPIF_CH0_TOP_STRT_ADD_CHROMA); regw(0, VPIF_CH0_BTM_STRT_ADD_CHROMA); } |
然后,在/driver/media/video/davinci/vpif_capture.c的vpif_config_addr()函数中配置该函数为sensorraw输入模式时的地址配置函数。
static void vpif_config_addr(struct channel_obj *ch, int muxmode) { struct common_obj *common;
vpif_dbg(2, debug, "vpif_config_addr\n");
common = &(ch->common[VPIF_VIDEO_INDEX]);
if (VPIF_CHANNEL1_VIDEO == ch->channel_id) common->set_addr = ch1_set_videobuf_addr; else if (2 == muxmode) common->set_addr = ch0_set_videobuf_addr_yc_nmux; else if (ch->vpifparams.std_info.capture_format == 1) common->set_addr = ch0_set_videobuf_addr_raw; else common->set_addr = ch0_set_videobuf_addr; } |
(6)通过CPLD选通使能ov5642。
由于系统默认是只使能了tvp5150,而ov5642是处于reset状态,所以需要通过CPLD使能ov5642才能使其工作,这需要在/arch/arm/mach-davinci/board-dm646x-evm.c中修改setup_vpif_input_channel_mode函数来实现。
static int setup_vpif_input_channel_mode(u8 mux_mode, u8 capture_format) { …… if (mux_mode) { val &= VPIF_INPUT_TWO_CHANNEL; value |= VIDCH1CLK; value1 |= VIDCH1CLKSRCCH1; } else if (!mux_mode && !capture_format){ val |= VPIF_INPUT_ONE_CHANNEL; value &= ~VIDCH1CLK; value1 &= VIDCH1CLKSRCCH0; } else if (!mux_mode && capture_format) { // CCD/CMOS input val = 0xbf;//val |= VPIF_INPUT_ONE_CHANNEL; value &= ~VIDCH1CLK; value1 &= VIDCH1CLKSRCCH0; } …… } |
(7)添加ov5642的vpif子设备定义。
这需要在/arch/arm/mach-davinci/board-dm646x-evm.c首先添加以下定义。
static struct vpif_subdev_info vpif_capture_sdev_info[] = { #ifndef CONFIG_VIDEO_TVP7002 { .name = "tvp5150", .board_info = { I2C_BOARD_INFO("tvp5150", 0x5d), //.platform_data = &tvp5150_pdata, }, .input = TVP5150_COMPOSITE0, .output = TVP5150_NORMAL, .can_route = 1, .vpif_if = { .if_type = VPIF_IF_BT656, .hd_pol = 1, .vd_pol = 1, .fid_pol = 0, }, }, { .name = "ov5642", .board_info = { I2C_BOARD_INFO("ov5642", 0x3c), }, .input = 0, .output = 0, .can_route = 0, .vpif_if = { .if_type = VPIF_IF_RAW_BAYER, .hd_pol = 0, .vd_pol = 1, .fid_pol = 0, }, }, |
然后,还需要在该文件中添加vpif channel0的输入设备定义。
static const struct vpif_input dm6467_ch0_inputs[] = { { .input = { .index = 0, .name = "Composite", .type = V4L2_INPUT_TYPE_CAMERA, .std = V4L2_STD_PAL, }, .subdev_name = "tvp5150", }, { .input = { .index = 0, .name = "Camera", .type = V4L2_INPUT_TYPE_CAMERA, .std = V4L2_STD_CAMERA_VGA, }, .subdev_name = "ov5642", }, |
对于vpif驱动程序的修改,除了以上部分,其实还改了很多很多地方,但上面这些是主要部分,其他都是一些细节问题,主要是一些参数设置的函数没有考虑到兼容sensor raw输入。至于要看所有的改动可以查看已经编好的内核中的相应文件。