From 96f69ba39c38d39c69f27ccdb3a29e68abc0be71 Mon Sep 17 00:00:00 2001 From: xumm Date: Thu, 31 Aug 2023 11:56:56 +0800 Subject: [PATCH] Add support for RAW-MIPI-IMX462M and RAW-MIPI-AR0234M --- linux/drivers/rk358x/cam_drv_src/veye_mvcam.c | 142 +++++++++++++----- linux/drivers/rk358x/cam_drv_src/veye_mvcam.h | 20 ++- linux/drivers/rk358x/cam_drv_src/veyecam2m.c | 1 + mv_tools_rockchip/i2c_tools/mv_mipi_i2c.sh | 97 +++++++++++- mv_tools_rockchip/i2c_tools/sources/lut_rw.c | 8 +- 5 files changed, 215 insertions(+), 53 deletions(-) diff --git a/linux/drivers/rk358x/cam_drv_src/veye_mvcam.c b/linux/drivers/rk358x/cam_drv_src/veye_mvcam.c index aa06a9b..136f252 100644 --- a/linux/drivers/rk358x/cam_drv_src/veye_mvcam.c +++ b/linux/drivers/rk358x/cam_drv_src/veye_mvcam.c @@ -28,8 +28,11 @@ #include #include #include - -#define DRIVER_VERSION KERNEL_VERSION(1, 0x01, 0x03) +/* +versionlog: v.1.1.04 -20230830 +add support for RAW_MIPI_IMX462M and RAW_MIPI_AR0234M +*/ +#define DRIVER_VERSION KERNEL_VERSION(1, 0x01, 0x04) #define mvcam_NAME "mvcam" @@ -85,7 +88,7 @@ struct mvcam_mode { u32 height; }; -static const s64 link_freq_menu_items[] = { +static s64 link_freq_menu_items[] = { MVCAM_DEFAULT_LINK_FREQ, }; @@ -113,6 +116,8 @@ struct mvcam { u32 cur_fps; u32 h_flip; u32 v_flip; + u32 lane_num; + u32 mipi_datarate; struct v4l2_ctrl_handler ctrl_handler; struct v4l2_ctrl *ctrls[MVCAM_MAX_CTRLS]; @@ -132,7 +137,7 @@ struct mvcam { const char *module_facing; const char *module_name; const char *len_name; - u32 lane_data_num; + }; @@ -541,7 +546,7 @@ static int mvcam_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad_id, { u32 val = 0; struct mvcam *mvcam = to_mvcam(sd); - val = 1 << (mvcam->lane_data_num - 1) | + val = 1 << (mvcam->lane_num - 1) | V4L2_MBUS_CSI2_CHANNEL_0 | V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; config->type = V4L2_MBUS_CSI2_DPHY; @@ -1019,6 +1024,31 @@ VEYE_TRACE return -ENODEV; } +static void mvcam_get_mipifeature(struct mvcam *mvcam) +{ + u32 lane_num; + u32 mipi_datarate; + struct i2c_client *client = mvcam->client; + mvcam_read(client, Lane_Num, &lane_num); + if(lane_num == 4){ + mvcam->lane_num = 4; + }else{ + mvcam->lane_num = 2; + } + + mvcam_read(client, MIPI_DataRate, &mipi_datarate); + if(mipi_datarate == 0xFFFFFFFF) + mipi_datarate = MVCAM_DEFAULT_MIPI_DATARATE; + else + mipi_datarate *=1000;//register value is kbps + + mvcam->mipi_datarate = mipi_datarate; + + link_freq_menu_items[0] = mvcam->mipi_datarate>>1;//hz is half of datarate + dev_info(&client->dev, "%s: lane num %d, datarate %d bps\n", + __func__, mvcam->lane_num,mvcam->mipi_datarate); + return; +} /* Start streaming */ static int mvcam_start_streaming(struct mvcam *mvcam) { @@ -1360,6 +1390,14 @@ static int mvcam_identify_module(struct mvcam * mvcam) mvcam->model_id = device_id; dev_info(&client->dev, "camera is: MV_MIPI_IMX287M\n"); break; + case RAW_MIPI_IMX462M: + mvcam->model_id = device_id; + dev_info(&client->dev, "camera is: RAW_MIPI_IMX462M\n"); + break; + case RAW_MIPI_AR0234M: + mvcam->model_id = device_id; + dev_info(&client->dev, "camera is: RAW_MIPI_AR0234M\n"); + break; default: dev_err(&client->dev, "camera id do not support: %x \n",device_id); return -EIO; @@ -1406,26 +1444,18 @@ static void free_gpio(struct mvcam *mvcam) // if (!IS_ERR(mvcam->mipi_pwr_gpio)) // gpio_free(desc_to_gpio(mvcam->mipi_pwr_gpio)); } -static int mvcam_probe(struct i2c_client *client, - const struct i2c_device_id *id) + +static int mvcam_check_hwcfg(struct device *dev) { - struct device *dev = &client->dev; - + int ret; + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct mvcam *mvcam = to_mvcam(sd); + struct device_node *node = dev->of_node; struct device_node *endpoint_node = NULL; struct v4l2_fwnode_endpoint vep = {0}; - struct mvcam *mvcam; - char facing[2]; - int ret; - - dev_info(dev, "veye mv series camera driver version: %02x.%02x.%02x\n", - DRIVER_VERSION >> 16, - (DRIVER_VERSION & 0xff00) >> 8, - DRIVER_VERSION & 0x00ff); - mvcam = devm_kzalloc(&client->dev, sizeof(struct mvcam), GFP_KERNEL); - if (!mvcam) - return -ENOMEM; - + ret = of_property_read_u32(node, RKMODULE_CAMERA_MODULE_INDEX, &mvcam->module_index); ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_FACING, @@ -1439,35 +1469,59 @@ static int mvcam_probe(struct i2c_client *client, return -EINVAL; } - /* Initialize subdev */ - v4l2_i2c_subdev_init(&mvcam->sd, client, &mvcam_subdev_ops); - mvcam->client = client; - - mvcam->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); - if (IS_ERR(mvcam->reset_gpio)) { - dev_info(dev, "Failed to get reset-gpios, maybe no use\n"); - } - - mvcam->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_OUT_HIGH); - if (IS_ERR(mvcam->pwdn_gpio)) { - dev_info(dev, "Failed to get pwdn-gpios, maybe no use\n"); - } - endpoint_node = of_find_node_by_name(node,"endpoint"); if(endpoint_node != NULL){ //printk("mvcam get endpoint node success\n"); ret=v4l2_fwnode_endpoint_parse(&endpoint_node->fwnode, &vep); if(ret){ - dev_info(dev, "Failed to get mvcam endpoint data lanes, set a default value\n"); - mvcam->lane_data_num = 2; + dev_info(dev, "Failed to get mvcam endpoint data lanes, set use lane num from camera %d\n",mvcam->lane_num); }else{ dev_info(dev, "Success to get mvcam endpoint data lanes, dts uses %d lanes\n", vep.bus.mipi_csi2.num_data_lanes); - mvcam->lane_data_num = vep.bus.mipi_csi2.num_data_lanes; + /* Check the number of MIPI CSI2 data lanes */ + if (vep.bus.mipi_csi2.num_data_lanes != mvcam->lane_num) { + dev_err(dev, "dts lane num %d mismatch camera data lane num %d\n",vep.bus.mipi_csi2.num_data_lanes,mvcam->lane_num); + return -ENOENT; + } } + }else{ dev_info(dev,"mvcam get endpoint node failed\n"); return -ENOENT; } + return 0; +} +static int mvcam_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + + + struct mvcam *mvcam; + char facing[2]; + int ret; + + dev_info(dev, "veye mv series camera driver version: %02x.%02x.%02x\n", + DRIVER_VERSION >> 16, + (DRIVER_VERSION & 0xff00) >> 8, + DRIVER_VERSION & 0x00ff); + mvcam = devm_kzalloc(&client->dev, sizeof(struct mvcam), GFP_KERNEL); + if (!mvcam) + return -ENOMEM; + + /* Initialize subdev */ + v4l2_i2c_subdev_init(&mvcam->sd, client, &mvcam_subdev_ops); + mvcam->client = client; + + mvcam->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(mvcam->reset_gpio)) { + dev_info(dev, "Failed to get reset-gpios, maybe no use\n"); + } + + mvcam->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_OUT_HIGH); + if (IS_ERR(mvcam->pwdn_gpio)) { + dev_info(dev, "Failed to get pwdn-gpios, maybe no use\n"); + } + mutex_init(&mvcam->mutex); ret = mvcam_power_on(dev); @@ -1484,7 +1538,11 @@ static int mvcam_probe(struct i2c_client *client, ret = -ENODEV; goto error_power_off; } - + mvcam_get_mipifeature(mvcam); + /* Check the hardware configuration in device tree */ + if(mvcam_check_hwcfg(dev)) + goto error_power_off; + mvcam_read(client, Sensor_Width, &mvcam->max_width); mvcam_read(client, Sensor_Height, &mvcam->max_height); if(mvcam->model_id == MV_MIPI_IMX178M){ @@ -1508,6 +1566,12 @@ static int mvcam_probe(struct i2c_client *client, }else if(mvcam->model_id == MV_MIPI_IMX287M){ mvcam->min_width = MV_IMX287M_ROI_W_MIN; mvcam->min_height = MV_IMX287M_ROI_H_MIN; + }else if(mvcam->model_id == RAW_MIPI_IMX462M){ + mvcam->min_width = RAW_IMX462M_ROI_W_MIN; + mvcam->min_height = RAW_IMX462M_ROI_H_MIN; + }else if(mvcam->model_id == RAW_MIPI_AR0234M){ + mvcam->min_width = RAW_AR0234M_ROI_W_MIN; + mvcam->min_height = RAW_AR0234M_ROI_H_MIN; } v4l2_dbg(1, debug, mvcam->client, "%s: max width %d; max height %d\n", __func__, mvcam->max_width,mvcam->max_height); diff --git a/linux/drivers/rk358x/cam_drv_src/veye_mvcam.h b/linux/drivers/rk358x/cam_drv_src/veye_mvcam.h index 77ad9ec..a856e32 100644 --- a/linux/drivers/rk358x/cam_drv_src/veye_mvcam.h +++ b/linux/drivers/rk358x/cam_drv_src/veye_mvcam.h @@ -43,6 +43,7 @@ #define User_define_zone1 0x440 #define User_define_zone2 0x444 #define User_define_zone3 0x448 +#define Slave_mode 0x460 #define Test_Image_Selector 0x800 #define Pixel_Format 0x804 @@ -58,7 +59,9 @@ #define Data_shift 0x82C #define Black_Level 0x830 #define ReadOut_Mode 0x834 - +#define Lane_Num 0x83C +#define MIPI_DataRate 0x840 + #define ISP_module_ctrl 0xC00 #define Exposure_Mode 0xC04 #define Target_Brightness 0xC08 @@ -141,14 +144,17 @@ enum enum_TriggerSrc{ #define MV_MIPI_SC130M 0x0130 #define MV_MIPI_IMX265M 0x0265 #define MV_MIPI_IMX264M 0x0264 -#define RAW_MIPI_SC132M 0x8132 #define MV_MIPI_IMX287M 0x0287 +#define RAW_MIPI_SC132M 0x8132 +#define RAW_MIPI_IMX462M 0x8462 +#define RAW_MIPI_AR0234M 0x8234 -#define MV_CAM_PIXEL_RATE 750000000 //750M +/* MV mipi datarate is 1.5Gbps */ +#define MVCAM_DEFAULT_MIPI_DATARATE 1500000000 /* MV mipi clk is 742.5Mhz */ #define MVCAM_DEFAULT_LINK_FREQ 742500000 -/*RAW mipi clk is 559Mhz */ -#define RAWCAM_DEFAULT_LINK_FREQ 559000000 +//pixel_rate = link_freq * 2 * nr_of_lanes / bits_per_sample +#define MV_CAM_PIXEL_RATE 750000000 //1.5Gbps*2*2/8=750M #define MV_CAM_DEF_FPS 22U @@ -166,6 +172,10 @@ enum enum_TriggerSrc{ #define RAW_SC132M_ROI_H_MIN 64U #define MV_IMX287M_ROI_W_MIN 264U #define MV_IMX287M_ROI_H_MIN 64U +#define RAW_IMX462M_ROI_W_MIN 368U +#define RAW_IMX462M_ROI_H_MIN 304U +#define RAW_AR0234M_ROI_W_MIN 64U +#define RAW_AR0234M_ROI_H_MIN 64U #define MV_CAM_ROI_W_ALIGN 8U #define MV_CAM_ROI_H_ALIGN 4U diff --git a/linux/drivers/rk358x/cam_drv_src/veyecam2m.c b/linux/drivers/rk358x/cam_drv_src/veyecam2m.c index fc43c49..e55925b 100644 --- a/linux/drivers/rk358x/cam_drv_src/veyecam2m.c +++ b/linux/drivers/rk358x/cam_drv_src/veyecam2m.c @@ -512,6 +512,7 @@ static long veyecam2m_compat_ioctl32(struct v4l2_subdev *sd, ret = -EFAULT; } kfree(ch_info); + break; default: ret = -ENOIOCTLCMD; break; diff --git a/mv_tools_rockchip/i2c_tools/mv_mipi_i2c.sh b/mv_tools_rockchip/i2c_tools/mv_mipi_i2c.sh index d237d7e..c652c81 100644 --- a/mv_tools_rockchip/i2c_tools/mv_mipi_i2c.sh +++ b/mv_tools_rockchip/i2c_tools/mv_mipi_i2c.sh @@ -195,6 +195,9 @@ ### Special function ./mv_mipi_i2c.sh -r -f snsreg -p1 SensorAddr +./mv_mipi_i2c.sh -r -f lanenum +./mv_mipi_i2c.sh -w -f lanenum -p1 [2/4] + COMMENT_SAMPLE # @@ -259,9 +262,10 @@ User_define_zone0=0x43C; User_define_zone1=0x440; User_define_zone2=0x444; User_define_zone3=0x448; -Nondiscontinues_mode=0x44C; +Nondiscontinuous_mode=0x44C; Sensor_Reg_Addr=0x0450; Sensor_Reg_Val=0x454; +Slave_mode=0x460; Test_Image_Selector=0x800; Pixel_Format=0x804; @@ -276,7 +280,10 @@ ROI_Offset_Y=0x824; Image_Direction=0x828; Data_shift=0x82C; Black_Level=0x830; -ReadOut_Mode=0x834; +BLC_Mode=0x834; +ReadOut_Mode=0x838; +Lane_Num=0x83C; +MIPI_DataRate=0x840; ISP_module_ctrl=0xC00; Exposure_Mode=0xC04; @@ -461,6 +468,12 @@ read_model() "33074") printf "model is RAW-MIPI-SC132M\n"; ;; + "33332") + printf "model is RAW-MIPI-AR0234M\n"; + ;; + "33890") + printf "model is RAW-MIPI-IMX462M\n"; + ;; *) printf " model %8x not recognized\n" $model; ;; @@ -661,6 +674,21 @@ write_blacklevel() printf "w black level is %d \n" $PARAM1; } +read_blcmode() +{ + local value=0; + typeset -i value; + value=$(./i2c_4read $I2C_DEV $I2C_ADDR $BLC_Mode 2>/dev/null); + printf "r BLC_Mode is %d \n" $value; +} + +write_blcmode() +{ + local res=0; + res=$(./i2c_4write $I2C_DEV $I2C_ADDR $BLC_Mode $PARAM1); + printf "w BLC_Mode is %d \n" $PARAM1; +} + read_roi() { local x=0; @@ -1265,7 +1293,7 @@ read_snsreg() sensor_val=$(./i2c_4read $I2C_DEV $I2C_ADDR $Sensor_Reg_Val 2>/dev/null); #check if msb set to 1 if [ $((($sensor_val & 0x80000000) == 0x80000000)) -eq 1 ]; then - sensor_val=$((sensor_val&0xFF)); + sensor_val=$((sensor_val&0xFFFF)); printf "read sensor register addr 0x%x value 0x%x \n" $PARAM1 $sensor_val; else printf "read sensor register failed\n"; @@ -1276,9 +1304,47 @@ read_clkmode() { local value=0; typeset -i value; - value=$(./i2c_4read $I2C_DEV $I2C_ADDR $Nondiscontinues_mode 2>/dev/null); - printf "r non discontinues mode is %d \n" $value; + value=$(./i2c_4read $I2C_DEV $I2C_ADDR $Nondiscontinuous_mode 2>/dev/null); + printf "r non discontinuous_mode mode is %d \n" $value; +} + +read_mipidatarate() +{ + local value=0; + typeset -i value; + value=$(./i2c_4read $I2C_DEV $I2C_ADDR $MIPI_DataRate 2>/dev/null); + printf "r MIPI datarate is %d Kbps/lane\n" $value; +} +read_lanenum() +{ + local value=0; + typeset -i value; + value=$(./i2c_4read $I2C_DEV $I2C_ADDR $Lane_Num 2>/dev/null); + printf "r lane number is %d \n" $value; } + +write_lanenum() +{ + local res=0; + res=$(./i2c_4write $I2C_DEV $I2C_ADDR $Lane_Num $PARAM1); + printf "w lane number is %d \n" $PARAM1; +} + +read_slavemode() +{ + local value=0; + typeset -i value; + value=$(./i2c_4read $I2C_DEV $I2C_ADDR $Slave_mode 2>/dev/null); + printf "r slave mode is %d \n" $value; +} + +write_slavemode() +{ + local res=0; + res=$(./i2c_4write $I2C_DEV $I2C_ADDR $Slave_mode $PARAM1); + printf "w slave mode is %d \n" $PARAM1; +} + <<'COMMENT_SAMPLE' read_fun() { @@ -1513,6 +1579,18 @@ if [ ${MODE} = "read" ] ; then "clkmode") read_clkmode; ;; + "mipidatarate") + read_mipidatarate; + ;; + "lanenum") + read_lanenum; + ;; + "blcmode") + read_blcmode; + ;; + "slavemode") + read_slavemode; + ;; *) echo "NOT SUPPORTED!"; ;; @@ -1662,6 +1740,15 @@ if [ ${MODE} = "write" ] ; then "aeag_run_once_save") write_aeag_run_once_save; ;; + "lanenum") + write_lanenum; + ;; + "blcmode") + write_blcmode; + ;; + "slavemode") + write_slavemode; + ;; *) echo "NOT SUPPORTED!"; ;; diff --git a/mv_tools_rockchip/i2c_tools/sources/lut_rw.c b/mv_tools_rockchip/i2c_tools/sources/lut_rw.c index 084cd68..89c58a5 100644 --- a/mv_tools_rockchip/i2c_tools/sources/lut_rw.c +++ b/mv_tools_rockchip/i2c_tools/sources/lut_rw.c @@ -17,9 +17,9 @@ static char i2c_device_name[I2C_DEVICE_NAME_LEN]; #define MAX_BLK_BUFF_SIZE (4096) -#define LUT_COUNT_ADDR (0xC70) -#define LUT_W_START_ADDR (0xC74) -#define LUT_W_DONE_ADDR (0xC78) +#define LUT_COUNT_ADDR (0xC74) +#define LUT_W_START_ADDR (0xC78) +#define LUT_W_DONE_ADDR (0xC7C) #define LUT_DATA_ADDR (0x1800) static int i2c_rd(int fd, uint8_t i2c_addr, uint16_t reg, uint32_t *values, uint32_t n) @@ -105,7 +105,7 @@ U32 main(int argc, char *argv[]) struct sensor_regs regs; if (argc < 4) { - printf("usage: %s . sample: %s 0x10 0x3b 0x1800 r lutfile.txt\n", argv[0], argv[0]); + printf("usage: %s . sample: %s 0x10 0x3b r lutfile.txt\n", argv[0], argv[0]); return -1; }