From 27dccde04dde076fdfc3522874feebea06e391a2 Mon Sep 17 00:00:00 2001 From: Hu Kejun Date: Thu, 25 Apr 2019 18:18:24 +0800 Subject: [PATCH] media: spi: rk1608: support multiple output format to isp Change-Id: Icc9c14891d6f7494a6d6cc4752dabcf07278d708 Signed-off-by: Hu Kejun --- drivers/media/spi/rk1608.c | 62 +++++--- drivers/media/spi/rk1608.h | 1 - drivers/media/spi/rk1608_dphy.c | 242 +++++++++++++++++++++----------- drivers/media/spi/rk1608_dphy.h | 33 +++-- 4 files changed, 227 insertions(+), 111 deletions(-) diff --git a/drivers/media/spi/rk1608.c b/drivers/media/spi/rk1608.c index 36d12b8a7e9d..d436f2a2c8c8 100644 --- a/drivers/media/spi/rk1608.c +++ b/drivers/media/spi/rk1608.c @@ -503,13 +503,15 @@ static int rk1608_lsb_w32(struct spi_device *spi, s32 addr, s32 data) static int rk1608_msg_init_sensor(struct rk1608_state *pdata, struct msg_init *msg, int id) { + u32 idx = pdata->dphy[id]->fmt_inf_idx; + msg->msg_head.size = sizeof(struct msg_init); msg->msg_head.type = id_msg_init_sensor_t; msg->msg_head.id.camera_id = id; msg->msg_head.mux.sync = 1; msg->in_mipi_phy = pdata->dphy[id]->in_mipi; msg->out_mipi_phy = pdata->dphy[id]->out_mipi; - msg->mipi_lane = pdata->dphy[id]->mipi_lane; + msg->mipi_lane = pdata->dphy[id]->fmt_inf[idx].mipi_lane; msg->bayer = 0; memcpy(msg->sensor_name, pdata->dphy[id]->sensor_name, sizeof(msg->sensor_name)); @@ -525,17 +527,19 @@ static int rk1608_msg_set_input_size(struct rk1608_state *pdata, { u32 i; u32 msg_size = sizeof(struct msg); + u32 idx = pdata->dphy[id]->fmt_inf_idx; + struct rk1608_fmt_inf *fmt_inf = &pdata->dphy[id]->fmt_inf[idx]; for (i = 0; i < 4; i++) { - if (pdata->dphy[id]->in_ch[i].width == 0) + if (fmt_inf->in_ch[i].width == 0) break; - msg->channel[i].width = pdata->dphy[id]->in_ch[i].width; - msg->channel[i].height = pdata->dphy[id]->in_ch[i].height; - msg->channel[i].data_id = pdata->dphy[id]->in_ch[i].data_id; + msg->channel[i].width = fmt_inf->in_ch[i].width; + msg->channel[i].height = fmt_inf->in_ch[i].height; + msg->channel[i].data_id = fmt_inf->in_ch[i].data_id; msg->channel[i].decode_format = - pdata->dphy[id]->in_ch[i].decode_format; - msg->channel[i].flag = pdata->dphy[id]->in_ch[i].flag; + fmt_inf->in_ch[i].decode_format; + msg->channel[i].flag = fmt_inf->in_ch[i].flag; msg_size += sizeof(struct preisp_vc_cfg); } @@ -552,17 +556,19 @@ static int rk1608_msg_set_output_size(struct rk1608_state *pdata, { u32 i; u32 msg_size = sizeof(struct msg_out_size_head); + u32 idx = pdata->dphy[id]->fmt_inf_idx; + struct rk1608_fmt_inf *fmt_inf = &pdata->dphy[id]->fmt_inf[idx]; for (i = 0; i < 4; i++) { - if (pdata->dphy[id]->out_ch[i].width == 0) + if (fmt_inf->out_ch[i].width == 0) break; - msg->channel[i].width = pdata->dphy[id]->out_ch[i].width; - msg->channel[i].height = pdata->dphy[id]->out_ch[i].height; - msg->channel[i].data_id = pdata->dphy[id]->out_ch[i].data_id; + msg->channel[i].width = fmt_inf->out_ch[i].width; + msg->channel[i].height = fmt_inf->out_ch[i].height; + msg->channel[i].data_id = fmt_inf->out_ch[i].data_id; msg->channel[i].decode_format = - pdata->dphy[id]->out_ch[i].decode_format; - msg->channel[i].flag = pdata->dphy[id]->out_ch[i].flag; + fmt_inf->out_ch[i].decode_format; + msg->channel[i].flag = fmt_inf->out_ch[i].flag; msg_size += sizeof(struct preisp_vc_cfg); } @@ -570,12 +576,12 @@ static int rk1608_msg_set_output_size(struct rk1608_state *pdata, msg->head.msg_head.type = id_msg_set_output_size_t; msg->head.msg_head.id.camera_id = id; msg->head.msg_head.mux.sync = 1; - msg->head.width = pdata->dphy[id]->mf.width; - msg->head.height = pdata->dphy[id]->mf.height; + msg->head.width = fmt_inf->mf.width; + msg->head.height = fmt_inf->mf.height; msg->head.mipi_clk = pdata->dphy[id]->link_freqs; - msg->head.line_length_pclk = pdata->dphy[id]->htotal; - msg->head.frame_length_lines = pdata->dphy[id]->vtotal; - msg->head.mipi_lane = pdata->dphy[id]->mipi_lane; + msg->head.line_length_pclk = fmt_inf->htotal; + msg->head.frame_length_lines = fmt_inf->vtotal; + msg->head.mipi_lane = fmt_inf->mipi_lane; return rk1608_send_msg_to_dsp(pdata, &msg->head.msg_head); } @@ -973,6 +979,21 @@ static int rk1608_g_frame_interval(struct v4l2_subdev *sd, return 0; } +static int rk1608_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct rk1608_state *pdata = to_state(sd); + + v4l2_subdev_call(pdata->sensor[sd->grp_id], + pad, + set_fmt, + cfg, + fmt); + + return 0; +} + static long rk1608_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) { struct rk1608_state *pdata = to_state(sd); @@ -1131,9 +1152,14 @@ static const struct v4l2_subdev_core_ops rk1608_core_ops = { .ioctl = rk1608_ioctl, }; +static const struct v4l2_subdev_pad_ops rk1608_subdev_pad_ops = { + .set_fmt = rk1608_set_fmt, +}; + static const struct v4l2_subdev_ops rk1608_subdev_ops = { .core = &rk1608_core_ops, .video = &rk1608_subdev_video_ops, + .pad = &rk1608_subdev_pad_ops, }; /** diff --git a/drivers/media/spi/rk1608.h b/drivers/media/spi/rk1608.h index e5b5d47ad839..dbfee08ba2ff 100644 --- a/drivers/media/spi/rk1608.h +++ b/drivers/media/spi/rk1608.h @@ -122,7 +122,6 @@ struct rk1608_state { struct v4l2_ctrl *exposure; struct v4l2_ctrl *gain; struct v4l2_ctrl_handler ctrl_handler; - s64 link_freqs; u32 max_speed_hz; u32 min_speed_hz; struct preisp_hdrae_para_s hdrae_para; diff --git a/drivers/media/spi/rk1608_dphy.c b/drivers/media/spi/rk1608_dphy.c index 32c6143765f2..dd52c7a4eecd 100644 --- a/drivers/media/spi/rk1608_dphy.c +++ b/drivers/media/spi/rk1608_dphy.c @@ -123,10 +123,10 @@ static int rk1608_enum_mbus_code(struct v4l2_subdev *sd, { struct rk1608_dphy *pdata = to_state(sd); - if (code->index > 0) + if (code->index > pdata->fmt_inf_num) return -EINVAL; - code->code = pdata->mf.code; + code->code = pdata->fmt_inf[code->index].mf.code; return 0; } @@ -137,16 +137,16 @@ static int rk1608_enum_frame_sizes(struct v4l2_subdev *sd, { struct rk1608_dphy *pdata = to_state(sd); - if (fse->index > 0) + if (fse->index > pdata->fmt_inf_num) return -EINVAL; - if (fse->code != pdata->mf.code) + if (fse->code != pdata->fmt_inf[fse->index].mf.code) return -EINVAL; - fse->min_width = pdata->mf.width; - fse->max_width = pdata->mf.width; - fse->max_height = pdata->mf.height; - fse->min_height = pdata->mf.height; + fse->min_width = pdata->fmt_inf[fse->index].mf.width; + fse->max_width = pdata->fmt_inf[fse->index].mf.width; + fse->max_height = pdata->fmt_inf[fse->index].mf.height; + fse->min_height = pdata->fmt_inf[fse->index].mf.height; return 0; } @@ -157,22 +157,50 @@ static int rk1608_get_fmt(struct v4l2_subdev *sd, { struct v4l2_mbus_framefmt *mf = &fmt->format; struct rk1608_dphy *pdata = to_state(sd); + u32 idx = pdata->fmt_inf_idx; - mf->code = pdata->mf.code; - mf->width = pdata->mf.width; - mf->height = pdata->mf.height; - mf->field = pdata->mf.field; - mf->colorspace = pdata->mf.colorspace; + mf->code = pdata->fmt_inf[idx].mf.code; + mf->width = pdata->fmt_inf[idx].mf.width; + mf->height = pdata->fmt_inf[idx].mf.height; + mf->field = pdata->fmt_inf[idx].mf.field; + mf->colorspace = pdata->fmt_inf[idx].mf.colorspace; return 0; } +static int rk1608_get_reso_dist(struct rk1608_fmt_inf *fmt_inf, + struct v4l2_subdev_format *fmt) +{ + struct v4l2_mbus_framefmt *framefmt = &fmt->format; + + return abs(fmt_inf->mf.width - framefmt->width) + + abs(fmt_inf->mf.height - framefmt->height); +} + static int rk1608_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct v4l2_ctrl *remote_ctrl; struct rk1608_dphy *pdata = to_state(sd); + u32 i, idx = 0; + int dist; + int cur_best_fit_dist = -1; + + for (i = 0; i < pdata->fmt_inf_num; i++) { + dist = rk1608_get_reso_dist(&pdata->fmt_inf[i], fmt); + if (cur_best_fit_dist == -1 || dist < cur_best_fit_dist) { + cur_best_fit_dist = dist; + idx = i; + } + } + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) + return -ENOTTY; + + pdata->fmt_inf_idx = idx; + + v4l2_subdev_call(pdata->rk1608_sd, pad, set_fmt, cfg, fmt); pdata->rk1608_sd->grp_id = pdata->sd.grp_id; remote_ctrl = v4l2_ctrl_find(pdata->rk1608_sd->ctrl_handler, @@ -341,6 +369,7 @@ static int rk1608_initialize_controls(struct rk1608_dphy *dphy) u32 i; int ret; s64 pixel_rate, pixel_bit; + u32 idx = dphy->fmt_inf_idx; struct v4l2_ctrl_handler *handler; unsigned long flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; @@ -356,7 +385,7 @@ static int rk1608_initialize_controls(struct rk1608_dphy *dphy) if (dphy->link_freq) dphy->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; - switch (dphy->data_type) { + switch (dphy->fmt_inf[idx].data_type) { case 0x2b: pixel_bit = 10; break; @@ -367,7 +396,7 @@ static int rk1608_initialize_controls(struct rk1608_dphy *dphy) pixel_bit = 8; break; } - pixel_rate = dphy->link_freqs * dphy->mipi_lane * 2; + pixel_rate = dphy->link_freqs * dphy->fmt_inf[idx].mipi_lane * 2; do_div(pixel_rate, pixel_bit); dphy->pixel_rate = v4l2_ctrl_new_std(handler, NULL, V4L2_CID_PIXEL_RATE, @@ -456,90 +485,143 @@ static int rk1608_dphy_dt_property(struct rk1608_dphy *dphy) { int ret = 0; struct device_node *node = dphy->dev->of_node; + struct device_node *parent_node = of_node_get(node); + struct device_node *prev_node = NULL; + u32 idx = 0; ret = of_property_read_u32(node, "id", &dphy->sd.grp_id); if (ret) dev_warn(dphy->dev, "Can not get id!"); + ret = of_property_read_u32(node, "cam_nums", &dphy->cam_nums); if (ret) dev_warn(dphy->dev, "Can not get cam_nums!"); - ret = of_property_read_u32(node, "data_type", &dphy->data_type); - if (ret) - dev_warn(dphy->dev, "Can not get data_type!"); + ret = of_property_read_u32(node, "in_mipi", &dphy->in_mipi); if (ret) dev_warn(dphy->dev, "Can not get in_mipi!"); + ret = of_property_read_u32(node, "out_mipi", &dphy->out_mipi); if (ret) dev_warn(dphy->dev, "Can not get out_mipi!"); - ret = of_property_read_u32(node, "mipi_lane", &dphy->mipi_lane); - if (ret) - dev_warn(dphy->dev, "Can not get mipi_lane!"); - ret = of_property_read_u32(node, "sensor_i2c_bus", &dphy->i2c_bus); - if (ret) - dev_warn(dphy->dev, "Can not get sensor_i2c_bus!"); - ret = of_property_read_u32(node, "sensor_i2c_addr", &dphy->i2c_addr); - if (ret) - dev_warn(dphy->dev, "Can not get sensor_i2c_addr!"); - ret = of_property_read_u32(node, "field", &dphy->mf.field); - if (ret) - dev_warn(dphy->dev, "Can not get field!"); - ret = of_property_read_u32(node, "colorspace", &dphy->mf.colorspace); - if (ret) - dev_warn(dphy->dev, "Can not get colorspace!"); - ret = of_property_read_u32(node, "code", &dphy->mf.code); - if (ret) - dev_warn(dphy->dev, "Can not get code!"); - ret = of_property_read_u32(node, "width", &dphy->mf.width); - if (ret) - dev_warn(dphy->dev, "Can not get width!"); - ret = of_property_read_u32(node, "height", &dphy->mf.height); - if (ret) - dev_warn(dphy->dev, "Can not get height!"); - ret = of_property_read_u32(node, "htotal", &dphy->htotal); - if (ret) - dev_warn(dphy->dev, "Can not get htotal!"); - ret = of_property_read_u32(node, "vtotal", &dphy->vtotal); - if (ret) - dev_warn(dphy->dev, "Can not get vtotal!"); + ret = of_property_read_u64(node, "link-freqs", &dphy->link_freqs); if (ret) dev_warn(dphy->dev, "Can not get link_freqs!"); + + ret = of_property_read_u32(node, "sensor_i2c_bus", &dphy->i2c_bus); + if (ret) + dev_warn(dphy->dev, "Can not get sensor_i2c_bus!"); + + ret = of_property_read_u32(node, "sensor_i2c_addr", &dphy->i2c_addr); + if (ret) + dev_warn(dphy->dev, "Can not get sensor_i2c_addr!"); + ret = of_property_read_string(node, "sensor-name", &dphy->sensor_name); if (ret) dev_warn(dphy->dev, "Can not get sensor-name!"); - ret = of_property_read_u32_array(node, "inch0-info", - (u32 *)&dphy->in_ch[0], 5); - if (ret) - dev_warn(dphy->dev, "Can not get inch0-info!"); - ret = of_property_read_u32_array(node, "inch1-info", - (u32 *)&dphy->in_ch[1], 5); - if (ret) - dev_info(dphy->dev, "Can not get inch1-info!"); - ret = of_property_read_u32_array(node, "inch2-info", - (u32 *)&dphy->in_ch[2], 5); - if (ret) - dev_info(dphy->dev, "Can not get inch2-info!"); - ret = of_property_read_u32_array(node, "inch3-info", - (u32 *)&dphy->in_ch[3], 5); - if (ret) - dev_info(dphy->dev, "Can not get inch3-info!"); - ret = of_property_read_u32_array(node, "outch0-info", - (u32 *)&dphy->out_ch[0], 5); - if (ret) - dev_warn(dphy->dev, "Can not get outch0-info!"); - ret = of_property_read_u32_array(node, "outch1-info", - (u32 *)&dphy->out_ch[1], 5); - if (ret) - dev_info(dphy->dev, "Can not get outch1-info!"); - ret = of_property_read_u32_array(node, "outch2-info", - (u32 *)&dphy->out_ch[2], 5); - if (ret) - dev_info(dphy->dev, "Can not get outch2-info!"); - ret = of_property_read_u32_array(node, "outch3-info", - (u32 *)&dphy->out_ch[3], 5); - if (ret) - dev_info(dphy->dev, "Can not get outch3-info!"); + + node = NULL; + while (!IS_ERR_OR_NULL(node = + of_get_next_child(parent_node, prev_node))) { + if (!strncasecmp(node->name, + "format-config", + strlen("format-config"))) { + ret = of_property_read_u32(node, "data_type", + &dphy->fmt_inf[idx].data_type); + if (ret) + dev_warn(dphy->dev, "Can not get data_type!"); + + ret = of_property_read_u32(node, "mipi_lane", + &dphy->fmt_inf[idx].mipi_lane); + if (ret) + dev_warn(dphy->dev, "Can not get mipi_lane!"); + + ret = of_property_read_u32(node, "field", + &dphy->fmt_inf[idx].mf.field); + if (ret) + dev_warn(dphy->dev, "Can not get field!"); + + ret = of_property_read_u32(node, "colorspace", + &dphy->fmt_inf[idx].mf.colorspace); + if (ret) + dev_warn(dphy->dev, "Can not get colorspace!"); + + ret = of_property_read_u32(node, "code", + &dphy->fmt_inf[idx].mf.code); + if (ret) + dev_warn(dphy->dev, "Can not get code!"); + + ret = of_property_read_u32(node, "width", + &dphy->fmt_inf[idx].mf.width); + if (ret) + dev_warn(dphy->dev, "Can not get width!"); + + ret = of_property_read_u32(node, "height", + &dphy->fmt_inf[idx].mf.height); + if (ret) + dev_warn(dphy->dev, "Can not get height!"); + + ret = of_property_read_u32(node, "htotal", + &dphy->fmt_inf[idx].htotal); + if (ret) + dev_warn(dphy->dev, "Can not get htotal!"); + + ret = of_property_read_u32(node, "vtotal", + &dphy->fmt_inf[idx].vtotal); + if (ret) + dev_warn(dphy->dev, "Can not get vtotal!"); + + ret = of_property_read_u32_array(node, "inch0-info", + (u32 *)&dphy->fmt_inf[idx].in_ch[0], 5); + if (ret) + dev_warn(dphy->dev, "Can not get inch0-info!"); + + ret = of_property_read_u32_array(node, "inch1-info", + (u32 *)&dphy->fmt_inf[idx].in_ch[1], 5); + if (ret) + dev_info(dphy->dev, "Can not get inch1-info!"); + + ret = of_property_read_u32_array(node, "inch2-info", + (u32 *)&dphy->fmt_inf[idx].in_ch[2], 5); + if (ret) + dev_info(dphy->dev, "Can not get inch2-info!"); + + ret = of_property_read_u32_array(node, "inch3-info", + (u32 *)&dphy->fmt_inf[idx].in_ch[3], 5); + if (ret) + dev_info(dphy->dev, "Can not get inch3-info!"); + + ret = of_property_read_u32_array(node, "outch0-info", + (u32 *)&dphy->fmt_inf[idx].out_ch[0], 5); + if (ret) + dev_warn(dphy->dev, "Can not get outch0-info!"); + + ret = of_property_read_u32_array(node, "outch1-info", + (u32 *)&dphy->fmt_inf[idx].out_ch[1], 5); + if (ret) + dev_info(dphy->dev, "Can not get outch1-info!"); + + ret = of_property_read_u32_array(node, "outch2-info", + (u32 *)&dphy->fmt_inf[idx].out_ch[2], 5); + if (ret) + dev_info(dphy->dev, "Can not get outch2-info!"); + + ret = of_property_read_u32_array(node, "outch3-info", + (u32 *)&dphy->fmt_inf[idx].out_ch[3], 5); + if (ret) + dev_info(dphy->dev, "Can not get outch3-info!"); + + idx++; + } + + of_node_put(prev_node); + prev_node = node; + } + dphy->fmt_inf_num = idx; + + of_node_put(prev_node); + of_node_put(parent_node); return ret; } diff --git a/drivers/media/spi/rk1608_dphy.h b/drivers/media/spi/rk1608_dphy.h index 918fd72a774a..e68eb2bdc2da 100644 --- a/drivers/media/spi/rk1608_dphy.h +++ b/drivers/media/spi/rk1608_dphy.h @@ -1,5 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ +#define RK1608_MAX_FMTINF 4 + struct rk1608_chinf { u32 width; u32 height; @@ -8,13 +10,22 @@ struct rk1608_chinf { u32 flag; }; +struct rk1608_fmt_inf { + u32 data_type; + u32 mipi_lane; + u32 htotal; + u32 vtotal; + struct v4l2_mbus_framefmt mf; + struct rk1608_chinf in_ch[4]; + struct rk1608_chinf out_ch[4]; +}; + struct rk1608_dphy { struct v4l2_subdev sd; struct v4l2_subdev *rk1608_sd; struct platform_device *pdev; struct device *dev; struct media_pad pad; - struct v4l2_mbus_framefmt mf; struct v4l2_ctrl *link_freq; struct v4l2_ctrl *pixel_rate; struct v4l2_ctrl *hblank; @@ -22,24 +33,22 @@ struct rk1608_dphy { struct v4l2_ctrl *exposure; struct v4l2_ctrl *gain; struct v4l2_ctrl_handler ctrl_handler; + u32 cam_nums; - u32 data_type; u32 in_mipi; u32 out_mipi; - u32 mipi_lane; - - u32 htotal; - u32 vtotal; s64 link_freqs; - u32 module_index; - const char *module_facing; - const char *module_name; - const char *len_name; u32 i2c_bus; u32 i2c_addr; const char *sensor_name; - struct rk1608_chinf in_ch[4]; - struct rk1608_chinf out_ch[4]; + u32 module_index; + const char *module_facing; + const char *module_name; + const char *len_name; + + u32 fmt_inf_num; + u32 fmt_inf_idx; + struct rk1608_fmt_inf fmt_inf[RK1608_MAX_FMTINF]; };