media: spi: rk1608: support multiple output format to isp

Change-Id: Icc9c14891d6f7494a6d6cc4752dabcf07278d708
Signed-off-by: Hu Kejun <william.hu@rock-chips.com>
This commit is contained in:
Hu Kejun
2019-04-25 18:18:24 +08:00
committed by Tao Huang
parent 3927673571
commit 27dccde04d
4 changed files with 227 additions and 111 deletions

View File

@@ -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,
};
/**

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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];
};