From 9370bb92b2d16684ee45cf24e879c93c509162da Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Thu, 19 Dec 2024 01:47:39 +0000 Subject: [PATCH] add wifi6 8852be driver --- 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