diff --git a/bsp/drivers/vin/modules/sensor/imx415_mipi.c b/bsp/drivers/vin/modules/sensor/imx415_mipi.c index 2439bbf67..70b2be034 100644 --- a/bsp/drivers/vin/modules/sensor/imx415_mipi.c +++ b/bsp/drivers/vin/modules/sensor/imx415_mipi.c @@ -57,15 +57,15 @@ static struct regval_list sensor_default_regs[] = { }; static struct regval_list sensor_12bit_30fps_regs[] = { -/* All pixel - 891Mbps - 27MHZ */ +/* All pixel - 891Mbps - 74.25MHz external INCK */ {0x3000, 0x01},/* stanby */ {0x3001, 0x00}, {0x3002, 0x01},/* XMSTA start */ {0x3003, 0x00},/* XMASTER SELECT MASTER */ - {0x3008, 0x5D}, + {0x3008, 0xFF}, {0x3009, 0x00}, - {0x300A, 0x42}, - {0x300B, 0xA0}, + {0x300A, 0xB6}, + {0x300B, 0x00}, {0x301C, 0x00}, {0x301D, 0x08}, {0x3020, 0x00}, @@ -121,12 +121,12 @@ static struct regval_list sensor_12bit_30fps_regs[] = { {0x30E2, 0x32},/* BLV */ {0x30E3, 0x00}, {0x3115, 0x00}, - {0x3116, 0x23}, - {0x3118, 0xC6}, + {0x3116, 0x28}, + {0x3118, 0xC0}, {0x3119, 0x00}, - {0x311A, 0xE7}, + {0x311A, 0xE0}, {0x311B, 0x00}, - {0x311E, 0x23}, + {0x311E, 0x28}, {0x3260, 0x01}, {0x32C8, 0x01}, {0x32D4, 0x21}, @@ -203,8 +203,8 @@ static struct regval_list sensor_12bit_30fps_regs[] = { {0x3BCA, 0xBD}, {0x4000, 0x10}, {0x4001, 0x03}, - {0x4004, 0xC0}, - {0x4005, 0x06}, + {0x4004, 0x90}, + {0x4005, 0x12}, {0x400C, 0x00}, {0x4018, 0x7F}, {0x4019, 0x00}, @@ -855,19 +855,14 @@ static int sensor_power(struct v4l2_subdev *sd, int on) vin_gpio_set_status(sd, RESET, 1); vin_gpio_set_status(sd, POWER_EN, 1); vin_gpio_write(sd, RESET, CSI_GPIO_LOW); - vin_gpio_write(sd, PWDN, CSI_GPIO_LOW); + vin_gpio_write(sd, PWDN, CSI_GPIO_HIGH); vin_gpio_write(sd, POWER_EN, CSI_GPIO_HIGH); vin_set_pmu_channel(sd, IOVDD, ON); - usleep_range(2000, 2200); vin_set_pmu_channel(sd, AVDD, ON); vin_set_pmu_channel(sd, DVDD, ON); + usleep_range(20000, 22000); vin_gpio_write(sd, RESET, CSI_GPIO_HIGH); - vin_gpio_write(sd, PWDN, CSI_GPIO_HIGH); - usleep_range(100, 120); - vin_set_mclk(sd, ON); - usleep_range(100, 120); - vin_set_mclk_freq(sd, MCLK); - usleep_range(3000, 3200); + usleep_range(50000, 52000); cci_unlock(sd); break; case PWR_OFF: @@ -914,10 +909,14 @@ static int sensor_reset(struct v4l2_subdev *sd, u32 val) static int sensor_detect(struct v4l2_subdev *sd) { - data_type rdval = 0; - int cnt = 0; - sensor_read(sd, 0x3008, &rdval); - sensor_print("%s read value is 0x%x\n", __func__, rdval); + data_type id_l = 0, id_h = 0; + int ret, ret_l; + + ret_l = sensor_read(sd, 0x3f12, &id_l); + ret = sensor_read(sd, 0x3f13, &id_h); + sensor_dbg("%s read id ret=%d/%d value=0x%x\n", + __func__, ret_l, ret, ((id_h & 0xff) << 8) | (id_l & 0xff)); + return 0; } @@ -1352,11 +1351,14 @@ static int sensor_probe(struct i2c_client *client, info->fmt = &sensor_formats[0]; info->fmt_pt = &sensor_formats[0]; info->win_pt = &sensor_win_sizes[0]; + info->current_wins = &sensor_win_sizes[0]; info->fmt_num = N_FMTS; info->win_size_num = N_WIN_SIZES; info->sensor_field = V4L2_FIELD_NONE; + info->width = sensor_win_sizes[0].width; + info->height = sensor_win_sizes[0].height; info->stream_seq = MIPI_BEFORE_SENSOR; - info->combo_mode = CMB_TERMINAL_RES | CMB_PHYA_OFFSET2 | MIPI_NORMAL_MODE; + info->combo_mode = CMB_TERMINAL_RES | CMB_PHYA_OFFSET0 | MIPI_NORMAL_MODE; info->af_first_flag = 1; info->exp = 0; info->gain = 0; diff --git a/bsp/drivers/vin/vin-csi/sunxi_csi.c b/bsp/drivers/vin/vin-csi/sunxi_csi.c index 4b949bfa5..f215aa571 100644 --- a/bsp/drivers/vin/vin-csi/sunxi_csi.c +++ b/bsp/drivers/vin/vin-csi/sunxi_csi.c @@ -36,6 +36,8 @@ struct csi_dev *glb_parser[VIN_MAX_CSI]; +static struct csi_format *__csi_try_format(struct v4l2_mbus_framefmt *mf); + static struct csi_format sunxi_csi_formats[] = { { .code = MEDIA_BUS_FMT_YUYV8_2X8, @@ -519,6 +521,15 @@ static int sunxi_csi_subdev_s_stream(struct v4l2_subdev *sd, int enable) csic_prs_enable(csi->id); csic_prs_disable(csi->id); csic_prs_enable(csi->id); + if (!csi->csi_fmt) { + if (!csi->mf.code) { + vin_err("parser%d stream on without active format\n", csi->id); + return -EINVAL; + } + csi->csi_fmt = __csi_try_format(&csi->mf); + vin_warn("parser%d missing active format, fallback to code 0x%x\n", + csi->id, csi->mf.code); + } __csi_set_fmt_hw(csi); } else { csi->tvin.flag = false; diff --git a/bsp/drivers/vin/vin-video/vin_video.c b/bsp/drivers/vin/vin-video/vin_video.c index 8f750c79f..7c273516a 100644 --- a/bsp/drivers/vin/vin-video/vin_video.c +++ b/bsp/drivers/vin/vin-video/vin_video.c @@ -382,6 +382,11 @@ void vin_set_next_buf_addr(struct vin_core *vinc) vinc->vin_status.lost_cnt = 0; #ifndef BUF_AUTO_UPDATE + if (list_empty(&cap->vidq_active)) { + vin_err("vinc%d stream on without queued buffer\n", vinc->id); + return; + } + buf = list_entry(cap->vidq_active.next, struct vin_buffer, list); vin_set_addr(vinc, &buf->vb.vb2_buf, &vinc->vid_cap.frame, &vinc->vid_cap.frame.paddr); #else @@ -963,6 +968,7 @@ static int vin_pipeline_set_mbus_config(struct vin_core *vinc) struct vin_pipeline *pipe = &vinc->vid_cap.pipe; struct v4l2_subdev *sd = pipe->sd[VIN_IND_SENSOR]; struct v4l2_mbus_config mcfg; + struct v4l2_subdev *cfg_sd; struct media_entity *me; struct media_graph graph; struct csi_dev *csi = NULL; @@ -973,6 +979,33 @@ static int vin_pipeline_set_mbus_config(struct vin_core *vinc) vin_err("%s get_mbus_config error!\n", sd->name); goto out; } + + cfg_sd = pipe->sd[VIN_IND_MIPI]; + if (cfg_sd) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) + ret = cfg_sd->ops->pad->get_mbus_config(cfg_sd, 0, &mcfg); +#else + ret = cfg_sd->ops->pad->set_mbus_config(cfg_sd, 0, &mcfg); +#endif + if (ret < 0) { + vin_err("%s set_mbus_config error!\n", cfg_sd->name); + goto out; + } + } + + cfg_sd = pipe->sd[VIN_IND_CSI]; + if (cfg_sd) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) + ret = cfg_sd->ops->pad->get_mbus_config(cfg_sd, 0, &mcfg); +#else + ret = cfg_sd->ops->pad->set_mbus_config(cfg_sd, 0, &mcfg); +#endif + if (ret < 0) { + vin_err("%s set_mbus_config error!\n", cfg_sd->name); + goto out; + } + } + /* s_mbus_config on all mipi and csi */ me = &vinc->vid_cap.subdev.entity; mutex_lock(&vinc->vid_cap.vdev.entity.graph_obj.mdev->graph_mutex); @@ -1043,6 +1076,7 @@ static int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv, return -EINVAL; } + memset(&mf, 0, sizeof(mf)); mf.width = f->fmt.pix_mp.width; mf.height = f->fmt.pix_mp.height; mf.code = ffmt->mbus_code; @@ -1061,6 +1095,8 @@ static int __vin_set_fmt(struct vin_core *vinc, struct v4l2_format *f) struct vin_vid_cap *cap = &vinc->vid_cap; struct sensor_win_size win_cfg; struct v4l2_mbus_framefmt mf; + struct v4l2_subdev_format mipi_fmt; + struct v4l2_subdev_format csi_fmt; struct vin_fmt *ffmt = NULL; struct mbus_framefmt_res *res = (void *)mf.reserved; __maybe_unused struct vin_md *vind = dev_get_drvdata(vinc->v4l2_dev->dev); @@ -1086,6 +1122,7 @@ static int __vin_set_fmt(struct vin_core *vinc, struct v4l2_format *f) } cap->frame.fmt = *ffmt; + memset(&mf, 0, sizeof(mf)); mf.width = f->fmt.pix_mp.width; mf.height = f->fmt.pix_mp.height; mf.field = f->fmt.pix_mp.field; @@ -1106,7 +1143,11 @@ static int __vin_set_fmt(struct vin_core *vinc, struct v4l2_format *f) vin_log(VIN_LOG_FMT, "pipeline try fmt %d*%d code %x field %d colorspace %d\n", mf.width, mf.height, mf.code, mf.field, mf.colorspace); - vin_pipeline_set_mbus_config(vinc); + ret = vin_pipeline_set_mbus_config(vinc); + if (ret < 0) { + vin_err("vin_pipeline_set_mbus_config failed\n"); + return ret; + } /* get current win configs */ memset(&win_cfg, 0, sizeof(win_cfg)); @@ -1139,7 +1180,52 @@ static int __vin_set_fmt(struct vin_core *vinc, struct v4l2_format *f) sel.which = V4L2_SUBDEV_FORMAT_TRY; sel.pad = cap->pipe.sd[VIN_IND_CSI]->entity.num_pads - 1; + if (cap->pipe.sd[VIN_IND_SENSOR]) { + struct v4l2_subdev_format sensor_fmt; + + memset(&sensor_fmt, 0, sizeof(sensor_fmt)); + sensor_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + sensor_fmt.pad = SENSOR_PAD_SOURCE; + ret = v4l2_subdev_call(cap->pipe.sd[VIN_IND_SENSOR], pad, + get_fmt, NULL, &sensor_fmt); + if (ret < 0) { + vin_err("sensor get_fmt error! code = %d\n", ret); + goto out; + } + mf = sensor_fmt.format; + } + + ret = vin_pipeline_set_mbus_config(vinc); + if (ret < 0) { + vin_err("vin_pipeline_set_mbus_config failed\n"); + goto out; + } + + if (cap->pipe.sd[VIN_IND_MIPI]) { + memset(&mipi_fmt, 0, sizeof(mipi_fmt)); + mipi_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + mipi_fmt.pad = MIPI_PAD_SINK; + mipi_fmt.format = mf; + ret = v4l2_subdev_call(cap->pipe.sd[VIN_IND_MIPI], pad, + set_fmt, NULL, &mipi_fmt); + if (ret < 0) { + vin_err("mipi set_fmt error! code = %d\n", ret); + goto out; + } + } + if (cap->pipe.sd[VIN_IND_CSI]) { + memset(&csi_fmt, 0, sizeof(csi_fmt)); + csi_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + csi_fmt.pad = CSI_PAD_SINK; + csi_fmt.format = mf; + ret = v4l2_subdev_call(cap->pipe.sd[VIN_IND_CSI], pad, + set_fmt, NULL, &csi_fmt); + if (ret < 0) { + vin_err("csi parser set_fmt error! code = %d\n", ret); + goto out; + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0) memset(&state, 0, sizeof(state)); state.pads = &cfg; diff --git a/bsp/drivers/vin/vin.c b/bsp/drivers/vin/vin.c index 1e1fb28f3..97418c2e3 100644 --- a/bsp/drivers/vin/vin.c +++ b/bsp/drivers/vin/vin.c @@ -563,6 +563,7 @@ static void vin_md_clk_disable(struct vin_md *vind) if (vind->mipi_clk[VIN_MIPI_CLK].clock) clk_disable_unprepare(vind->mipi_clk[VIN_MIPI_CLK].clock); + vind->clk_en = false; #endif } @@ -803,6 +804,12 @@ static void vin_md_set_power(struct vin_md *vind, int on) #if IS_ENABLED(CONFIG_VIN_INIT_MELIS) && !defined CONFIG_RV_RUN_CAR_REVERSE if (on) { if (vind->sensor_power_on) { +#if IS_ENABLED(CONFIG_PM) + pm_runtime_get_sync(&vind->pdev->dev); +#else + vin_md_clk_enable(vind); +#endif + usleep_range(100, 120); csic_top_version_read_en(vind->id, 1); csic_feature_list_get(vind->id, &vind->csic_fl); csic_version_get(vind->id, &vind->csic_ver); @@ -817,7 +824,11 @@ static void vin_md_set_power(struct vin_md *vind, int on) #endif if (on) { +#if IS_ENABLED(CONFIG_PM) + pm_runtime_get_sync(&vind->pdev->dev); +#else vin_md_clk_enable(vind); +#endif usleep_range(100, 120); #if IS_ENABLED(CONFIG_ARCH_SUN60IW1) #ifdef MULTI_FRM_MERGE_INT @@ -881,7 +892,11 @@ static void vin_md_set_power(struct vin_md *vind, int on) csic_ccu_bk_intpool_clk_gating_en(0); #endif +#if IS_ENABLED(CONFIG_PM) + pm_runtime_put_sync(&vind->pdev->dev); +#else vin_md_clk_disable(vind); +#endif } } @@ -2225,7 +2240,7 @@ static int vin_create_media_links(struct vin_md *vind) static int vin_setup_default_links(struct vin_md *vind) { - struct v4l2_subdev *isp, *scaler; + struct v4l2_subdev *sensor, *mipi, *csi, *tdm_rx, *isp, *scaler; int i, ret = 0; for (i = 0; i < VIN_MAX_DEV; i++) { @@ -2237,6 +2252,56 @@ static int vin_setup_default_links(struct vin_md *vind) if (vinc == NULL) continue; + /* SENSOR */ + if (vinc->rear_sensor >= VIN_MAX_DEV || + vind->modules[vinc->rear_sensor].sensors.valid_idx == NO_VALID_SENSOR) + sensor = NULL; + else + sensor = vind->modules[vinc->rear_sensor].modules.sensor[ + vind->modules[vinc->rear_sensor].sensors.valid_idx].sd; + + /* MIPI */ + if (vinc->mipi_sel == 0xff) + mipi = NULL; + else + mipi = vind->mipi[vinc->mipi_sel].sd; + + /* CSI */ + if (vinc->csi_sel == 0xff) + csi = NULL; + else + csi = vind->csi[vinc->csi_sel].sd; + + /* TDM RX */ + if (vinc->tdm_rx_sel == 0xff) + tdm_rx = NULL; + else + tdm_rx = vind->tdm[vinc->tdm_rx_sel / TDM_RX_NUM].tdm_rx[vinc->tdm_rx_sel].sd; + + if (sensor && mipi) { + link = media_entity_find_link(&sensor->entity.pads[SENSOR_PAD_SOURCE], + &mipi->entity.pads[0]); + if (link) { + ret = media_entity_setup_link(link, MEDIA_LNK_FL_ENABLED); + if (ret) + vin_err("sensor to mipi setup link error\n"); + } else { + vin_err("sensor to mipi link null\n"); + } + } + + if (csi && tdm_rx) { + link = media_entity_find_link(&csi->entity.pads[CSI_PAD_SOURCE], + &tdm_rx->entity.pads[0]); + if (link) { + ret = media_entity_setup_link(link, MEDIA_LNK_FL_ENABLED); + if (ret) + vin_err("csi to tdm_rx setup link error\n"); + } else { + vin_err("csi to tdm_rx link null\n"); + } + } + /* ISP */ if (vinc->isp_sel == 0xff) isp = NULL; @@ -2655,10 +2720,22 @@ static void vin_shutdown(struct platform_device *pdev) int vin_runtime_suspend(struct device *d) { + struct vin_md *vind = dev_get_drvdata(d); + + if (vind) { + vin_log(VIN_LOG_POWER, "%s\n", __func__); + vin_md_clk_disable(vind); + } return 0; } int vin_runtime_resume(struct device *d) { + struct vin_md *vind = dev_get_drvdata(d); + + if (vind) { + vin_log(VIN_LOG_POWER, "%s\n", __func__); + return vin_md_clk_enable(vind); + } return 0; }