DM6467的OV5642 Linux驱动程序开发(二)——Linux内核修改

来源:互联网 发布:vba连接oracle数据库 编辑:程序博客网 时间:2024/04/30 11:33

 

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输入。至于要看所有的改动可以查看已经编好的内核中的相应文件。

原创粉丝点击