From 1543e317f1da31b75942316931e8f491a8920811 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Thu, 04 Jan 2024 10:08:02 +0000
Subject: [PATCH] disable FB
---
kernel/drivers/media/spi/rk1608_dphy.c | 387 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 373 insertions(+), 14 deletions(-)
diff --git a/kernel/drivers/media/spi/rk1608_dphy.c b/kernel/drivers/media/spi/rk1608_dphy.c
index 0740bd9..378ba55 100644
--- a/kernel/drivers/media/spi/rk1608_dphy.c
+++ b/kernel/drivers/media/spi/rk1608_dphy.c
@@ -24,9 +24,10 @@
#include <linux/of_platform.h>
#include <linux/types.h>
#include <linux/rk-preisp.h>
-#include <linux/rkisp1-config.h>
+#include <linux/rk-isp1-config.h>
#include <linux/rk-camera-module.h>
#include "rk1608_dphy.h"
+#include <linux/compat.h>
#define RK1608_DPHY_NAME "RK1608-dphy"
@@ -109,9 +110,114 @@
return ret;
}
+#define RK1608_MAX_BITRATE (1500000000)
+static int rk1608_get_link_sensor_timing(struct rk1608_dphy *pdata)
+{
+ int ret = 0;
+ u32 i;
+ u32 idx = pdata->fmt_inf_idx;
+ struct rk1608_fmt_inf *fmt_inf = &pdata->fmt_inf[idx];
+ int sub_sensor_num = pdata->sub_sensor_num;
+ u32 width = 0, height = 0, out_width, out_height;
+ struct v4l2_subdev *link_sensor;
+ u32 id = pdata->sd.grp_id;
+ struct v4l2_subdev_frame_interval fi;
+ int max_fps = 30;
+ u64 bps;
+
+ struct v4l2_subdev_format fmt = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ .pad = 0,
+ };
+
+ if (!IS_ERR_OR_NULL(pdata->link_sensor_client)) {
+
+ link_sensor = i2c_get_clientdata(
+ pdata->link_sensor_client);
+ if (IS_ERR_OR_NULL(link_sensor)) {
+ dev_err(pdata->dev, "can not get link sensor i2c client\n");
+ return -EINVAL;
+ }
+
+ ret = v4l2_subdev_call(link_sensor, pad, get_fmt, NULL, &fmt);
+ if (ret) {
+ dev_info(pdata->dev, "get link fmt fail\n");
+ return -EINVAL;
+ }
+
+ width = fmt.format.width;
+ height = fmt.format.height;
+ dev_info(pdata->dev, "phy[%d] get fmt w:%d h:%d\n",
+ id, width, height);
+
+ memset(&fi, 0, sizeof(fi));
+ ret = v4l2_subdev_call(link_sensor, video, g_frame_interval, &fi);
+ if (ret) {
+ dev_info(pdata->dev, "get link interval fail\n");
+ return -EINVAL;
+ }
+
+ max_fps = fi.interval.denominator / fi.interval.numerator;
+ dev_info(pdata->dev, "phy[%d] get fps:%d (%d/%d)\n",
+ id, max_fps, fi.interval.denominator, fi.interval.numerator);
+
+ } else {
+ width = fmt_inf->mf.width;
+ height = fmt_inf->mf.height;
+ dev_info(pdata->dev, "phy[%d] no link sensor\n", id);
+ }
+
+ if (!width || !height) {
+ dev_err(pdata->dev, "phy[%d] get fmt error!\n", id);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < 4; i++) {
+ if (fmt_inf->in_ch[i].width == 0)
+ break;
+
+ fmt_inf->in_ch[i].width = width;
+ fmt_inf->in_ch[i].height = height;
+ }
+
+ out_width = width;
+ out_height = height * (sub_sensor_num + 1); /* sub add main */
+ for (i = 0; i < 4; i++) {
+ if (fmt_inf->out_ch[i].width == 0)
+ break;
+
+ fmt_inf->out_ch[i].width = out_width;
+ fmt_inf->out_ch[i].height = out_height;
+ }
+
+ fmt_inf->hactive = out_width;
+ fmt_inf->vactive = out_height;
+ fmt_inf->htotal = out_width + (width * 1 / 3); //1.33
+ fmt_inf->vtotal = out_height + (height >> 4);
+
+ /* max 30 fps, raw 10 */
+ bps = fmt_inf->htotal * fmt_inf->vtotal
+ / fmt_inf->mipi_lane_out * 10 * max_fps;
+
+ /* add extra timing */
+ bps = bps * 105;
+ do_div(bps, 100);
+
+ if (bps > RK1608_MAX_BITRATE)
+ bps = RK1608_MAX_BITRATE;
+
+ pdata->link_freqs = (u32)(bps/2);
+ dev_info(pdata->dev, "target mipi bps:%lld\n", bps);
+
+ return 0;
+}
+
static int rk1608_s_stream(struct v4l2_subdev *sd, int enable)
{
struct rk1608_dphy *pdata = to_state(sd);
+
+ if (enable && pdata->sub_sensor_num)
+ rk1608_get_link_sensor_timing(pdata);
pdata->rk1608_sd->grp_id = sd->grp_id;
v4l2_subdev_call(pdata->rk1608_sd, video, s_stream, enable);
@@ -159,12 +265,43 @@
struct v4l2_mbus_framefmt *mf = &fmt->format;
struct rk1608_dphy *pdata = to_state(sd);
u32 idx = pdata->fmt_inf_idx;
+ struct v4l2_subdev *link_sensor;
+ int ret = -1;
- 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;
+ if (!IS_ERR_OR_NULL(pdata->link_sensor_client)) {
+ link_sensor = i2c_get_clientdata(pdata->link_sensor_client);
+ if (IS_ERR_OR_NULL(link_sensor)) {
+ dev_err(pdata->dev, "can not get link sensor i2c client\n");
+ goto exit;
+ }
+
+ ret = v4l2_subdev_call(link_sensor, pad, get_fmt, NULL, fmt);
+ if (ret) {
+ dev_info(pdata->dev, "get link fmt fail\n");
+ goto exit;
+ }
+
+ dev_info(pdata->dev, "use link sensor fmt w:%d h:%d code:%d\n",
+ mf->width, mf->height, mf->code);
+ }
+
+exit:
+ if (ret || !mf->width || !mf->height) {
+ 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;
+ } else {
+ pdata->fmt_inf[idx].mf.code = mf->code;
+ pdata->fmt_inf[idx].mf.width = mf->width;
+ pdata->fmt_inf[idx].mf.height = mf->height;
+ pdata->fmt_inf[idx].mf.field = mf->field;
+ pdata->fmt_inf[idx].mf.colorspace = mf->colorspace;
+ }
+
+ if (pdata->sub_sensor_num)
+ rk1608_get_link_sensor_timing(pdata);
return 0;
}
@@ -201,9 +338,9 @@
pdata->fmt_inf_idx = idx;
+ pdata->rk1608_sd->grp_id = pdata->sd.grp_id;
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,
V4L2_CID_HBLANK);
if (remote_ctrl) {
@@ -233,7 +370,30 @@
struct v4l2_subdev_frame_interval *fi)
{
struct rk1608_dphy *pdata = to_state(sd);
+ struct v4l2_subdev *link_sensor;
+ int ret = 0;
+ if (!IS_ERR_OR_NULL(pdata->link_sensor_client)) {
+ link_sensor = i2c_get_clientdata(pdata->link_sensor_client);
+ if (IS_ERR_OR_NULL(link_sensor)) {
+ dev_err(pdata->dev, "can not get link sensor i2c client\n");
+ return -EINVAL;
+ }
+
+ ret = v4l2_subdev_call(link_sensor,
+ video,
+ g_frame_interval,
+ fi);
+ if (ret)
+ dev_info(pdata->dev, "get link interval fail\n");
+ else
+ return ret;
+ }
+
+ if (!(pdata->rk1608_sd)) {
+ dev_info(pdata->dev, "pdata->rk1608_sd NULL\n");
+ return -EFAULT;
+ }
pdata->rk1608_sd->grp_id = sd->grp_id;
v4l2_subdev_call(pdata->rk1608_sd,
video,
@@ -249,18 +409,18 @@
return 0;
}
-static int rk1608_g_mbus_config(struct v4l2_subdev *sd,
+static int rk1608_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad_id,
struct v4l2_mbus_config *config)
{
struct rk1608_dphy *pdata = to_state(sd);
u32 val = 0;
- val = 1 << (pdata->fmt_inf[pdata->fmt_inf_idx].mipi_lane - 1) |
+ val = 1 << (pdata->fmt_inf[pdata->fmt_inf_idx].mipi_lane_out - 1) |
V4L2_MBUS_CSI2_CHANNEL_0 |
V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
- config->type = V4L2_MBUS_CSI2;
+ config->type = V4L2_MBUS_CSI2_DPHY;
config->flags = val;
return 0;
@@ -269,6 +429,7 @@
static long rk1608_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
struct rk1608_dphy *pdata = to_state(sd);
+ struct v4l2_subdev *link_sensor;
long ret = 0;
switch (cmd) {
@@ -289,11 +450,22 @@
case PREISP_DISP_WRITE_EEPROM:
case PREISP_DISP_READ_EEPROM:
case PREISP_DISP_SET_LED_ON_OFF:
+ case RKMODULE_SET_QUICK_STREAM:
mutex_lock(&rk1608_dphy_mutex);
pdata->rk1608_sd->grp_id = pdata->sd.grp_id;
ret = v4l2_subdev_call(pdata->rk1608_sd, core, ioctl,
cmd, arg);
mutex_unlock(&rk1608_dphy_mutex);
+ break;
+ case RKMODULE_GET_CSI_DPHY_PARAM:
+ if (!IS_ERR_OR_NULL(pdata->link_sensor_client)) {
+ link_sensor = i2c_get_clientdata(pdata->link_sensor_client);
+ if (IS_ERR_OR_NULL(link_sensor)) {
+ dev_err(pdata->dev, "can not get link sensor i2c client\n");
+ return -EINVAL;
+ }
+ ret = v4l2_subdev_call(link_sensor, core, ioctl, cmd, arg);
+ }
break;
default:
ret = -ENOIOCTLCMD;
@@ -310,7 +482,9 @@
struct preisp_hdrae_exp_s hdrae_exp;
struct rkmodule_inf *inf;
struct rkmodule_awb_cfg *cfg;
- long ret;
+ struct rkmodule_csi_dphy_param *dphy_param;
+ u32 stream;
+ long ret = -EFAULT;
switch (cmd) {
case PREISP_CMD_SET_HDRAE_EXP:
@@ -327,7 +501,10 @@
ret = rk1608_ioctl(sd, cmd, inf);
if (!ret)
- ret = copy_to_user(up, inf, sizeof(*inf));
+ if (copy_to_user(up, inf, sizeof(*inf))) {
+ kfree(inf);
+ return -EFAULT;
+ }
kfree(inf);
break;
case RKMODULE_AWB_CFG:
@@ -336,10 +513,29 @@
ret = -ENOMEM;
return ret;
}
- if (copy_from_user(cfg, up, sizeof(cfg)))
+ if (copy_from_user(cfg, up, sizeof(*cfg)))
return -EFAULT;
ret = rk1608_ioctl(sd, cmd, cfg);
kfree(cfg);
+ break;
+ case RKMODULE_SET_QUICK_STREAM:
+ ret = copy_from_user(&stream, up, sizeof(u32));
+ if (!ret)
+ ret = rk1608_ioctl(sd, cmd, &stream);
+ else
+ ret = -EFAULT;
+
+ break;
+ case RKMODULE_GET_CSI_DPHY_PARAM:
+ dphy_param = kzalloc(sizeof(*dphy_param), GFP_KERNEL);
+ if (!dphy_param) {
+ ret = -ENOMEM;
+ return ret;
+ }
+ if (copy_from_user(dphy_param, up, sizeof(*dphy_param)))
+ return -EFAULT;
+ ret = rk1608_ioctl(sd, cmd, dphy_param);
+ kfree(dphy_param);
break;
default:
ret = -ENOIOCTLCMD;
@@ -385,6 +581,87 @@
ctrl->id);
if (remote_ctrl)
ret = v4l2_ctrl_s_ctrl(remote_ctrl, ctrl->val);
+
+ return ret;
+}
+
+#define CROP_START(SRC, DST) (((SRC) - (DST)) / 2 / 4 * 4)
+static int rk1608_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_selection *sel)
+{
+ struct rk1608_dphy *pdata = to_state(sd);
+ u32 idx = pdata->fmt_inf_idx;
+ u32 width = pdata->fmt_inf[idx].mf.width;
+ u32 height = pdata->fmt_inf[idx].mf.height;
+ struct v4l2_subdev *link_sensor;
+ int ret = -EINVAL;
+
+ if (sel->target != V4L2_SEL_TGT_CROP_BOUNDS)
+ return -EINVAL;
+
+ if (!IS_ERR_OR_NULL(pdata->link_sensor_client)) {
+ link_sensor = i2c_get_clientdata(pdata->link_sensor_client);
+ if (IS_ERR_OR_NULL(link_sensor)) {
+ dev_err(pdata->dev, "can not get link sensor i2c client\n");
+ goto err;
+ }
+
+ ret = v4l2_subdev_call(link_sensor, pad, get_selection, NULL, sel);
+ if (!ret)
+ return 0;
+ }
+
+err:
+ if (pdata->fmt_inf[idx].hcrop && pdata->fmt_inf[idx].vcrop) {
+ width = pdata->fmt_inf[idx].hcrop;
+ height = pdata->fmt_inf[idx].vcrop;
+ }
+
+ sel->r.left = CROP_START(pdata->fmt_inf[idx].mf.width, width);
+ sel->r.top = CROP_START(pdata->fmt_inf[idx].mf.height, height);
+ sel->r.width = width;
+ sel->r.height = height;
+
+ return 0;
+}
+
+static int rk1608_enum_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_interval_enum *fie)
+{
+ struct rk1608_dphy *pdata = to_state(sd);
+ u32 idx = pdata->fmt_inf_idx;
+ int ret = 0;
+ struct v4l2_fract max_fps = {
+ .numerator = 10000,
+ .denominator = 300000,
+ };
+ struct v4l2_subdev *link_sensor;
+
+ if (!IS_ERR_OR_NULL(pdata->link_sensor_client)) {
+ link_sensor = i2c_get_clientdata(pdata->link_sensor_client);
+ if (IS_ERR_OR_NULL(link_sensor)) {
+ dev_err(pdata->dev, "can not get link sensor i2c client\n");
+ goto err;
+ }
+
+ ret = v4l2_subdev_call(link_sensor,
+ pad,
+ enum_frame_interval,
+ NULL,
+ fie);
+ return ret;
+ }
+
+err:
+ if (fie->index >= pdata->fmt_inf_num)
+ return -EINVAL;
+
+ fie->code = pdata->fmt_inf[idx].mf.code;
+ fie->width = pdata->fmt_inf[idx].mf.width;
+ fie->height = pdata->fmt_inf[idx].mf.height;
+ fie->interval = max_fps;
return ret;
}
@@ -511,7 +788,6 @@
.s_stream = rk1608_s_stream,
.g_frame_interval = rk1608_g_frame_interval,
.s_frame_interval = rk1608_s_frame_interval,
- .g_mbus_config = rk1608_g_mbus_config,
};
static const struct v4l2_subdev_pad_ops rk1608_subdev_pad_ops = {
@@ -519,6 +795,9 @@
.enum_frame_size = rk1608_enum_frame_sizes,
.get_fmt = rk1608_get_fmt,
.set_fmt = rk1608_set_fmt,
+ .get_mbus_config = rk1608_g_mbus_config,
+ .get_selection = rk1608_get_selection,
+ .enum_frame_interval = rk1608_enum_frame_interval,
};
static const struct v4l2_subdev_core_ops rk1608_core_ops = {
@@ -541,7 +820,9 @@
struct device_node *node = dphy->dev->of_node;
struct device_node *parent_node = of_node_get(node);
struct device_node *prev_node = NULL;
+ struct i2c_client *link_sensor_client;
u32 idx = 0;
+ u32 sub_idx = 0;
ret = of_property_read_u32(node, "id", &dphy->sd.grp_id);
if (ret)
@@ -590,6 +871,11 @@
&dphy->fmt_inf[idx].mipi_lane);
if (ret)
dev_warn(dphy->dev, "Can not get mipi_lane!");
+
+ ret = of_property_read_u32(node, "mipi_lane_out",
+ &dphy->fmt_inf[idx].mipi_lane_out);
+ if (ret)
+ dev_warn(dphy->dev, "Can not get mipi_lane_out!");
ret = of_property_read_u32(node, "field",
&dphy->fmt_inf[idx].mf.field);
@@ -676,6 +962,16 @@
if (ret)
dev_info(dphy->dev, "Can not get outch3-info!");
+ ret = of_property_read_u32(node, "hcrop",
+ &dphy->fmt_inf[idx].hcrop);
+ if (ret)
+ dev_warn(dphy->dev, "Can not get hcrop!");
+
+ ret = of_property_read_u32(node, "vcrop",
+ &dphy->fmt_inf[idx].vcrop);
+ if (ret)
+ dev_warn(dphy->dev, "Can not get vcrop!");
+
idx++;
}
@@ -684,6 +980,69 @@
}
dphy->fmt_inf_num = idx;
+ prev_node = NULL;
+ /* get virtual sub sensor */
+ node = NULL;
+ while (!IS_ERR_OR_NULL(node =
+ of_get_next_child(parent_node, prev_node))) {
+ if (!strncasecmp(node->name,
+ "virtual-sub-sensor-config",
+ strlen("virtual-sub-sensor-config"))) {
+
+ if (sub_idx >= 4) {
+ dev_err(dphy->dev, "get too mach sub_sensor node, max 4.\n");
+ break;
+ }
+
+ ret = of_property_read_u32(node, "id",
+ &dphy->sub_sensor[sub_idx].id);
+ if (ret)
+ dev_warn(dphy->dev, "Can not get sub sensor id!");
+ else
+ dev_info(dphy->dev, "get sub sensor id:%d",
+ dphy->sub_sensor[sub_idx].id);
+
+ ret = of_property_read_u32(node, "in_mipi",
+ &dphy->sub_sensor[sub_idx].in_mipi);
+ if (ret)
+ dev_warn(dphy->dev, "Can not get sub sensor in_mipi!");
+ else
+ dev_info(dphy->dev, "get sub sensor in_mipi:%d",
+ dphy->sub_sensor[sub_idx].in_mipi);
+
+ ret = of_property_read_u32(node, "out_mipi",
+ &dphy->sub_sensor[sub_idx].out_mipi);
+ if (ret)
+ dev_warn(dphy->dev, "Can not get sub sensor out_mipi!");
+ else
+ dev_info(dphy->dev, "get sub sensor out_mipi:%d",
+ dphy->sub_sensor[sub_idx].out_mipi);
+
+ sub_idx++;
+ }
+
+ of_node_put(prev_node);
+ prev_node = node;
+ }
+ dphy->sub_sensor_num = sub_idx;
+
+ node = of_parse_phandle(parent_node, "link-sensor", 0);
+ if (node) {
+ dev_info(dphy->dev, "get link sensor node:%s\n", node->full_name);
+ link_sensor_client =
+ of_find_i2c_device_by_node(node);
+ of_node_put(node);
+ if (IS_ERR_OR_NULL(link_sensor_client)) {
+ dev_err(dphy->dev, "can not get link sensor node\n");
+ } else {
+ dphy->link_sensor_client = link_sensor_client;
+ dev_info(dphy->dev, "get link sensor client\n");
+ }
+ } else {
+ dev_err(dphy->dev, "can not get link-sensor node\n");
+ }
+ /* get virtual sub sensor end */
+
of_node_put(prev_node);
of_node_put(parent_node);
--
Gitblit v1.6.2