media: sunxi-vin: bring up BPI-M8 IMX415 CSI
This commit is contained in:
parent
beb389776e
commit
e49ff5bdd9
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user