From 4c0e9158bf1c177a02d201406a33243611a18de4 Mon Sep 17 00:00:00 2001 From: Changhuang Liang Date: Thu, 1 Jun 2023 14:00:13 +0800 Subject: media: starfive: Add V4L2_CAP_IO_MC capabilities Add V4L2_CAP_IO_MC capabilities. Signed-off-by: Changhuang Liang --- drivers/media/platform/starfive/v4l2_driver/stf_video.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/starfive/v4l2_driver/stf_video.c b/drivers/media/platform/starfive/v4l2_driver/stf_video.c index ac8f98a8cec9..60400120e018 100644 --- a/drivers/media/platform/starfive/v4l2_driver/stf_video.c +++ b/drivers/media/platform/starfive/v4l2_driver/stf_video.c @@ -1511,7 +1511,7 @@ int stf_video_register(struct stfcamss_video *video, V4L2_CAP_VIDEO_CAPTURE; vdev->vfl_dir = VFL_DIR_RX; } - vdev->device_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; + vdev->device_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE | V4L2_CAP_IO_MC; if (video->type == V4L2_CAP_VIDEO_OUTPUT) vdev->ioctl_ops = &stf_vid_ioctl_ops_out; else -- cgit v1.2.3 From 9dc2c2d8b769a8703d5c37f0cab80346304bce5c Mon Sep 17 00:00:00 2001 From: Changhuang Liang Date: Thu, 1 Jun 2023 17:06:22 +0800 Subject: media: starfive: Add isp frame sync event Add isp frame sync event. Signed-off-by: Changhuang Liang --- .../media/platform/starfive/v4l2_driver/stf_vin.c | 26 +++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/starfive/v4l2_driver/stf_vin.c b/drivers/media/platform/starfive/v4l2_driver/stf_vin.c index 5758ab77d7ea..a96199a161fe 100644 --- a/drivers/media/platform/starfive/v4l2_driver/stf_vin.c +++ b/drivers/media/platform/starfive/v4l2_driver/stf_vin.c @@ -9,6 +9,7 @@ #include #include #include +#include #include "stfcamss.h" @@ -1133,6 +1134,9 @@ static void vin_buffer_done(struct vin_line *line, struct vin_params *params) struct vin_output *output = &line->output; unsigned long flags; u64 ts = ktime_get_ns(); + struct v4l2_event event = { + .type = V4L2_EVENT_FRAME_SYNC, + }; if (output->state == VIN_OUTPUT_OFF || output->state == VIN_OUTPUT_RESERVED) @@ -1141,6 +1145,11 @@ static void vin_buffer_done(struct vin_line *line, struct vin_params *params) spin_lock_irqsave(&line->output_lock, flags); while ((ready_buf = vin_buf_get_ready(output))) { + if (line->id >= VIN_LINE_ISP && line->id <= VIN_LINE_ISP_SS1) { + event.u.frame_sync.frame_sequence = output->sequence; + v4l2_event_queue(line->subdev.devnode, &event); + } + ready_buf->vb.vb2_buf.timestamp = ts; ready_buf->vb.sequence = output->sequence++; @@ -1331,8 +1340,23 @@ static int vin_link_setup(struct media_entity *entity, return 0; } +static int stf_vin_subscribe_event(struct v4l2_subdev *sd, + struct v4l2_fh *fh, + struct v4l2_event_subscription *sub) +{ + switch (sub->type) { + case V4L2_EVENT_FRAME_SYNC: + return v4l2_event_subscribe(fh, sub, 0, NULL); + default: + st_debug(ST_VIN, "unsupport subscribe_event\n"); + return -EINVAL; + } +} + static const struct v4l2_subdev_core_ops vin_core_ops = { .s_power = vin_set_power, + .subscribe_event = stf_vin_subscribe_event, + .unsubscribe_event = v4l2_event_subdev_unsubscribe, }; static const struct v4l2_subdev_video_ops vin_video_ops = { @@ -1393,7 +1417,7 @@ int stf_vin_register(struct stf_vin2_dev *vin_dev, struct v4l2_device *v4l2_dev) v4l2_subdev_init(sd, &vin_v4l2_ops); sd->internal_ops = &vin_v4l2_internal_ops; - sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; snprintf(sd->name, ARRAY_SIZE(sd->name), "%s%d_%s", STF_VIN_NAME, 0, sub_name); v4l2_set_subdevdata(sd, &vin_dev->line[i]); -- cgit v1.2.3 From 54853480cacddb9b07f8969611b81b8172d36340 Mon Sep 17 00:00:00 2001 From: Changhuang Liang Date: Wed, 28 Jun 2023 10:10:04 +0800 Subject: media: satrfive: stf_isp: Add new conctrl support Add new conctrl for jh7110 isp. Signed-off-by: Changhuang Liang --- .../media/platform/starfive/v4l2_driver/stf_isp.c | 53 ++++- include/uapi/linux/jh7110-isp.h | 253 +++++++++++++++++++++ include/uapi/linux/v4l2-controls.h | 6 + 3 files changed, 311 insertions(+), 1 deletion(-) create mode 100644 include/uapi/linux/jh7110-isp.h diff --git a/drivers/media/platform/starfive/v4l2_driver/stf_isp.c b/drivers/media/platform/starfive/v4l2_driver/stf_isp.c index a6f19c03104e..9f474d4a1758 100644 --- a/drivers/media/platform/starfive/v4l2_driver/stf_isp.c +++ b/drivers/media/platform/starfive/v4l2_driver/stf_isp.c @@ -12,6 +12,7 @@ #include #include #include +#include #include "stf_isp_ioctl.h" #include "stf_dmabuf.h" @@ -264,7 +265,7 @@ static int isp_s_ctrl(struct v4l2_ctrl *ctrl) { struct v4l2_subdev *sd = ctrl_to_sd(ctrl); struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd); - int ret; + int ret = 0; /* * If the device is not powered up by the host driver do @@ -309,6 +310,12 @@ static int isp_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_VFLIP: ret = isp_set_ctrl_vflip(isp_dev, ctrl->val); break; + case V4L2_CID_USER_JH7110_ISP_WB_SETTING: + break; + case V4L2_CID_USER_JH7110_ISP_CAR_SETTING: + break; + case V4L2_CID_USER_JH7110_ISP_CCM_SETTING: + break; default: ret = -EINVAL; break; @@ -322,12 +329,52 @@ static const struct v4l2_ctrl_ops isp_ctrl_ops = { .s_ctrl = isp_s_ctrl, }; +struct v4l2_ctrl_config isp_ctrl[] = { + [0] = { + .ops = &isp_ctrl_ops, + .type = V4L2_CTRL_TYPE_U8, + .def = 0, + .min = 0x00, + .max = 0xff, + .step = 1, + .name = "WB Setting", + .id = V4L2_CID_USER_JH7110_ISP_WB_SETTING, + .dims[0] = sizeof(struct jh7110_isp_wb_setting), + .flags = 0, + }, + [1] = { + .ops = &isp_ctrl_ops, + .type = V4L2_CTRL_TYPE_U8, + .def = 0, + .min = 0x00, + .max = 0xff, + .step = 1, + .name = "Car Setting", + .id = V4L2_CID_USER_JH7110_ISP_CAR_SETTING, + .dims[0] = sizeof(struct jh7110_isp_car_setting), + .flags = 0, + }, + [2] = { + .ops = &isp_ctrl_ops, + .type = V4L2_CTRL_TYPE_U8, + .def = 0, + .min = 0x00, + .max = 0xff, + .step = 1, + .name = "CCM Setting", + .id = V4L2_CID_USER_JH7110_ISP_CCM_SETTING, + .dims[0] = sizeof(struct jh7110_isp_ccm_setting), + .flags = 0, + }, +}; + static int isp_init_controls(struct stf_isp_dev *isp_dev) { const struct v4l2_ctrl_ops *ops = &isp_ctrl_ops; struct isp_ctrls *ctrls = &isp_dev->ctrls; struct v4l2_ctrl_handler *hdl = &ctrls->handler; int ret; + int i; v4l2_ctrl_handler_init(hdl, 32); @@ -378,6 +425,10 @@ static int isp_init_controls(struct stf_isp_dev *isp_dev) V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0, V4L2_CID_POWER_LINE_FREQUENCY_50HZ); + for (i = 0; i < ARRAY_SIZE(isp_ctrl); i++) + v4l2_ctrl_new_custom(hdl, &isp_ctrl[i], NULL); + + if (hdl->error) { ret = hdl->error; goto free_ctrls; diff --git a/include/uapi/linux/jh7110-isp.h b/include/uapi/linux/jh7110-isp.h new file mode 100644 index 000000000000..86a8ff17414f --- /dev/null +++ b/include/uapi/linux/jh7110-isp.h @@ -0,0 +1,253 @@ +/* SPDX-License-Identifier: ((GPL-2.0+ WITH Linux-syscall-note) OR BSD-3-Clause) */ +/* + * jh7110-isp.h + * + * JH7110 ISP driver - user space header file. + * + * Copyright © 2023 Starfive Technology Co., Ltd. + * + * Author: Su Zejian (zejian.su@starfivetech.com) + * + */ + +#ifndef __JH7110_ISP_H_ +#define __JH7110_ISP_H_ + +#include + +#define V4L2_CID_USER_JH7110_ISP_WB_SETTING \ + (V4L2_CID_USER_JH7110_ISP_BASE + 0x0001) +#define V4L2_CID_USER_JH7110_ISP_CAR_SETTING \ + (V4L2_CID_USER_JH7110_ISP_BASE + 0x0002) +#define V4L2_CID_USER_JH7110_ISP_CCM_SETTING \ + (V4L2_CID_USER_JH7110_ISP_BASE + 0x0003) +#define V4L2_CID_USER_JH7110_ISP_CFA_SETTING \ + (V4L2_CID_USER_JH7110_ISP_BASE + 0x0004) +#define V4L2_CID_USER_JH7110_ISP_CTC_SETTING \ + (V4L2_CID_USER_JH7110_ISP_BASE + 0x0005) +#define V4L2_CID_USER_JH7110_ISP_DBC_SETTING \ + (V4L2_CID_USER_JH7110_ISP_BASE + 0x0006) +#define V4L2_CID_USER_JH7110_ISP_DNYUV_SETTING \ + (V4L2_CID_USER_JH7110_ISP_BASE + 0x0007) +#define V4L2_CID_USER_JH7110_ISP_GMARGB_SETTING \ + (V4L2_CID_USER_JH7110_ISP_BASE + 0x0008) +#define V4L2_CID_USER_JH7110_ISP_LCCF_SETTING \ + (V4L2_CID_USER_JH7110_ISP_BASE + 0x0009) +#define V4L2_CID_USER_JH7110_ISP_OBC_SETTING \ + (V4L2_CID_USER_JH7110_ISP_BASE + 0x000a) +#define V4L2_CID_USER_JH7110_ISP_OECF_SETTING \ + (V4L2_CID_USER_JH7110_ISP_BASE + 0x000b) +#define V4L2_CID_USER_JH7110_ISP_R2Y_SETTING \ + (V4L2_CID_USER_JH7110_ISP_BASE + 0x000c) +#define V4L2_CID_USER_JH7110_ISP_SAT_SETTING \ + (V4L2_CID_USER_JH7110_ISP_BASE + 0x000d) +#define V4L2_CID_USER_JH7110_ISP_SHRP_SETTING \ + (V4L2_CID_USER_JH7110_ISP_BASE + 0x000e) +#define V4L2_CID_USER_JH7110_ISP_YCRV_SETTING \ + (V4L2_CID_USER_JH7110_ISP_BASE + 0x000f) + +struct jh7110_isp_wb_gain { + __u16 gain_r; + __u16 gain_g; + __u16 gain_b; +}; + +struct jh7110_isp_wb_setting { + __u32 enabled; + struct jh7110_isp_wb_gain gains; +}; + +struct jh7110_isp_car_setting { + __u32 enabled; +}; + +struct jh7110_isp_ccm_smlow { + __s32 ccm[3][3]; + __s32 offsets[3]; +}; + +struct jh7110_isp_ccm_setting { + __u32 enabled; + struct jh7110_isp_ccm_smlow ccm_smlow; +}; + +struct jh7110_isp_cfa_params { + __s32 hv_width; + __s32 cross_cov; +}; + +struct jh7110_isp_cfa_setting { + __u32 enabled; + struct jh7110_isp_cfa_params settings; +}; + +struct jh7110_isp_ctc_params { + __u8 saf_mode; + __u8 daf_mode; + __s32 max_gt; + __s32 min_gt; +}; + +struct jh7110_isp_ctc_setting { + __u32 enabled; + struct jh7110_isp_ctc_params settings; +}; + +struct jh7110_isp_dbc_params { + __s32 bad_gt; + __s32 bad_xt; +}; + +struct jh7110_isp_dbc_setting { + __u32 enabled; + struct jh7110_isp_dbc_params settings; +}; + +struct jh7110_isp_dnyuv_params { + __u8 y_sweight[10]; + __u16 y_curve[7]; + __u8 uv_sweight[10]; + __u16 uv_curve[7]; +}; + +struct jh7110_isp_dnyuv_setting { + __u32 enabled; + struct jh7110_isp_dnyuv_params settings; +}; + +struct jh7110_isp_gmargb_point { + __u16 g_val; + __u16 sg_val; +}; + +struct jh7110_isp_gmargb_setting { + __u32 enabled; + struct jh7110_isp_gmargb_point curve[15]; +}; + +struct jh7110_isp_lccf_circle { + __s16 center_x; + __s16 center_y; + __u8 radius; +}; + +struct jh7110_isp_lccf_curve_param { + __s16 f1; + __s16 f2; +}; + +struct jh7110_isp_lccf_setting { + __u32 enabled; + struct jh7110_isp_lccf_circle circle; + struct jh7110_isp_lccf_curve_param r_param; + struct jh7110_isp_lccf_curve_param gr_param; + struct jh7110_isp_lccf_curve_param gb_param; + struct jh7110_isp_lccf_curve_param b_param; +}; + +struct jh7110_isp_blacklevel_win_size { + __u32 width; + __u32 height; +}; + +struct jh7110_isp_blacklevel_gain { + __u8 tl_gain; + __u8 tr_gain; + __u8 bl_gain; + __u8 br_gain; +}; + +struct jh7110_isp_blacklevel_offset { + __u8 tl_offset; + __u8 tr_offset; + __u8 bl_offset; + __u8 br_offset; +}; + +struct jh7110_isp_blacklevel_setting { + __u32 enabled; + struct jh7110_isp_blacklevel_win_size win_size; + struct jh7110_isp_blacklevel_gain gain[4]; + struct jh7110_isp_blacklevel_offset offset[4]; +}; + +struct jh7110_isp_oecf_point { + __u16 x; + __u16 y; + __s16 slope; +}; + +struct jh7110_isp_oecf_setting { + __u32 enabled; + struct jh7110_isp_oecf_point r_curve[16]; + struct jh7110_isp_oecf_point gr_curve[16]; + struct jh7110_isp_oecf_point gb_curve[16]; + struct jh7110_isp_oecf_point b_curve[16]; +}; + +struct jh7110_isp_r2y_matrix { + __s16 m[9]; +}; + +struct jh7110_isp_r2y_setting { + __u32 enabled; + struct jh7110_isp_r2y_matrix matrix; +}; + +struct jh7110_isp_sat_curve { + __s16 yi_min; + __s16 yo_ir; + __s16 yo_min; + __s16 yo_max; +}; + +struct jh7110_isp_sat_hue_info { + __s16 sin; + __s16 cos; +}; + +struct jh7110_isp_sat_info { + __s16 gain_cmab; + __s16 gain_cmad; + __s16 threshold_cmb; + __s16 threshold_cmd; + __s16 offset_u; + __s16 offset_v; + __s16 cmsf; +}; + +struct jh7110_isp_sat_setting { + __u32 enabled; + struct jh7110_isp_sat_curve curve; + struct jh7110_isp_sat_hue_info hue_info; + struct jh7110_isp_sat_info sat_info; +}; + +struct jh7110_isp_sharp_weight { + __u8 weight[15]; + __u32 recip_wei_sum; +}; + +struct jh7110_isp_sharp_strength { + __s16 diff[4]; + __s16 f[4]; +}; + +struct jh7110_isp_sharp_setting { + __u32 enabled; + struct jh7110_isp_sharp_weight weight; + struct jh7110_isp_sharp_strength strength; + __s8 pdirf; + __s8 ndirf; +}; + +struct jh7110_isp_ycrv_curve { + __s16 y[64]; +}; + +struct jh7110_isp_ycrv_setting { + __u32 enabled; + struct jh7110_isp_ycrv_curve curve; +}; + +#endif diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index 5532b5f68493..efc2e53b84a9 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -212,6 +212,12 @@ enum v4l2_colorfx { */ #define V4L2_CID_USER_CCS_BASE (V4L2_CID_USER_BASE + 0x10f0) +/* + * The base for the jh7110-isp driver controls. + * We reserve 16 controls for this driver. + */ +#define V4L2_CID_USER_JH7110_ISP_BASE (V4L2_CID_USER_BASE + 0x1170) + /* MPEG-class control IDs */ /* The MPEG controls are applicable to all codec controls * and the 'MPEG' part of the define is historical */ -- cgit v1.2.3 From d8b4134033d2c594896bd46bd4bb838eb892c54c Mon Sep 17 00:00:00 2001 From: Changhuang Liang Date: Thu, 3 Aug 2023 10:28:13 +0800 Subject: media: starfive: Add isp sc buffer point Add isp sc buffer point. Signed-off-by: Changhuang Liang --- drivers/media/platform/starfive/v4l2_driver/stf_video.c | 4 +++- drivers/media/platform/starfive/v4l2_driver/stf_video.h | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/starfive/v4l2_driver/stf_video.c b/drivers/media/platform/starfive/v4l2_driver/stf_video.c index 60400120e018..19e949655672 100644 --- a/drivers/media/platform/starfive/v4l2_driver/stf_video.c +++ b/drivers/media/platform/starfive/v4l2_driver/stf_video.c @@ -340,8 +340,10 @@ static int video_buf_init(struct vb2_buffer *vb) } if (stf_vin_map_isp_pad(video->id, STF_ISP_PAD_SRC) - == STF_ISP_PAD_SRC_SCD_Y) + == STF_ISP_PAD_SRC_SCD_Y) { buffer->addr[1] = buffer->addr[0] + ISP_YHIST_BUFFER_SIZE; + buffer->vaddr_sc = vb2_plane_vaddr(vb, 0); + } return 0; } diff --git a/drivers/media/platform/starfive/v4l2_driver/stf_video.h b/drivers/media/platform/starfive/v4l2_driver/stf_video.h index c7b6fa7a9dcd..cf99be2df8db 100644 --- a/drivers/media/platform/starfive/v4l2_driver/stf_video.h +++ b/drivers/media/platform/starfive/v4l2_driver/stf_video.h @@ -28,6 +28,7 @@ struct stfcamss_buffer { struct vb2_v4l2_buffer vb; dma_addr_t addr[3]; + void *vaddr_sc; /* Use for isp sc data */ struct list_head queue; int sizeimage; }; -- cgit v1.2.3 From 43dada4396658351388c90f2391a89f33d29e351 Mon Sep 17 00:00:00 2001 From: Changhuang Liang Date: Thu, 17 Aug 2023 16:39:23 +0800 Subject: media: starfive: isp: Update format pad table one by one Update format pad table one by one, it can simply code. Signed-off-by: Changhuang Liang --- .../media/platform/starfive/v4l2_driver/stf_isp.c | 46 +++++++--------------- 1 file changed, 14 insertions(+), 32 deletions(-) diff --git a/drivers/media/platform/starfive/v4l2_driver/stf_isp.c b/drivers/media/platform/starfive/v4l2_driver/stf_isp.c index 9f474d4a1758..0d01a9b59731 100644 --- a/drivers/media/platform/starfive/v4l2_driver/stf_isp.c +++ b/drivers/media/platform/starfive/v4l2_driver/stf_isp.c @@ -87,16 +87,15 @@ static const struct isp_format isp_formats_st7110_iti[] = { { MEDIA_BUS_FMT_YUV8_1X24, 8}, }; -#define SINK_FORMATS_INDEX 0 -#define UO_FORMATS_INDEX 1 -#define ITI_FORMATS_INDEX 2 -#define RAW_FORMATS_INDEX 3 - static const struct isp_format_table isp_formats_st7110[] = { - { isp_formats_st7110_sink, ARRAY_SIZE(isp_formats_st7110_sink) }, // 0 - { isp_formats_st7110_uo, ARRAY_SIZE(isp_formats_st7110_uo) }, // 1 - { isp_formats_st7110_iti, ARRAY_SIZE(isp_formats_st7110_iti) }, // 2 - { isp_formats_st7110_raw, ARRAY_SIZE(isp_formats_st7110_raw) }, // 3 + { isp_formats_st7110_sink, ARRAY_SIZE(isp_formats_st7110_sink) }, /* pad 0 */ + { isp_formats_st7110_uo, ARRAY_SIZE(isp_formats_st7110_uo) }, /* pad 1 */ + { isp_formats_st7110_uo, ARRAY_SIZE(isp_formats_st7110_uo) }, /* pad 2 */ + { isp_formats_st7110_uo, ARRAY_SIZE(isp_formats_st7110_uo) }, /* pad 3 */ + { isp_formats_st7110_iti, ARRAY_SIZE(isp_formats_st7110_iti) }, /* pad 4 */ + { isp_formats_st7110_iti, ARRAY_SIZE(isp_formats_st7110_iti) }, /* pad 5 */ + { isp_formats_st7110_raw, ARRAY_SIZE(isp_formats_st7110_raw) }, /* pad 6 */ + { isp_formats_st7110_raw, ARRAY_SIZE(isp_formats_st7110_raw) }, /* pad 7 */ }; int stf_isp_subdev_init(struct stfcamss *stfcamss) @@ -588,7 +587,7 @@ static int isp_match_sensor_format_get_index(struct stf_isp_dev *isp_dev) st_debug(ST_ISP, "Got sensor format 0x%x !!\n", fmt.format.code); - formats = &isp_dev->formats[SINK_FORMATS_INDEX]; + formats = &isp_dev->formats[0]; /* isp sink format */ for (idx = 0; idx < formats->nfmts; idx++) { if (formats->fmts[idx].code == fmt.format.code) { st_info(ST_ISP, @@ -632,11 +631,10 @@ static void isp_try_format(struct stf_isp_dev *isp_dev, u32 code = fmt->code; u32 bpp; - switch (pad) { - case STF_ISP_PAD_SINK: + if (pad == STF_ISP_PAD_SINK) { /* Set format on sink pad */ - formats = &isp_dev->formats[SINK_FORMATS_INDEX]; + formats = &isp_dev->formats[pad]; fmt->width = clamp_t(u32, fmt->width, STFCAMSS_FRAME_MIN_WIDTH, STFCAMSS_FRAME_MAX_WIDTH); @@ -648,24 +646,8 @@ static void isp_try_format(struct stf_isp_dev *isp_dev, fmt->field = V4L2_FIELD_NONE; fmt->colorspace = V4L2_COLORSPACE_SRGB; fmt->flags = 0; - - break; - - case STF_ISP_PAD_SRC: - case STF_ISP_PAD_SRC_SS0: - case STF_ISP_PAD_SRC_SS1: - formats = &isp_dev->formats[UO_FORMATS_INDEX]; - break; - - case STF_ISP_PAD_SRC_ITIW: - case STF_ISP_PAD_SRC_ITIR: - formats = &isp_dev->formats[ITI_FORMATS_INDEX]; - break; - - case STF_ISP_PAD_SRC_RAW: - case STF_ISP_PAD_SRC_SCD_Y: - formats = &isp_dev->formats[RAW_FORMATS_INDEX]; - break; + } else { + formats = &isp_dev->formats[pad]; } i = isp_match_format_get_index(formats, fmt->code, pad); @@ -736,7 +718,7 @@ static int isp_enum_mbus_code(struct v4l2_subdev *sd, if (code->index >= isp_dev->nformats) return -EINVAL; if (code->pad == STF_ISP_PAD_SINK) { - formats = &isp_dev->formats[SINK_FORMATS_INDEX]; + formats = &isp_dev->formats[code->pad]; code->code = formats->fmts[code->index].code; } else { struct v4l2_mbus_framefmt *sink_fmt; -- cgit v1.2.3 From 8e8f8713eb33ae7fe3465a484d1f0d95f526ecbb Mon Sep 17 00:00:00 2001 From: Changhuang Liang Date: Thu, 17 Aug 2023 16:48:31 +0800 Subject: media: starfive: isp: Fix enum isp subdev code bug Fix enum isp subdev code bug. Signed-off-by: Changhuang Liang --- drivers/media/platform/starfive/v4l2_driver/stf_isp.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/drivers/media/platform/starfive/v4l2_driver/stf_isp.c b/drivers/media/platform/starfive/v4l2_driver/stf_isp.c index 0d01a9b59731..8b36e22ef583 100644 --- a/drivers/media/platform/starfive/v4l2_driver/stf_isp.c +++ b/drivers/media/platform/starfive/v4l2_driver/stf_isp.c @@ -715,21 +715,11 @@ static int isp_enum_mbus_code(struct v4l2_subdev *sd, struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd); const struct isp_format_table *formats; - if (code->index >= isp_dev->nformats) + if (code->index >= isp_dev->formats[code->pad].nfmts) return -EINVAL; - if (code->pad == STF_ISP_PAD_SINK) { - formats = &isp_dev->formats[code->pad]; - code->code = formats->fmts[code->index].code; - } else { - struct v4l2_mbus_framefmt *sink_fmt; - - sink_fmt = __isp_get_format(isp_dev, state, STF_ISP_PAD_SINK, - code->which); - code->code = sink_fmt->code; - if (!code->code) - return -EINVAL; - } + formats = &isp_dev->formats[code->pad]; + code->code = formats->fmts[code->index].code; code->flags = 0; return 0; -- cgit v1.2.3 From 5a0dc091ad05a0ea42cc293a4131c76cd9e86cf7 Mon Sep 17 00:00:00 2001 From: "zejian.su" Date: Mon, 3 Jul 2023 16:52:13 +0800 Subject: Add 16 ISP controls, remove the frame SYNC event to video7 (SC) These controls are: WB, CAR, CCM, CFA, CTC, DBC, DNYUV, GMARGB, LCCF, OBC, OECF, R2Y, SAT, SHRP, YCRV, SC --- .../media/platform/starfive/v4l2_driver/stf_isp.c | 628 +++++++++++++++++++++ .../platform/starfive/v4l2_driver/stf_video.c | 22 + .../media/platform/starfive/v4l2_driver/stf_vin.c | 16 +- include/uapi/linux/jh7110-isp.h | 48 +- 4 files changed, 706 insertions(+), 8 deletions(-) diff --git a/drivers/media/platform/starfive/v4l2_driver/stf_isp.c b/drivers/media/platform/starfive/v4l2_driver/stf_isp.c index 8b36e22ef583..35e38efa238b 100644 --- a/drivers/media/platform/starfive/v4l2_driver/stf_isp.c +++ b/drivers/media/platform/starfive/v4l2_driver/stf_isp.c @@ -195,6 +195,41 @@ static const char * const test_pattern_menu[] = { "Color squares w/ rolling bar", }; +enum isp_modules_index { + imi_obc = 0, + imi_oecf, + imi_lccf, + imi_awb, + imi_dbc, + imi_ctc, + imi_cfa, + imi_car, + imi_ccm, + imi_gmargb, + imi_r2y, + imi_ycrv, + imi_shrp, + imi_dnyuv, + imi_sat, + imi_sc +}; + +#define MODULE_ENABLE_REGISTER0 0x10 +#define MODULE_ENABLE_REGISTER1 0xa08 + +struct module_register_info { + __u32 en_reg; + __u32 en_nbit; + __u32 cfg_reg; +}; + +static const struct module_register_info mod_reg_info[] = { + {MODULE_ENABLE_REGISTER0, 2, 0x034}, {MODULE_ENABLE_REGISTER0, 4, 0x100}, {MODULE_ENABLE_REGISTER0, 6, 0x050}, {MODULE_ENABLE_REGISTER0, 7, 0x280}, + {MODULE_ENABLE_REGISTER1, 22, 0xa14}, {MODULE_ENABLE_REGISTER1, 21, 0xa10}, {MODULE_ENABLE_REGISTER1, 1, 0xa1c}, {MODULE_ENABLE_REGISTER1, 2, 0x000}, + {MODULE_ENABLE_REGISTER1, 3, 0xc40}, {MODULE_ENABLE_REGISTER1, 4, 0xe00}, {MODULE_ENABLE_REGISTER1, 5, 0xe40}, {MODULE_ENABLE_REGISTER1, 19, 0xf00}, + {MODULE_ENABLE_REGISTER1, 7, 0xe80}, {MODULE_ENABLE_REGISTER1, 17, 0xc00}, {MODULE_ENABLE_REGISTER1, 8, 0xa30}, {MODULE_ENABLE_REGISTER0, 17, 0x09c} +}; + #define ISP_TEST_ENABLE BIT(7) #define ISP_TEST_ROLLING BIT(6) /* rolling horizontal bar */ #define ISP_TEST_TRANSPARENT BIT(5) @@ -260,6 +295,401 @@ static int isp_g_volatile_ctrl(struct v4l2_ctrl *ctrl) return 0; } +#define CREATE_REG_VALUE_FUNCTION(type) \ + static u32 create_reg_value_##type(const type * value, s32 size, u32 mask, s32 nbits) { \ + s32 npos = 0; \ + u32 res = 0; \ + s32 sz = size; \ + s32 i = 0; \ + if(size * nbits > 32) sz = 32 / nbits; \ + for(i = 0; i < sz; i++, npos += nbits, value++) res |= (u32)(value[0] & mask) << npos; \ + return res; \ +} + +CREATE_REG_VALUE_FUNCTION(u8); +CREATE_REG_VALUE_FUNCTION(u16); +#define CREATE_REG_VALUE(type, value, size, mask, nbits) create_reg_value_##type(value, size, mask, nbits) + +#define FILL_ISP_REGS_FUNC(type) \ +static void fill_isp_regs_##type(void __iomem *ispbase, u32 offset, const type * value, s32 size, u32 mask, u32 nbits) { \ + s32 i; \ + for(i = 0; i < size; i++, value++) \ + reg_write(ispbase, offset + i * 4, (u32)(value[0] & mask) << nbits); \ +} +FILL_ISP_REGS_FUNC(u32); +FILL_ISP_REGS_FUNC(u8); +FILL_ISP_REGS_FUNC(u16); + +#define FILL_ISP_REGS(type, ispbase, offset, value, size, mask, nbits) \ + fill_isp_regs_##type(ispbase, offset, value, size, mask, nbits) + +static int isp_set_ctrl_wb(struct stf_isp_dev *isp_dev, const void * value) +{ + const struct module_register_info * reg_info = &mod_reg_info[imi_awb]; + const struct jh7110_isp_wb_setting * setting = (const struct jh7110_isp_wb_setting *)value; + const struct jh7110_isp_wb_gain * gains = &setting->gains; + u32 r_g = (((u32)gains->gain_r << 16) | gains->gain_r) & 0x03ff03ff; + u32 g_g = (((u32)gains->gain_g << 16) | gains->gain_g) & 0x03ff03ff; + u32 b_g = (((u32)gains->gain_b << 16) | gains->gain_b) & 0x03ff03ff; + u32 reg_addr = reg_info->cfg_reg + 16 * sizeof(u32); + struct stf_vin_dev *vin = isp_dev->stfcamss->vin; + void __iomem *ispbase = vin->isp_base; + + reg_write(ispbase, reg_addr, r_g); + reg_write(ispbase, reg_addr + 1 * 4, r_g); + reg_write(ispbase, reg_addr + 2 * 4, g_g); + reg_write(ispbase, reg_addr + 3 * 4, g_g); + reg_write(ispbase, reg_addr + 4 * 4, g_g); + reg_write(ispbase, reg_addr + 5 * 4, g_g); + reg_write(ispbase, reg_addr + 6 * 4, b_g); + reg_write(ispbase, reg_addr + 7 * 4, b_g); + reg_set_bit(ispbase, reg_info->en_reg, 1 << reg_info->en_nbit, setting->enabled ? 1 << reg_info->en_nbit : 0); + + return 0; +} + +static int isp_set_ctrl_car(struct stf_isp_dev *isp_dev, const void * value) +{ + const struct module_register_info * reg_info = &mod_reg_info[imi_car]; + const struct jh7110_isp_car_setting * setting = (const struct jh7110_isp_car_setting *)value; + struct stf_vin_dev *vin = isp_dev->stfcamss->vin; + void __iomem *ispbase = vin->isp_base; + + reg_set_bit(ispbase, reg_info->en_reg, 1 << reg_info->en_nbit, setting->enabled ? 1 << reg_info->en_nbit : 0); + + return 0; +} + +static int isp_set_ctrl_ccm(struct stf_isp_dev *isp_dev, const void * value) +{ + const struct module_register_info * reg_info = &mod_reg_info[imi_ccm]; + const struct jh7110_isp_ccm_setting * setting = (const struct jh7110_isp_ccm_setting *)value; + const struct jh7110_isp_ccm_smlow * ccm = (const struct jh7110_isp_ccm_smlow *)(&(setting->ccm_smlow)); + u32 reg_addr = reg_info->cfg_reg + 12 * sizeof(u32); + struct stf_vin_dev *vin = isp_dev->stfcamss->vin; + void __iomem *ispbase = vin->isp_base; + + reg_write(ispbase, reg_info->cfg_reg, 6 << 16); + FILL_ISP_REGS(u32, ispbase, reg_addr, (u32 *)ccm, 12, 0x7ff, 0); + + reg_set_bit(ispbase, reg_info->en_reg, 1 << reg_info->en_nbit, setting->enabled ? 1 << reg_info->en_nbit : 0); + + return 0; +} + +static int isp_set_ctrl_cfa(struct stf_isp_dev *isp_dev, const void * value) +{ + const struct module_register_info * reg_info = &mod_reg_info[imi_cfa]; + const struct jh7110_isp_cfa_setting * setting = (const struct jh7110_isp_cfa_setting *)value; + const struct jh7110_isp_cfa_params * cfg = (const struct jh7110_isp_cfa_params *)(&(setting->settings)); + u32 reg_addr = reg_info->cfg_reg; + struct stf_vin_dev *vin = isp_dev->stfcamss->vin; + void __iomem *ispbase = vin->isp_base; + + reg_write(ispbase, reg_addr, ((u32)(cfg->cross_cov & 0x3) << 4) | (cfg->hv_width & 0xf)); + reg_set_bit(ispbase, reg_info->en_reg, 1 << reg_info->en_nbit, setting->enabled ? 1 << reg_info->en_nbit : 0); + + return 0; +} + +static int isp_set_ctrl_ctc(struct stf_isp_dev *isp_dev, const void * value) +{ + const struct module_register_info * reg_info = &mod_reg_info[imi_ctc]; + const struct jh7110_isp_ctc_setting * setting = (const struct jh7110_isp_ctc_setting *)value; + const struct jh7110_isp_ctc_params * cfg = (const struct jh7110_isp_ctc_params *)(&(setting->settings)); + u32 reg_addr = reg_info->cfg_reg; + struct stf_vin_dev *vin = isp_dev->stfcamss->vin; + void __iomem *ispbase = vin->isp_base; + u32 reg_value = (u32)(((cfg->saf_mode & 1) << 1) | (cfg->daf_mode & 1)) << 30; + + reg_value |= ((u32)(cfg->max_gt & 0x3ff) << 16) | (cfg->min_gt & 0x3ff); + reg_write(ispbase, reg_addr, reg_value); + reg_set_bit(ispbase, reg_info->en_reg, 1 << reg_info->en_nbit, setting->enabled ? 1 << reg_info->en_nbit : 0); + + return 0; +} + +static int isp_set_ctrl_dbc(struct stf_isp_dev *isp_dev, const void * value) +{ + const struct module_register_info * reg_info = &mod_reg_info[imi_dbc]; + const struct jh7110_isp_dbc_setting * setting = (const struct jh7110_isp_dbc_setting *)value; + const struct jh7110_isp_dbc_params * cfg = (const struct jh7110_isp_dbc_params *)(&(setting->settings)); + u32 reg_addr = reg_info->cfg_reg; + struct stf_vin_dev *vin = isp_dev->stfcamss->vin; + void __iomem *ispbase = vin->isp_base; + + reg_write(ispbase, reg_addr, ((u32)(cfg->bad_gt & 0x3ff) << 16) | (cfg->bad_xt & 0x3ff)); + reg_set_bit(ispbase, reg_info->en_reg, 1 << reg_info->en_nbit, setting->enabled ? 1 << reg_info->en_nbit : 0); + + return 0; +} + +static int isp_set_ctrl_dnyuv(struct stf_isp_dev *isp_dev, const void * value) +{ + const struct module_register_info * reg_info = &mod_reg_info[imi_dnyuv]; + const struct jh7110_isp_dnyuv_setting * setting = (const struct jh7110_isp_dnyuv_setting *)value; + const struct jh7110_isp_dnyuv_params * cfg = (const struct jh7110_isp_dnyuv_params *)(&(setting->settings)); + u32 reg_addr = reg_info->cfg_reg; + struct stf_vin_dev *vin = isp_dev->stfcamss->vin; + void __iomem *ispbase = vin->isp_base; + + reg_write(ispbase, reg_addr, CREATE_REG_VALUE(u8, cfg->y_sweight, 6, 0x7, 4)); + reg_write(ispbase, reg_addr + 4, CREATE_REG_VALUE(u8, &cfg->y_sweight[6], 4, 0x7, 4)); + reg_write(ispbase, reg_addr + 8, CREATE_REG_VALUE(u8, cfg->uv_sweight, 6, 0x7, 4)); + reg_write(ispbase, reg_addr + 12, CREATE_REG_VALUE(u8, &cfg->uv_sweight[6], 4, 0x7, 4)); + reg_write(ispbase, reg_addr + 16, CREATE_REG_VALUE(u16, &cfg->y_curve[0], 2, 0x3ff, 16)); + reg_write(ispbase, reg_addr + 20, CREATE_REG_VALUE(u16, &cfg->y_curve[2], 2, 0x3ff, 16)); + reg_write(ispbase, reg_addr + 24, CREATE_REG_VALUE(u16, &cfg->y_curve[4], 2, 0x3ff, 16)); + reg_write(ispbase, reg_addr + 28, CREATE_REG_VALUE(u16, &cfg->uv_curve[0], 2, 0x3ff, 16)); + reg_write(ispbase, reg_addr + 32, CREATE_REG_VALUE(u16, &cfg->uv_curve[2], 2, 0x3ff, 16)); + reg_write(ispbase, reg_addr + 36, CREATE_REG_VALUE(u16, &cfg->uv_curve[4], 2, 0x3ff, 16)); + + reg_set_bit(ispbase, reg_info->en_reg, 1 << reg_info->en_nbit, setting->enabled ? 1 << reg_info->en_nbit : 0); + + return 0; +} + +static int isp_set_ctrl_gmargb(struct stf_isp_dev *isp_dev, const void * value) +{ + const struct module_register_info * reg_info = &mod_reg_info[imi_gmargb]; + const struct jh7110_isp_gmargb_setting * setting = (const struct jh7110_isp_gmargb_setting *)value; + const struct jh7110_isp_gmargb_point * curve = setting->curve; + u32 reg_addr = reg_info->cfg_reg; + struct stf_vin_dev *vin = isp_dev->stfcamss->vin; + void __iomem *ispbase = vin->isp_base; + s32 i; + + for(i = 0; i < 15; i++, curve++, reg_addr += 4) + reg_write(ispbase, reg_addr, ((u32)curve->sg_val << 16) | (curve->g_val & 0x3ff)); + + reg_set_bit(ispbase, reg_info->en_reg, 1 << reg_info->en_nbit, setting->enabled ? 1 << reg_info->en_nbit : 0); + + return 0; +} + +static int isp_set_ctrl_lccf(struct stf_isp_dev *isp_dev, const void * value) +{ + const struct module_register_info * reg_info = &mod_reg_info[imi_lccf]; + const struct jh7110_isp_lccf_setting * setting = (const struct jh7110_isp_lccf_setting *)value; + const s16 * params = (s16 *)(&setting->r_param); + u32 reg_addr = reg_info->cfg_reg; + struct stf_vin_dev *vin = isp_dev->stfcamss->vin; + void __iomem *ispbase = vin->isp_base; + s32 i; + + reg_write(ispbase, reg_addr, ((u32)(setting->circle.center_y & 0x7fff) << 16) | (setting->circle.center_x & 0x7fff)); + reg_write(ispbase, reg_addr + 8, setting->circle.radius & 0xf); + reg_addr += 0x90; + for(i = 0; i < 4; i++, reg_addr += 4, params += 2) + reg_write(ispbase, reg_addr, CREATE_REG_VALUE(u16, params, 2, 0x1fff, 16)); + + reg_set_bit(ispbase, reg_info->en_reg, 1 << reg_info->en_nbit, setting->enabled ? 1 << reg_info->en_nbit : 0); + + return 0; +} + +static int isp_set_ctrl_obc(struct stf_isp_dev *isp_dev, const void * value) +{ + const struct module_register_info * reg_info = &mod_reg_info[imi_obc]; + const struct jh7110_isp_blacklevel_setting * setting = (const struct jh7110_isp_blacklevel_setting *)value; + const u8 * params = (u8 *)setting->gain; + u32 reg_addr = reg_info->cfg_reg; + struct stf_vin_dev *vin = isp_dev->stfcamss->vin; + void __iomem *ispbase = vin->isp_base; + s32 i; + + reg_write(ispbase, reg_addr, ((u32)(setting->win_size.height & 0xf) << 4) | (setting->win_size.width & 0xf)); + + reg_addr += 0x2ac; //0x2e0 + for(i = 0; i < 8; i++, reg_addr += 4, params += 4) + reg_write(ispbase, reg_addr, CREATE_REG_VALUE(u8, params, 4, 0xff, 8)); + + reg_set_bit(ispbase, reg_info->en_reg, 1 << reg_info->en_nbit, setting->enabled ? 1 << reg_info->en_nbit : 0); + + return 0; +} + +static int isp_set_ctrl_oecf(struct stf_isp_dev *isp_dev, const void * value) +{ + const struct module_register_info * reg_info = &mod_reg_info[imi_oecf]; + const struct jh7110_isp_oecf_setting * setting = (const struct jh7110_isp_oecf_setting *)value; + const struct jh7110_isp_oecf_point * pts = (struct jh7110_isp_oecf_point *)(setting->r_curve); + u32 reg_x_addr = reg_info->cfg_reg; + u32 reg_y_addr = reg_info->cfg_reg + 0x080; + u32 reg_s_addr = reg_info->cfg_reg + 0x100; + struct stf_vin_dev *vin = isp_dev->stfcamss->vin; + void __iomem *ispbase = vin->isp_base; + u32 x, y, slope; + s32 i; + + for(i = 0; i < 32; i++, reg_x_addr += 4, reg_y_addr += 4, reg_s_addr += 4) { + x = pts->x & 0x3ff; + y = pts->y & 0x3ff; + slope = pts->slope & 0x3ff; + pts++; + x |= ((pts->x & 0x3ff) << 16); + y |= ((pts->y & 0x3ff) << 16); + slope |= ((pts->slope & 0x3ff) << 16); + pts++; + + reg_write(ispbase, reg_x_addr, x); + reg_write(ispbase, reg_y_addr, y); + reg_write(ispbase, reg_s_addr, slope); + } + + reg_set_bit(ispbase, reg_info->en_reg, 1 << reg_info->en_nbit, setting->enabled ? 1 << reg_info->en_nbit : 0); + + return 0; +} + +static int isp_set_ctrl_r2y(struct stf_isp_dev *isp_dev, const void * value) +{ + const struct module_register_info * reg_info = &mod_reg_info[imi_r2y]; + const struct jh7110_isp_r2y_setting * setting = (const struct jh7110_isp_r2y_setting *)value; + const s16 * params = setting->matrix.m; + u32 reg_addr = reg_info->cfg_reg; + struct stf_vin_dev *vin = isp_dev->stfcamss->vin; + void __iomem *ispbase = vin->isp_base; + s32 i; + + for(i = 0; i < 9; i++, reg_addr += 4) + reg_write(ispbase, reg_addr, (u32)(params[i] & 0x1ff)); + + reg_set_bit(ispbase, reg_info->en_reg, 1 << reg_info->en_nbit, setting->enabled ? 1 << reg_info->en_nbit : 0); + + return 0; +} + + +static int isp_set_ctrl_sat(struct stf_isp_dev *isp_dev, const void * value) +{ + const struct module_register_info * reg_info = &mod_reg_info[imi_sat]; + const struct jh7110_isp_sat_setting * setting = (const struct jh7110_isp_sat_setting *)value; + const u16 * params = (u16 *)(&setting->sat_info); + u32 reg_addr = reg_info->cfg_reg; + struct stf_vin_dev *vin = isp_dev->stfcamss->vin; + void __iomem *ispbase = vin->isp_base; + s32 i; + + for(i = 0; i < 3; i++, reg_addr += 4, params += 2) + reg_write(ispbase, reg_addr, CREATE_REG_VALUE(u16, params, 2, 0xfff, 16)); + reg_write(ispbase, reg_addr, CREATE_REG_VALUE(u16, &setting->hue_info.cos, 2, 0x3ff, 16)); + reg_addr += 4; + reg_write(ispbase, reg_addr, setting->sat_info.cmsf & 0xf); + + params = (u16 *)(&setting->curve); + reg_addr += 0x14; // 0xa54 + for(i = 0; i < 2; i++, reg_addr += 4, params += 2) + reg_write(ispbase, reg_addr, CREATE_REG_VALUE(u16, params, 2, 0x3fff, 16)); + + reg_set_bit(ispbase, reg_info->en_reg, 1 << reg_info->en_nbit, setting->enabled ? 1 << reg_info->en_nbit : 0); + + return 0; +} + +static int isp_set_ctrl_shrp(struct stf_isp_dev *isp_dev, const void * value) +{ + const struct module_register_info * reg_info = &mod_reg_info[imi_shrp]; + const struct jh7110_isp_sharp_setting * setting = (const struct jh7110_isp_sharp_setting *)value; + u32 reg_addr = reg_info->cfg_reg; + struct stf_vin_dev *vin = isp_dev->stfcamss->vin; + void __iomem *ispbase = vin->isp_base; + s32 i; + + for(i = 0; i < 4; i++, reg_addr += 4) + reg_write(ispbase, reg_addr, ((u32)(setting->strength.diff[i] & 0x3ff) << 16) | ((u32)(setting->weight.weight[i] & 0xf) << 8)); + FILL_ISP_REGS(u8, ispbase, reg_addr, (u8 *)(&setting->weight.weight[4]), 15 - 4, 0xf, 8); + reg_addr += (15 - 4) * 4; + + for(i = 0; i < 3; i++, reg_addr += 4) + reg_write(ispbase, reg_addr, ((u32)(setting->strength.f[i] & 0x7f) << 24) | (setting->strength.s[i] & 0x1fffff)); + + reg_addr += 3 * 4; + reg_write(ispbase, reg_addr, ((u32)(setting->pdirf & 0xf) << 28) | ((u32)(setting->ndirf & 0xf) << 24) | (setting->weight.recip_wei_sum & 0x3fffff)); + + reg_set_bit(ispbase, reg_info->en_reg, 1 << reg_info->en_nbit, setting->enabled ? 1 << reg_info->en_nbit : 0); + + return 0; +} + +static int isp_set_ctrl_ycrv(struct stf_isp_dev *isp_dev, const void * value) +{ + const struct module_register_info * reg_info = &mod_reg_info[imi_ycrv]; + const struct jh7110_isp_ycrv_setting * setting = (const struct jh7110_isp_ycrv_setting *)value; + u32 reg_addr = reg_info->cfg_reg; + struct stf_vin_dev *vin = isp_dev->stfcamss->vin; + void __iomem *ispbase = vin->isp_base; + + FILL_ISP_REGS(u16, ispbase, reg_addr, (u16 *)(setting->curve.y), 64, 0x3ff, 0); + + reg_set_bit(ispbase, reg_info->en_reg, 1 << reg_info->en_nbit, setting->enabled ? 1 << reg_info->en_nbit : 0); + + return 0; +} + +static int isp_set_ctrl_sc(struct stf_isp_dev *isp_dev, const void * value) +{ + const struct module_register_info * reg_info = &mod_reg_info[imi_sc]; + const struct jh7110_isp_sc_setting * setting = (const struct jh7110_isp_sc_setting *)value; + const u8 * params = setting->awb_config.awb_cw; + u32 reg_addr = 0x00; + struct stf_vin_dev *vin = isp_dev->stfcamss->vin; + void __iomem *ispbase = vin->isp_base; + u32 weight_cfg[6] = {0}; + u32 * weight = weight_cfg; + u32 * w_diff = weight_cfg + 2; + s32 i; + + // AF register + reg_write(ispbase, 0xc0, + ((u32)(setting->af_config.es_hor_thr & 0x1ff) << 16) | + ((u32)(setting->af_config.es_ver_thr & 0xff) << 8) | + ((setting->af_config.ver_en & 0x1) << 3) | + ((setting->af_config.hor_en & 0x1) << 2) | + ((setting->af_config.es_sum_mode & 0x1) << 1) | + (setting->af_config.es_hor_mode & 0x1)); + + // AWB weight sum register + reg_write(ispbase, 0x5d0, CREATE_REG_VALUE(u8, &setting->awb_config.ws_config.awb_ws_rl, 4, 0xff, 8)); + reg_write(ispbase, 0x5d4, CREATE_REG_VALUE(u8, &setting->awb_config.ws_config.awb_ws_gbl, 4, 0xff, 8)); + + // AWB weight value point + reg_addr = 0x4d0; + for(i = 0; i < 13; i++) { + reg_write(ispbase, reg_addr, CREATE_REG_VALUE(u8, params, 8, 0xf, 4)); + reg_addr += 4; + params += 8; + reg_write(ispbase, reg_addr, CREATE_REG_VALUE(u8, params, 5, 0xf, 4)); + reg_addr += 4; + params += 5; + } + + // AWB intensity weight curve register + reg_addr = 0x538; + for(i = 0; i < 4; i++) { + weight[0] |= (setting->awb_config.pts[i].weight & 0xf) << (i * 4); + w_diff[0] |= ((((s16)(setting->awb_config.pts[i + 1].weight & 0xf) - (s16)(setting->awb_config.pts[i].weight & 0xf)) * 2) & 0xff) << (i * 8); + } + for(w_diff++; i < 8; i++) { + weight[0] |= (setting->awb_config.pts[i].weight & 0xf) << (i * 4); + w_diff[0] |= ((((s16)(setting->awb_config.pts[i + 1].weight & 0xf) - (s16)(setting->awb_config.pts[i].weight & 0xf)) * 2) & 0xff) << (i * 8); + } + for(weight++, w_diff++; i < 12; i++) { + weight[0] |= (setting->awb_config.pts[i].weight & 0xf) << (i * 4); + w_diff[0] |= ((((s16)(setting->awb_config.pts[i + 1].weight & 0xf) - (s16)(setting->awb_config.pts[i].weight & 0xf)) * 2) & 0xff) << (i * 8); + } + for(w_diff++; i < 16; i++) { + weight[0] |= (setting->awb_config.pts[i].weight & 0xf) << (i * 4); + w_diff[0] |= ((((s16)(setting->awb_config.pts[i + 1].weight & 0xf) - (s16)(setting->awb_config.pts[i].weight & 0xf)) * 2) & 0xff) << (i * 8); + } + + FILL_ISP_REGS(u32, ispbase, reg_addr, weight_cfg, 6, 0xffffffff, 0); + + reg_set_bit(ispbase, reg_info->en_reg, 1 << reg_info->en_nbit, setting->enabled ? 1 << reg_info->en_nbit : 0); + + return 0; +} + static int isp_s_ctrl(struct v4l2_ctrl *ctrl) { struct v4l2_subdev *sd = ctrl_to_sd(ctrl); @@ -310,10 +740,52 @@ static int isp_s_ctrl(struct v4l2_ctrl *ctrl) ret = isp_set_ctrl_vflip(isp_dev, ctrl->val); break; case V4L2_CID_USER_JH7110_ISP_WB_SETTING: + ret = isp_set_ctrl_wb(isp_dev, ctrl->p_new.p_u8); break; case V4L2_CID_USER_JH7110_ISP_CAR_SETTING: + ret = isp_set_ctrl_car(isp_dev, ctrl->p_new.p_u8); break; case V4L2_CID_USER_JH7110_ISP_CCM_SETTING: + ret = isp_set_ctrl_ccm(isp_dev, ctrl->p_new.p_u8); + break; + case V4L2_CID_USER_JH7110_ISP_CFA_SETTING: + ret = isp_set_ctrl_cfa(isp_dev, ctrl->p_new.p_u8); + break; + case V4L2_CID_USER_JH7110_ISP_CTC_SETTING: + ret = isp_set_ctrl_ctc(isp_dev, ctrl->p_new.p_u8); + break; + case V4L2_CID_USER_JH7110_ISP_DBC_SETTING: + ret = isp_set_ctrl_dbc(isp_dev, ctrl->p_new.p_u8); + break; + case V4L2_CID_USER_JH7110_ISP_DNYUV_SETTING: + ret = isp_set_ctrl_dnyuv(isp_dev, ctrl->p_new.p_u8); + break; + case V4L2_CID_USER_JH7110_ISP_GMARGB_SETTING: + ret = isp_set_ctrl_gmargb(isp_dev, ctrl->p_new.p_u8); + break; + case V4L2_CID_USER_JH7110_ISP_LCCF_SETTING: + ret = isp_set_ctrl_lccf(isp_dev, ctrl->p_new.p_u8); + break; + case V4L2_CID_USER_JH7110_ISP_OBC_SETTING: + ret = isp_set_ctrl_obc(isp_dev, ctrl->p_new.p_u8); + break; + case V4L2_CID_USER_JH7110_ISP_OECF_SETTING: + ret = isp_set_ctrl_oecf(isp_dev, ctrl->p_new.p_u8); + break; + case V4L2_CID_USER_JH7110_ISP_R2Y_SETTING: + ret = isp_set_ctrl_r2y(isp_dev, ctrl->p_new.p_u8); + break; + case V4L2_CID_USER_JH7110_ISP_SAT_SETTING: + ret = isp_set_ctrl_sat(isp_dev, ctrl->p_new.p_u8); + break; + case V4L2_CID_USER_JH7110_ISP_SHRP_SETTING: + ret = isp_set_ctrl_shrp(isp_dev, ctrl->p_new.p_u8); + break; + case V4L2_CID_USER_JH7110_ISP_YCRV_SETTING: + ret = isp_set_ctrl_ycrv(isp_dev, ctrl->p_new.p_u8); + break; + case V4L2_CID_USER_JH7110_ISP_STAT_SETTING: + ret = isp_set_ctrl_sc(isp_dev, ctrl->p_new.p_u8); break; default: ret = -EINVAL; @@ -365,6 +837,162 @@ struct v4l2_ctrl_config isp_ctrl[] = { .dims[0] = sizeof(struct jh7110_isp_ccm_setting), .flags = 0, }, + [3] = { + .ops = &isp_ctrl_ops, + .type = V4L2_CTRL_TYPE_U8, + .def = 0, + .min = 0x00, + .max = 0xff, + .step = 1, + .name = "CFA Setting", + .id = V4L2_CID_USER_JH7110_ISP_CFA_SETTING, + .dims[0] = sizeof(struct jh7110_isp_cfa_setting), + .flags = 0, + }, + [4] = { + .ops = &isp_ctrl_ops, + .type = V4L2_CTRL_TYPE_U8, + .def = 0, + .min = 0x00, + .max = 0xff, + .step = 1, + .name = "CTC Setting", + .id = V4L2_CID_USER_JH7110_ISP_CTC_SETTING, + .dims[0] = sizeof(struct jh7110_isp_ctc_setting), + .flags = 0, + }, + [5] = { + .ops = &isp_ctrl_ops, + .type = V4L2_CTRL_TYPE_U8, + .def = 0, + .min = 0x00, + .max = 0xff, + .step = 1, + .name = "CTC Setting", + .id = V4L2_CID_USER_JH7110_ISP_DBC_SETTING, + .dims[0] = sizeof(struct jh7110_isp_dbc_setting), + .flags = 0, + }, + [6] = { + .ops = &isp_ctrl_ops, + .type = V4L2_CTRL_TYPE_U8, + .def = 0, + .min = 0x00, + .max = 0xff, + .step = 1, + .name = "DNYUV Setting", + .id = V4L2_CID_USER_JH7110_ISP_DNYUV_SETTING, + .dims[0] = sizeof(struct jh7110_isp_dnyuv_setting), + .flags = 0, + }, + [7] = { + .ops = &isp_ctrl_ops, + .type = V4L2_CTRL_TYPE_U8, + .def = 0, + .min = 0x00, + .max = 0xff, + .step = 1, + .name = "DNYUV Setting", + .id = V4L2_CID_USER_JH7110_ISP_GMARGB_SETTING, + .dims[0] = sizeof(struct jh7110_isp_gmargb_setting), + .flags = 0, + }, + [8] = { + .ops = &isp_ctrl_ops, + .type = V4L2_CTRL_TYPE_U8, + .def = 0, + .min = 0x00, + .max = 0xff, + .step = 1, + .name = "LCCF Setting", + .id = V4L2_CID_USER_JH7110_ISP_LCCF_SETTING, + .dims[0] = sizeof(struct jh7110_isp_lccf_setting), + .flags = 0, + }, + [9] = { + .ops = &isp_ctrl_ops, + .type = V4L2_CTRL_TYPE_U8, + .def = 0, + .min = 0x00, + .max = 0xff, + .step = 1, + .name = "OBC Setting", + .id = V4L2_CID_USER_JH7110_ISP_OBC_SETTING, + .dims[0] = sizeof(struct jh7110_isp_blacklevel_setting), + .flags = 0, + }, + [10] = { + .ops = &isp_ctrl_ops, + .type = V4L2_CTRL_TYPE_U8, + .def = 0, + .min = 0x00, + .max = 0xff, + .step = 1, + .name = "OECF Setting", + .id = V4L2_CID_USER_JH7110_ISP_OECF_SETTING, + .dims[0] = sizeof(struct jh7110_isp_oecf_setting), + .flags = 0, + }, + [11] = { + .ops = &isp_ctrl_ops, + .type = V4L2_CTRL_TYPE_U8, + .def = 0, + .min = 0x00, + .max = 0xff, + .step = 1, + .name = "R2Y Setting", + .id = V4L2_CID_USER_JH7110_ISP_R2Y_SETTING, + .dims[0] = sizeof(struct jh7110_isp_r2y_setting), + .flags = 0, + }, + [12] = { + .ops = &isp_ctrl_ops, + .type = V4L2_CTRL_TYPE_U8, + .def = 0, + .min = 0x00, + .max = 0xff, + .step = 1, + .name = "SAT Setting", + .id = V4L2_CID_USER_JH7110_ISP_SAT_SETTING, + .dims[0] = sizeof(struct jh7110_isp_sat_setting), + .flags = 0, + }, + [13] = { + .ops = &isp_ctrl_ops, + .type = V4L2_CTRL_TYPE_U8, + .def = 0, + .min = 0x00, + .max = 0xff, + .step = 1, + .name = "SAT Setting", + .id = V4L2_CID_USER_JH7110_ISP_SHRP_SETTING, + .dims[0] = sizeof(struct jh7110_isp_sharp_setting), + .flags = 0, + }, + [14] = { + .ops = &isp_ctrl_ops, + .type = V4L2_CTRL_TYPE_U8, + .def = 0, + .min = 0x00, + .max = 0xff, + .step = 1, + .name = "YCRV Setting", + .id = V4L2_CID_USER_JH7110_ISP_YCRV_SETTING, + .dims[0] = sizeof(struct jh7110_isp_ycrv_setting), + .flags = 0, + }, + [15] = { + .ops = &isp_ctrl_ops, + .type = V4L2_CTRL_TYPE_U8, + .def = 0, + .min = 0x00, + .max = 0xff, + .step = 1, + .name = "SC Setting", + .id = V4L2_CID_USER_JH7110_ISP_STAT_SETTING, + .dims[0] = sizeof(struct jh7110_isp_sc_setting), + .flags = 0, + }, }; static int isp_init_controls(struct stf_isp_dev *isp_dev) diff --git a/drivers/media/platform/starfive/v4l2_driver/stf_video.c b/drivers/media/platform/starfive/v4l2_driver/stf_video.c index 19e949655672..53c7a6146b6c 100644 --- a/drivers/media/platform/starfive/v4l2_driver/stf_video.c +++ b/drivers/media/platform/starfive/v4l2_driver/stf_video.c @@ -1280,6 +1280,22 @@ int video_s_selection(struct file *file, void *fh, return ret; } +static int stf_video_subscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + switch (sub->type) { + case V4L2_EVENT_FRAME_SYNC: + return v4l2_event_subscribe(fh, sub, 2, NULL); + //int ret = v4l2_event_subscribe(fh, sub, 2, NULL); + //pr_info("subscribe ret: %d\n", ret); + //return ret; + default: + return v4l2_ctrl_subscribe_event(fh, sub); + //st_debug(ST_VIN, "unsupport subscribe_event\n"); + //return -EINVAL; + } +} + static const struct v4l2_ioctl_ops stf_vid_ioctl_ops = { .vidioc_querycap = video_querycap, .vidioc_enum_fmt_vid_cap = video_enum_fmt, @@ -1304,6 +1320,8 @@ static const struct v4l2_ioctl_ops stf_vid_ioctl_ops = { .vidioc_s_parm = video_s_parm, .vidioc_s_selection = video_s_selection, .vidioc_g_selection = video_g_selection, + .vidioc_subscribe_event = stf_video_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; static const struct v4l2_ioctl_ops stf_vid_ioctl_ops_mp = { @@ -1330,6 +1348,8 @@ static const struct v4l2_ioctl_ops stf_vid_ioctl_ops_mp = { .vidioc_s_parm = video_s_parm, .vidioc_s_selection = video_s_selection, .vidioc_g_selection = video_g_selection, + .vidioc_subscribe_event = stf_video_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; static const struct v4l2_ioctl_ops stf_vid_ioctl_ops_out = { @@ -1349,6 +1369,8 @@ static const struct v4l2_ioctl_ops stf_vid_ioctl_ops_out = { .vidioc_prepare_buf = vb2_ioctl_prepare_buf, .vidioc_streamon = vb2_ioctl_streamon, .vidioc_streamoff = vb2_ioctl_streamoff, + .vidioc_subscribe_event = stf_video_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; static int video_open(struct file *file) diff --git a/drivers/media/platform/starfive/v4l2_driver/stf_vin.c b/drivers/media/platform/starfive/v4l2_driver/stf_vin.c index a96199a161fe..67e69565d179 100644 --- a/drivers/media/platform/starfive/v4l2_driver/stf_vin.c +++ b/drivers/media/platform/starfive/v4l2_driver/stf_vin.c @@ -1145,9 +1145,12 @@ static void vin_buffer_done(struct vin_line *line, struct vin_params *params) spin_lock_irqsave(&line->output_lock, flags); while ((ready_buf = vin_buf_get_ready(output))) { - if (line->id >= VIN_LINE_ISP && line->id <= VIN_LINE_ISP_SS1) { + //if (line->id >= VIN_LINE_ISP && line->id <= VIN_LINE_ISP_SS1) { + if (line->id == VIN_LINE_ISP_SCD_Y) { event.u.frame_sync.frame_sequence = output->sequence; - v4l2_event_queue(line->subdev.devnode, &event); + v4l2_event_queue(&(line->video_out.vdev), &event); + //v4l2_event_queue(line->subdev.devnode, &event); + //pr_info("----------frame sync-----------\n"); } ready_buf->vb.vb2_buf.timestamp = ts; @@ -1346,7 +1349,10 @@ static int stf_vin_subscribe_event(struct v4l2_subdev *sd, { switch (sub->type) { case V4L2_EVENT_FRAME_SYNC: - return v4l2_event_subscribe(fh, sub, 0, NULL); + //return v4l2_event_subscribe(fh, sub, 2, NULL); + int ret = v4l2_event_subscribe(fh, sub, 2, NULL); + pr_info("subscribe ret: %d\n", ret); + return ret; default: st_debug(ST_VIN, "unsupport subscribe_event\n"); return -EINVAL; @@ -1355,8 +1361,8 @@ static int stf_vin_subscribe_event(struct v4l2_subdev *sd, static const struct v4l2_subdev_core_ops vin_core_ops = { .s_power = vin_set_power, - .subscribe_event = stf_vin_subscribe_event, - .unsubscribe_event = v4l2_event_subdev_unsubscribe, + //.subscribe_event = stf_vin_subscribe_event, + //.unsubscribe_event = v4l2_event_subdev_unsubscribe, }; static const struct v4l2_subdev_video_ops vin_video_ops = { diff --git a/include/uapi/linux/jh7110-isp.h b/include/uapi/linux/jh7110-isp.h index 86a8ff17414f..e20895bd881a 100644 --- a/include/uapi/linux/jh7110-isp.h +++ b/include/uapi/linux/jh7110-isp.h @@ -15,6 +15,8 @@ #include +#define V4L2_CID_USER_JH7110_ISP_BASE (V4L2_CID_USER_BASE + 0x1170) + #define V4L2_CID_USER_JH7110_ISP_WB_SETTING \ (V4L2_CID_USER_JH7110_ISP_BASE + 0x0001) #define V4L2_CID_USER_JH7110_ISP_CAR_SETTING \ @@ -45,6 +47,8 @@ (V4L2_CID_USER_JH7110_ISP_BASE + 0x000e) #define V4L2_CID_USER_JH7110_ISP_YCRV_SETTING \ (V4L2_CID_USER_JH7110_ISP_BASE + 0x000f) +#define V4L2_CID_USER_JH7110_ISP_STAT_SETTING \ + (V4L2_CID_USER_JH7110_ISP_BASE + 0x0010) struct jh7110_isp_wb_gain { __u16 gain_r; @@ -202,13 +206,13 @@ struct jh7110_isp_sat_curve { }; struct jh7110_isp_sat_hue_info { - __s16 sin; __s16 cos; + __s16 sin; }; struct jh7110_isp_sat_info { __s16 gain_cmab; - __s16 gain_cmad; + __s16 gain_cmmd; __s16 threshold_cmb; __s16 threshold_cmd; __s16 offset_u; @@ -230,7 +234,8 @@ struct jh7110_isp_sharp_weight { struct jh7110_isp_sharp_strength { __s16 diff[4]; - __s16 f[4]; + __s16 f[3]; + __s32 s[3]; }; struct jh7110_isp_sharp_setting { @@ -250,4 +255,41 @@ struct jh7110_isp_ycrv_setting { struct jh7110_isp_ycrv_curve curve; }; +struct jh7110_isp_sc_af_config { + __u8 es_hor_mode; + __u8 es_sum_mode; + __u8 hor_en; + __u8 ver_en; + __u8 es_ver_thr; + __u16 es_hor_thr; +}; + +struct jh7110_isp_sc_awb_ws { + __u8 awb_ws_rl; + __u8 awb_ws_ru; + __u8 awb_ws_grl; + __u8 awb_ws_gru; + __u8 awb_ws_gbl; + __u8 awb_ws_gbu; + __u8 awb_ws_bl; + __u8 awb_ws_bu; +}; + +struct jh7110_isp_sc_awb_point { + __u16 intensity; + __u8 weight; +}; + +struct jh7110_isp_sc_awb_config { + struct jh7110_isp_sc_awb_ws ws_config; + __u8 awb_cw[169]; + struct jh7110_isp_sc_awb_point pts[17]; +}; + +struct jh7110_isp_sc_setting { + __u32 enabled; + struct jh7110_isp_sc_af_config af_config; + struct jh7110_isp_sc_awb_config awb_config; +}; + #endif -- cgit v1.2.3 From 7d7d284f7c210b2b722856a0f9dcf7870a20d4e9 Mon Sep 17 00:00:00 2001 From: "zejian.su" Date: Mon, 7 Aug 2023 10:38:36 +0800 Subject: Expand 2 bytes after the SC buffer for the AE/AWB flag and copy the histogram data to the SC buffer. --- .../media/platform/starfive/v4l2_driver/stf_isp.c | 37 +++++++++++++++++++++- .../media/platform/starfive/v4l2_driver/stf_isp.h | 2 +- .../platform/starfive/v4l2_driver/stf_video.c | 5 --- .../media/platform/starfive/v4l2_driver/stf_vin.c | 36 ++++++++++----------- include/uapi/linux/jh7110-isp.h | 33 +++++++++++++++++++ 5 files changed, 87 insertions(+), 26 deletions(-) diff --git a/drivers/media/platform/starfive/v4l2_driver/stf_isp.c b/drivers/media/platform/starfive/v4l2_driver/stf_isp.c index 35e38efa238b..c836ba709788 100644 --- a/drivers/media/platform/starfive/v4l2_driver/stf_isp.c +++ b/drivers/media/platform/starfive/v4l2_driver/stf_isp.c @@ -323,6 +323,13 @@ FILL_ISP_REGS_FUNC(u16); #define FILL_ISP_REGS(type, ispbase, offset, value, size, mask, nbits) \ fill_isp_regs_##type(ispbase, offset, value, size, mask, nbits) +static void fill_regs_with_zero(void __iomem *ispbase, u32 offset, u32 size) +{ + u32 i; + for(i = 0; i < size; i++, offset += 4) + reg_write(ispbase, offset, 0); +} + static int isp_set_ctrl_wb(struct stf_isp_dev *isp_dev, const void * value) { const struct module_register_info * reg_info = &mod_reg_info[imi_awb]; @@ -335,6 +342,8 @@ static int isp_set_ctrl_wb(struct stf_isp_dev *isp_dev, const void * value) struct stf_vin_dev *vin = isp_dev->stfcamss->vin; void __iomem *ispbase = vin->isp_base; + fill_regs_with_zero(ispbase, reg_info->cfg_reg, 16); + reg_write(ispbase, reg_addr, r_g); reg_write(ispbase, reg_addr + 1 * 4, r_g); reg_write(ispbase, reg_addr + 2 * 4, g_g); @@ -370,8 +379,13 @@ static int isp_set_ctrl_ccm(struct stf_isp_dev *isp_dev, const void * value) void __iomem *ispbase = vin->isp_base; reg_write(ispbase, reg_info->cfg_reg, 6 << 16); + fill_regs_with_zero(ispbase, reg_info->cfg_reg + 4, 11); + FILL_ISP_REGS(u32, ispbase, reg_addr, (u32 *)ccm, 12, 0x7ff, 0); + reg_addr += 12 * 4; + fill_regs_with_zero(ispbase, reg_addr, 2); + reg_set_bit(ispbase, reg_info->en_reg, 1 << reg_info->en_nbit, setting->enabled ? 1 << reg_info->en_nbit : 0); return 0; @@ -640,6 +654,27 @@ static int isp_set_ctrl_sc(struct stf_isp_dev *isp_dev, const void * value) u32 * w_diff = weight_cfg + 2; s32 i; + // SC dumping axi id + reg_write(ispbase, 0x9c, 1 << 24); + + // SC frame crop + reg_write(ispbase, 0xb8, ((u32)(setting->crop_config.v_start) << 16) | setting->crop_config.h_start); + + // SC config1 + reg_write(ispbase, 0xbc, ((u32)(setting->awb_config.sel) << 30) | ((u32)(setting->awb_config.awb_ps_grb_ba) << 16) | + ((u32)(setting->crop_config.sw_height) << 8) | setting->crop_config.sw_width); + + // SC decimation config + reg_write(ispbase, 0xd8, ((u32)(setting->crop_config.vkeep) << 24) | ((u32)(setting->crop_config.vperiod) << 16) | + ((u32)(setting->crop_config.hkeep) << 8) | setting->crop_config.hperiod); + + // SC AWB pixel sum config + reg_write(ispbase, 0xc4, CREATE_REG_VALUE(u8, &setting->awb_config.ws_ps_config.awb_ps_rl, 4, 0xff, 8)); + reg_write(ispbase, 0xc8, CREATE_REG_VALUE(u8, &setting->awb_config.ws_ps_config.awb_ps_bl, 4, 0xff, 8)); + reg_write(ispbase, 0xcc, CREATE_REG_VALUE(u16, &setting->awb_config.ws_ps_config.awb_ps_grl, 2, 0xffff, 16)); + reg_write(ispbase, 0xd0, CREATE_REG_VALUE(u16, &setting->awb_config.ws_ps_config.awb_ps_gbl, 2, 0xffff, 16)); + reg_write(ispbase, 0xd4, CREATE_REG_VALUE(u16, &setting->awb_config.ws_ps_config.awb_ps_grbl, 2, 0xffff, 16)); + // AF register reg_write(ispbase, 0xc0, ((u32)(setting->af_config.es_hor_thr & 0x1ff) << 16) | @@ -686,7 +721,7 @@ static int isp_set_ctrl_sc(struct stf_isp_dev *isp_dev, const void * value) FILL_ISP_REGS(u32, ispbase, reg_addr, weight_cfg, 6, 0xffffffff, 0); reg_set_bit(ispbase, reg_info->en_reg, 1 << reg_info->en_nbit, setting->enabled ? 1 << reg_info->en_nbit : 0); - + return 0; } diff --git a/drivers/media/platform/starfive/v4l2_driver/stf_isp.h b/drivers/media/platform/starfive/v4l2_driver/stf_isp.h index 5924503f536e..d740b1fe1aa1 100644 --- a/drivers/media/platform/starfive/v4l2_driver/stf_isp.h +++ b/drivers/media/platform/starfive/v4l2_driver/stf_isp.h @@ -18,7 +18,7 @@ #define ISP_SCD_BUFFER_SIZE (19 * 256 * 4) // align 128 #define ISP_YHIST_BUFFER_SIZE (64 * 4) -#define ISP_SCD_Y_BUFFER_SIZE (ISP_SCD_BUFFER_SIZE + ISP_YHIST_BUFFER_SIZE) +#define ISP_SCD_Y_BUFFER_SIZE (ISP_SCD_BUFFER_SIZE + ISP_YHIST_BUFFER_SIZE + 2) #define ISP_RAW_DATA_BITS 12 #define SCALER_RATIO_MAX 1 // no compose function #define STF_ISP_REG_OFFSET_MAX 0x0FFF diff --git a/drivers/media/platform/starfive/v4l2_driver/stf_video.c b/drivers/media/platform/starfive/v4l2_driver/stf_video.c index 53c7a6146b6c..8a5e5a846f96 100644 --- a/drivers/media/platform/starfive/v4l2_driver/stf_video.c +++ b/drivers/media/platform/starfive/v4l2_driver/stf_video.c @@ -1286,13 +1286,8 @@ static int stf_video_subscribe_event(struct v4l2_fh *fh, switch (sub->type) { case V4L2_EVENT_FRAME_SYNC: return v4l2_event_subscribe(fh, sub, 2, NULL); - //int ret = v4l2_event_subscribe(fh, sub, 2, NULL); - //pr_info("subscribe ret: %d\n", ret); - //return ret; default: return v4l2_ctrl_subscribe_event(fh, sub); - //st_debug(ST_VIN, "unsupport subscribe_event\n"); - //return -EINVAL; } } diff --git a/drivers/media/platform/starfive/v4l2_driver/stf_vin.c b/drivers/media/platform/starfive/v4l2_driver/stf_vin.c index 67e69565d179..dc30b018e684 100644 --- a/drivers/media/platform/starfive/v4l2_driver/stf_vin.c +++ b/drivers/media/platform/starfive/v4l2_driver/stf_vin.c @@ -1147,6 +1147,17 @@ static void vin_buffer_done(struct vin_line *line, struct vin_params *params) while ((ready_buf = vin_buf_get_ready(output))) { //if (line->id >= VIN_LINE_ISP && line->id <= VIN_LINE_ISP_SS1) { if (line->id == VIN_LINE_ISP_SCD_Y) { +#define ADDR_REG_YHIST_ACC_0 0x0D00 + struct stf_vin2_dev *vin_dev = line_to_vin2_dev(line); + struct stf_vin_dev *vin = vin_dev->stfcamss->vin; + void __iomem *ispbase = vin->isp_base; + u32 y_hist_reg_addr = ADDR_REG_YHIST_ACC_0; + u32 * y_hist_addr = (u32 *)ready_buf->vaddr_sc; + s32 i = 0; + + for(i = 0; i < 64; i++, y_hist_reg_addr += 4) + y_hist_addr[i] = reg_read(ispbase, y_hist_reg_addr); + event.u.frame_sync.frame_sequence = output->sequence; v4l2_event_queue(&(line->video_out.vdev), &event); //v4l2_event_queue(line->subdev.devnode, &event); @@ -1246,9 +1257,14 @@ static void vin_change_buffer(struct vin_line *line) scd_type = vin_dev->hw_ops->vin_isp_get_scd_type(vin_dev); ready_buf->vb.flags &= ~(V4L2_BUF_FLAG_PFRAME | V4L2_BUF_FLAG_BFRAME); if (scd_type == AWB_TYPE) + { ready_buf->vb.flags |= V4L2_BUF_FLAG_PFRAME; - else + *((u16 *)(ready_buf->vaddr_sc + ISP_SCD_BUFFER_SIZE + ISP_YHIST_BUFFER_SIZE)) = 0xffff; + }else{ ready_buf->vb.flags |= V4L2_BUF_FLAG_BFRAME; + *((u16 *)(ready_buf->vaddr_sc + ISP_SCD_BUFFER_SIZE + ISP_YHIST_BUFFER_SIZE)) = 0; + } + if (!output->frame_skip) { output->frame_skip = ISP_AWB_OECF_SKIP_FRAME; scd_type = scd_type == AWB_TYPE ? OECF_TYPE : AWB_TYPE; @@ -1343,26 +1359,8 @@ static int vin_link_setup(struct media_entity *entity, return 0; } -static int stf_vin_subscribe_event(struct v4l2_subdev *sd, - struct v4l2_fh *fh, - struct v4l2_event_subscription *sub) -{ - switch (sub->type) { - case V4L2_EVENT_FRAME_SYNC: - //return v4l2_event_subscribe(fh, sub, 2, NULL); - int ret = v4l2_event_subscribe(fh, sub, 2, NULL); - pr_info("subscribe ret: %d\n", ret); - return ret; - default: - st_debug(ST_VIN, "unsupport subscribe_event\n"); - return -EINVAL; - } -} - static const struct v4l2_subdev_core_ops vin_core_ops = { .s_power = vin_set_power, - //.subscribe_event = stf_vin_subscribe_event, - //.unsubscribe_event = v4l2_event_subdev_unsubscribe, }; static const struct v4l2_subdev_video_ops vin_video_ops = { diff --git a/include/uapi/linux/jh7110-isp.h b/include/uapi/linux/jh7110-isp.h index e20895bd881a..91254bb509a2 100644 --- a/include/uapi/linux/jh7110-isp.h +++ b/include/uapi/linux/jh7110-isp.h @@ -255,6 +255,17 @@ struct jh7110_isp_ycrv_setting { struct jh7110_isp_ycrv_curve curve; }; +struct jh7110_isp_sc_config { + __u16 h_start; + __u16 v_start; + __u8 sw_width; + __u8 sw_height; + __u8 hperiod; + __u8 hkeep; + __u8 vperiod; + __u8 vkeep; +}; + struct jh7110_isp_sc_af_config { __u8 es_hor_mode; __u8 es_sum_mode; @@ -264,6 +275,23 @@ struct jh7110_isp_sc_af_config { __u16 es_hor_thr; }; +struct jh7110_isp_sc_awb_ps { + __u8 awb_ps_rl; + __u8 awb_ps_ru; + __u8 awb_ps_gl; + __u8 awb_ps_gu; + __u8 awb_ps_bl; + __u8 awb_ps_bu; + __u8 awb_ps_yl; + __u8 awb_ps_yu; + __u16 awb_ps_grl; + __u16 awb_ps_gru; + __u16 awb_ps_gbl; + __u16 awb_ps_gbu; + __u16 awb_ps_grbl; + __u16 awb_ps_grbu; +}; + struct jh7110_isp_sc_awb_ws { __u8 awb_ws_rl; __u8 awb_ws_ru; @@ -275,12 +303,16 @@ struct jh7110_isp_sc_awb_ws { __u8 awb_ws_bu; }; + struct jh7110_isp_sc_awb_point { __u16 intensity; __u8 weight; }; struct jh7110_isp_sc_awb_config { + struct jh7110_isp_sc_awb_ps ws_ps_config; + __u8 awb_ps_grb_ba; + __u8 sel; struct jh7110_isp_sc_awb_ws ws_config; __u8 awb_cw[169]; struct jh7110_isp_sc_awb_point pts[17]; @@ -288,6 +320,7 @@ struct jh7110_isp_sc_awb_config { struct jh7110_isp_sc_setting { __u32 enabled; + struct jh7110_isp_sc_config crop_config; struct jh7110_isp_sc_af_config af_config; struct jh7110_isp_sc_awb_config awb_config; }; -- cgit v1.2.3 From d4ed3c99a15dda46483c4421d78ba212b1012262 Mon Sep 17 00:00:00 2001 From: "zejian.su" Date: Mon, 30 Oct 2023 16:09:58 +0800 Subject: Add ISP control for video2 and video3. Signed-off-by: zejian.su --- .../media/platform/starfive/v4l2_driver/stf_isp.c | 46 ++++++++++++++++++++++ include/uapi/linux/jh7110-isp.h | 23 +++++++++++ 2 files changed, 69 insertions(+) diff --git a/drivers/media/platform/starfive/v4l2_driver/stf_isp.c b/drivers/media/platform/starfive/v4l2_driver/stf_isp.c index c836ba709788..51e09f50628f 100644 --- a/drivers/media/platform/starfive/v4l2_driver/stf_isp.c +++ b/drivers/media/platform/starfive/v4l2_driver/stf_isp.c @@ -725,6 +725,24 @@ static int isp_set_ctrl_sc(struct stf_isp_dev *isp_dev, const void * value) return 0; } +static int isp_set_ctrl_outss(struct stf_isp_dev *isp_dev, const void * value) +{ + const struct jh7110_isp_outss_setting * setting = (const struct jh7110_isp_outss_setting *)value; + struct stf_vin_dev *vin = isp_dev->stfcamss->vin; + void __iomem *ispbase = vin->isp_base; + u32 reg_addr = !setting->which ? 0xa9c : 0xab4; + + if(!setting->stride) + return 0; + + // Output Image Stride Register, 8-byte(64bit) granularity. + reg_write(ispbase, reg_addr, setting->stride); + reg_write(ispbase, reg_addr + 4, ((setting->hsm << 16) | (setting->hsm & 0x3))); + reg_write(ispbase, reg_addr + 8, ((setting->vsm << 16) | (setting->vsm & 0x3))); + + return 0; +} + static int isp_s_ctrl(struct v4l2_ctrl *ctrl) { struct v4l2_subdev *sd = ctrl_to_sd(ctrl); @@ -822,6 +840,10 @@ static int isp_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_USER_JH7110_ISP_STAT_SETTING: ret = isp_set_ctrl_sc(isp_dev, ctrl->p_new.p_u8); break; + case V4L2_CID_USER_JH7110_ISP_OUTSS0_SETTING: + case V4L2_CID_USER_JH7110_ISP_OUTSS1_SETTING: + ret = isp_set_ctrl_outss(isp_dev, ctrl->p_new.p_u8); + break; default: ret = -EINVAL; break; @@ -1028,6 +1050,30 @@ struct v4l2_ctrl_config isp_ctrl[] = { .dims[0] = sizeof(struct jh7110_isp_sc_setting), .flags = 0, }, + [16] = { + .ops = &isp_ctrl_ops, + .type = V4L2_CTRL_TYPE_U8, + .def = 0, + .min = 0x00, + .max = 0xff, + .step = 1, + .name = "OUTSS Setting", + .id = V4L2_CID_USER_JH7110_ISP_OUTSS0_SETTING, + .dims[0] = sizeof(struct jh7110_isp_outss_setting), + .flags = 0, + }, + [17] = { + .ops = &isp_ctrl_ops, + .type = V4L2_CTRL_TYPE_U8, + .def = 0, + .min = 0x00, + .max = 0xff, + .step = 1, + .name = "OUTSS Setting", + .id = V4L2_CID_USER_JH7110_ISP_OUTSS1_SETTING, + .dims[0] = sizeof(struct jh7110_isp_outss_setting), + .flags = 0, + }, }; static int isp_init_controls(struct stf_isp_dev *isp_dev) diff --git a/include/uapi/linux/jh7110-isp.h b/include/uapi/linux/jh7110-isp.h index 91254bb509a2..33e0da35c291 100644 --- a/include/uapi/linux/jh7110-isp.h +++ b/include/uapi/linux/jh7110-isp.h @@ -49,6 +49,10 @@ (V4L2_CID_USER_JH7110_ISP_BASE + 0x000f) #define V4L2_CID_USER_JH7110_ISP_STAT_SETTING \ (V4L2_CID_USER_JH7110_ISP_BASE + 0x0010) +#define V4L2_CID_USER_JH7110_ISP_OUTSS0_SETTING \ + (V4L2_CID_USER_JH7110_ISP_BASE + 0x0011) +#define V4L2_CID_USER_JH7110_ISP_OUTSS1_SETTING \ + (V4L2_CID_USER_JH7110_ISP_BASE + 0x0012) struct jh7110_isp_wb_gain { __u16 gain_r; @@ -325,4 +329,23 @@ struct jh7110_isp_sc_setting { struct jh7110_isp_sc_awb_config awb_config; }; +struct jh7110_isp_outss_setting { + __u8 which; + __u16 stride; // Output Image Stride Register, 8-byte(64bit) granularity. + __u8 hsm; // horizontal scale mode + __u32 hsf; // horizontal scale factor (time 4096) + __u8 vsm; // vertical scale mode + __u32 vsf; // vertical scale factor (time 4096) +}; + +struct jh7110_isp_sc_buffer { + __u32 y_histogram[64]; + __u32 reserv0[33]; + __u32 bright_sc[4096]; + __u32 reserv1[96]; + __u32 ae_hist_y[128]; + __u32 reserv2[511]; + __u16 flag; +}; + #endif -- cgit v1.2.3